blob: a5574a173a92cba88254f9af9b390b12e5725f72 [file] [log] [blame]
Andrew Browna450fad2015-01-22 11:24:40 -08001/*
andrewsbrown4feb2da2015-03-03 16:05:29 -08002 * jndn-utils
3 * Copyright (c) 2015, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU Lesser General Public License,
7 * version 3, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT ANY
10 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
12 * more details.
Andrew Browna450fad2015-01-22 11:24:40 -080013 */
14package com.intel.jndn.utils;
15
Andrew Browndb457052015-02-21 15:41:58 -080016import com.intel.jndn.utils.event.NDNEvent;
17import com.intel.jndn.utils.event.NDNObservable;
18import com.intel.jndn.utils.event.NDNObserver;
Andrew Browna450fad2015-01-22 11:24:40 -080019import java.io.IOException;
andrewsbrown0cf35f92015-03-09 12:00:00 -070020import java.util.logging.Level;
Andrew Browna450fad2015-01-22 11:24:40 -080021import net.named_data.jndn.Data;
22import net.named_data.jndn.Face;
23import net.named_data.jndn.ForwardingFlags;
24import net.named_data.jndn.Interest;
25import net.named_data.jndn.Name;
26import net.named_data.jndn.OnInterest;
27import net.named_data.jndn.OnRegisterFailed;
28import net.named_data.jndn.encoding.EncodingException;
Andrew Browna88e6ef2015-01-22 11:43:44 -080029import net.named_data.jndn.security.KeyChain;
Andrew Browna450fad2015-01-22 11:24:40 -080030import net.named_data.jndn.transport.Transport;
Andrew Browndb457052015-02-21 15:41:58 -080031import java.util.logging.Logger;
Andrew Browna450fad2015-01-22 11:24:40 -080032
33/**
34 * Provide a server to simplify serving data over the NDN network. Exposes two
35 * main methods: put() for serving static, known data packets and on() for
36 * serving dynamically created packets on-demand.
37 *
38 * @author Andrew Brown <andrew.brown@intel.com>
39 */
40public class Server {
41
42 public static final long DEFAULT_SLEEP_TIME = 20;
43 public static final long DEFAULT_TIMEOUT = 2000;
Andrew Browndb457052015-02-21 15:41:58 -080044 private static final Logger logger = Logger.getLogger(Server.class.getName());
Andrew Browna450fad2015-01-22 11:24:40 -080045 private static Server defaultInstance;
Andrew Browna88e6ef2015-01-22 11:43:44 -080046 private KeyChain keyChain;
47 private Name certificateName;
Andrew Browna450fad2015-01-22 11:24:40 -080048
49 /**
50 * Singleton access for simpler server use
51 *
52 * @return
53 */
54 public static Server getDefault() {
55 if (defaultInstance == null) {
56 defaultInstance = new Server();
57 }
58 return defaultInstance;
59 }
60
61 /**
Andrew Browna88e6ef2015-01-22 11:43:44 -080062 * Constructor
63 */
64 public Server() {
65 // no signing
66 }
67
68 /**
69 * Constructor; enables signing
70 *
71 * @param keyChain
72 * @param certificateName
73 */
74 public Server(KeyChain keyChain, Name certificateName) {
75 this.keyChain = keyChain;
76 this.certificateName = certificateName;
77 }
78
79 /**
Andrew Browna450fad2015-01-22 11:24:40 -080080 * Synchronously serve a Data on the given face until one request accesses the
81 * data; will return incoming Interest request.
82 * <pre><code> Interest request = Client.putSync(face, data); </code></pre>
83 *
84 * @param face
85 * @param data
86 * @return
87 */
88 public Interest putSync(Face face, final Data data) {
89 // setup event
90 long startTime = System.currentTimeMillis();
91 final String dataName = data.getName().toUri();
92 final NDNEvent event = new NDNEvent();
93
94 // setup flags
95 ForwardingFlags flags = new ForwardingFlags();
96 flags.setCapture(true);
97
98 // register the data name on the face
99 try {
100 face.registerPrefix(data.getName(), new OnInterest() {
101 @Override
102 public void onInterest(Name prefix, Interest interest, Transport transport, long registeredPrefixId) {
Andrew Browna88e6ef2015-01-22 11:43:44 -0800103 // sign packet
104 if (keyChain != null) {
105 try {
106 keyChain.sign(data, certificateName != null ? certificateName : keyChain.getDefaultCertificateName());
107 } catch (net.named_data.jndn.security.SecurityException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800108 logger.severe("Failed to sign data for: " + dataName + e);
Andrew Browna88e6ef2015-01-22 11:43:44 -0800109 event.fromPacket(e);
110 }
111 }
112
113 // send packet
Andrew Browna450fad2015-01-22 11:24:40 -0800114 try {
115 transport.send(data.wireEncode().buf());
Andrew Browndb457052015-02-21 15:41:58 -0800116 logger.fine("Sent data: " + dataName);
Andrew Browna450fad2015-01-22 11:24:40 -0800117 event.fromPacket(interest);
118 } catch (IOException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800119 logger.severe("Failed to send data for: " + dataName);
Andrew Browna450fad2015-01-22 11:24:40 -0800120 event.fromPacket(e);
121 }
122 }
123 }, new OnRegisterFailed() {
124 @Override
125 public void onRegisterFailed(Name prefix) {
126 event.fromPacket(new Exception("Failed to register name: " + dataName));
127 }
128 }, flags);
129 logger.info("Registered data: " + dataName);
130 } catch (IOException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800131 logger.severe("Could not connect to face to register prefix: " + dataName + e);
Andrew Browna450fad2015-01-22 11:24:40 -0800132 event.fromPacket(e);
133 } catch (net.named_data.jndn.security.SecurityException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800134 logger.severe("Error registering prefix: " + dataName + e);
Andrew Browna450fad2015-01-22 11:24:40 -0800135 event.fromPacket(e);
136 }
137
138 // process eventCount until one response is sent or error
139 while (event.getPacket() == null) {
140 try {
141 synchronized (face) {
142 face.processEvents();
143 }
144 } catch (IOException | EncodingException e) {
andrewsbrown0cf35f92015-03-09 12:00:00 -0700145 logger.log(Level.WARNING, "Failed to process events.", e);
Andrew Browna450fad2015-01-22 11:24:40 -0800146 event.fromPacket(e);
147 }
148 sleep();
149 }
150
151 // return
Andrew Browndb457052015-02-21 15:41:58 -0800152 logger.fine("Request time (ms): " + (event.getTimestamp() - startTime));
Andrew Browna450fad2015-01-22 11:24:40 -0800153 return (event.isSuccess()) ? (Interest) event.getPacket() : null;
154 }
155
156 /**
157 * Asynchronously serve a Data on the given face until an observer stops it.
158 * E.g.: NDNObserver observer = Client.put(face, data); // when finished
Andrew Browna88e6ef2015-01-22 11:43:44 -0800159 * serving the data, stop the background thread observer.stop();
Andrew Browna450fad2015-01-22 11:24:40 -0800160 *
161 * @param face
162 * @param data
163 * @return
164 */
165 public NDNObserver put(final Face face, final Data data) {
166 // setup observer
167 final NDNObserver observer = new NDNObserver();
168 final NDNObservable eventHandler = new NDNObservable();
169 eventHandler.addObserver(observer);
170
Andrew Browna88e6ef2015-01-22 11:43:44 -0800171 // setup interest handler
Andrew Browna450fad2015-01-22 11:24:40 -0800172 final OnInterest interestHandler = new OnInterest() {
173 @Override
174 public void onInterest(Name prefix, Interest interest, Transport transport, long registeredPrefixId) {
Andrew Browna88e6ef2015-01-22 11:43:44 -0800175 // sign packet
176 if (keyChain != null) {
177 try {
178 keyChain.sign(data, certificateName != null ? certificateName : keyChain.getDefaultCertificateName());
179 } catch (net.named_data.jndn.security.SecurityException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800180 logger.severe("Failed to sign data for: " + data.getName().toUri() + e);
Andrew Browna88e6ef2015-01-22 11:43:44 -0800181 eventHandler.notify(e);
182 }
183 }
184
185 // send packet
Andrew Browna450fad2015-01-22 11:24:40 -0800186 try {
187 transport.send(data.wireEncode().buf());
188 } catch (IOException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800189 logger.severe("Failed to send data for: " + data.getName().toUri());
Andrew Browna450fad2015-01-22 11:24:40 -0800190 eventHandler.notify(e);
191 }
192 }
193 };
Andrew Browna88e6ef2015-01-22 11:43:44 -0800194
195 // setup failure handler
Andrew Browna450fad2015-01-22 11:24:40 -0800196 final OnRegisterFailed failureHandler = new OnRegisterFailed() {
197 @Override
198 public void onRegisterFailed(Name prefix) {
Andrew Browndb457052015-02-21 15:41:58 -0800199 logger.severe("Failed to register name to put: " + data.getName().toUri());
Andrew Browna450fad2015-01-22 11:24:40 -0800200 eventHandler.notify(new Exception("Failed to register name to put: " + data.getName().toUri()));
201 }
202 };
Andrew Browna88e6ef2015-01-22 11:43:44 -0800203
204 // setup forwarding flags
Andrew Browna450fad2015-01-22 11:24:40 -0800205 final ForwardingFlags flags = new ForwardingFlags();
206 flags.setCapture(true); // no shorter routes will answer for this prefix, see http://redmine.named-data.net/projects/nfd/wiki/RibMgmt#Route-inheritance
207 flags.setChildInherit(false); // the interest name must be exact, no child components after the prefix
208
Andrew Browna88e6ef2015-01-22 11:43:44 -0800209 // start background thread
Andrew Browna450fad2015-01-22 11:24:40 -0800210 Thread backgroundThread = new Thread(new Runnable() {
211 @Override
212 public void run() {
213 // register name on the face
214 try {
215 face.registerPrefix(data.getName(), interestHandler, failureHandler, flags);
216 logger.info("Registered data : " + data.getName().toUri());
217 } catch (IOException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800218 logger.severe("Could not connect to face to register prefix: " + data.getName().toUri() + e);
Andrew Browna450fad2015-01-22 11:24:40 -0800219 eventHandler.notify(e);
220 } catch (net.named_data.jndn.security.SecurityException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800221 logger.severe("Error registering prefix: " + data.getName().toUri() + e);
Andrew Browna450fad2015-01-22 11:24:40 -0800222 eventHandler.notify(e);
223 }
224
225 // process eventCount until a request is received
226 while (observer.interestCount() == 0 && observer.errorCount() == 0 && !observer.mustStop()) {
227 try {
228 synchronized (face) {
229 face.processEvents();
230 }
231 } catch (IOException | EncodingException e) {
andrewsbrown0cf35f92015-03-09 12:00:00 -0700232 logger.log(Level.WARNING, "Failed to process events.", e);
Andrew Browna450fad2015-01-22 11:24:40 -0800233 eventHandler.notify(e);
234 }
235 sleep();
236 }
237 }
238 });
239 backgroundThread.setName(String.format("Server.put(%s)", data.getName().toUri()));
240 backgroundThread.setDaemon(true);
241 backgroundThread.start();
242
243 return observer;
244 }
245
246 /**
247 * Register a prefix on the face to serve Data packets for incoming Interests.
Andrew Browna88e6ef2015-01-22 11:43:44 -0800248 * This method will create a background thread to process events until the
249 * user calls stop() on the returned observer
250 *
Andrew Browna450fad2015-01-22 11:24:40 -0800251 * @param face
252 * @param prefix
253 * @param handler
Andrew Browna88e6ef2015-01-22 11:43:44 -0800254 * @return
Andrew Browna450fad2015-01-22 11:24:40 -0800255 */
256 public NDNObserver on(final Face face, final Name prefix, final OnServeInterest handler) {
257 // setup observer
258 final NDNObserver observer = new NDNObserver();
259 final NDNObservable eventHandler = new NDNObservable();
260 eventHandler.addObserver(observer);
261
Andrew Browna88e6ef2015-01-22 11:43:44 -0800262 // setup interest handler
Andrew Browna450fad2015-01-22 11:24:40 -0800263 final OnInterest interestHandler = new OnInterest() {
264 @Override
265 public void onInterest(Name prefix, Interest interest, Transport transport, long registeredPrefixId) {
Andrew Browna88e6ef2015-01-22 11:43:44 -0800266 // notify observers of interest received
Andrew Browna450fad2015-01-22 11:24:40 -0800267 eventHandler.notify(interest);
Andrew Browna88e6ef2015-01-22 11:43:44 -0800268
269 // grab data from OnServeInterest handler
270 Data data = handler.onInterest(prefix, interest);
271
272 // sign packet
273 if (keyChain != null) {
274 try {
275 keyChain.sign(data, certificateName != null ? certificateName : keyChain.getDefaultCertificateName());
276 } catch (net.named_data.jndn.security.SecurityException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800277 logger.severe("Failed to sign data for: " + interest.getName().toUri() + e);
Andrew Browna88e6ef2015-01-22 11:43:44 -0800278 eventHandler.notify(e);
279 }
280 }
281
282 // send packet
Andrew Browna450fad2015-01-22 11:24:40 -0800283 try {
Andrew Browna450fad2015-01-22 11:24:40 -0800284 transport.send(data.wireEncode().buf());
Andrew Browna88e6ef2015-01-22 11:43:44 -0800285 eventHandler.notify(data); // notify observers of data sent
Andrew Browna450fad2015-01-22 11:24:40 -0800286 } catch (IOException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800287 logger.severe("Failed to send data for: " + interest.getName().toUri());
Andrew Browna450fad2015-01-22 11:24:40 -0800288 eventHandler.notify(e);
289 }
290 }
291 };
Andrew Browna88e6ef2015-01-22 11:43:44 -0800292
293 // setup failure handler
Andrew Browna450fad2015-01-22 11:24:40 -0800294 final OnRegisterFailed failureHandler = new OnRegisterFailed() {
295 @Override
296 public void onRegisterFailed(Name prefix) {
Andrew Browndb457052015-02-21 15:41:58 -0800297 logger.severe("Failed to register name to put: " + prefix.toUri());
Andrew Browna450fad2015-01-22 11:24:40 -0800298 eventHandler.notify(new Exception("Failed to register name to put: " + prefix.toUri()));
299 }
300 };
Andrew Browna88e6ef2015-01-22 11:43:44 -0800301
302 // setup forwarding flags
Andrew Browna450fad2015-01-22 11:24:40 -0800303 final ForwardingFlags flags = new ForwardingFlags();
304 flags.setCapture(true); // no shorter routes will answer for this prefix, see http://redmine.named-data.net/projects/nfd/wiki/RibMgmt#Route-inheritance
305 flags.setChildInherit(true); // the interest name may have child components after the prefix
306
Andrew Browna88e6ef2015-01-22 11:43:44 -0800307 // start background thread
Andrew Browna450fad2015-01-22 11:24:40 -0800308 Thread backgroundThread = new Thread(new Runnable() {
309 @Override
310 public void run() {
311 // register name on the face
312 try {
313 face.registerPrefix(prefix, interestHandler, failureHandler, flags);
314 logger.info("Registered data : " + prefix.toUri());
315 } catch (IOException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800316 logger.severe("Could not connect to face to register prefix: " + prefix.toUri() + e);
Andrew Browna450fad2015-01-22 11:24:40 -0800317 eventHandler.notify(e);
318 } catch (net.named_data.jndn.security.SecurityException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800319 logger.severe("Error registering prefix: " + prefix.toUri() + e);
Andrew Browna450fad2015-01-22 11:24:40 -0800320 eventHandler.notify(e);
321 }
322
323 // process events until told to stop or error bubbles up
324 while (observer.errorCount() == 0 && !observer.mustStop()) {
325 try {
326 synchronized (face) {
327 face.processEvents();
328 }
329 } catch (IOException | EncodingException e) {
andrewsbrown0cf35f92015-03-09 12:00:00 -0700330 logger.log(Level.WARNING, "Failed to process events.", e);
Andrew Browna450fad2015-01-22 11:24:40 -0800331 eventHandler.notify(e);
332 }
333 sleep();
334 }
335 }
336 });
Andrew Brown665c0c12015-01-22 15:57:53 -0800337 backgroundThread.setName(String.format("Server.on(%s)", prefix.toUri()));
Andrew Browna450fad2015-01-22 11:24:40 -0800338 backgroundThread.setDaemon(true);
339 backgroundThread.start();
340
341 return observer;
342 }
343
344 /**
345 * Put the current thread to sleep to allow time for IO
346 */
347 protected void sleep() {
348 try {
349 Thread.currentThread().sleep(DEFAULT_SLEEP_TIME);
350 } catch (InterruptedException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800351 logger.severe("Event loop interrupted." + e);
Andrew Browna450fad2015-01-22 11:24:40 -0800352 }
353 }
354
355}