blob: decd07a315af821eb4e6ffce60fc73d6960f5c85 [file] [log] [blame]
Andrew Browna450fad2015-01-22 11:24:40 -08001/*
2 * File name: Server.java
3 *
4 * Purpose: Provide a server to simplify serving data over the NDN
5 * network.
6 *
7 * © Copyright Intel Corporation. All rights reserved.
8 * Intel Corporation, 2200 Mission College Boulevard,
9 * Santa Clara, CA 95052-8119, USA
10 */
11package com.intel.jndn.utils;
12
Andrew Browndb457052015-02-21 15:41:58 -080013import com.intel.jndn.utils.event.NDNEvent;
14import com.intel.jndn.utils.event.NDNObservable;
15import com.intel.jndn.utils.event.NDNObserver;
Andrew Browna450fad2015-01-22 11:24:40 -080016import java.io.IOException;
17import net.named_data.jndn.Data;
18import net.named_data.jndn.Face;
19import net.named_data.jndn.ForwardingFlags;
20import net.named_data.jndn.Interest;
21import net.named_data.jndn.Name;
22import net.named_data.jndn.OnInterest;
23import net.named_data.jndn.OnRegisterFailed;
24import net.named_data.jndn.encoding.EncodingException;
Andrew Browna88e6ef2015-01-22 11:43:44 -080025import net.named_data.jndn.security.KeyChain;
Andrew Browna450fad2015-01-22 11:24:40 -080026import net.named_data.jndn.transport.Transport;
Andrew Browndb457052015-02-21 15:41:58 -080027import java.util.logging.Logger;
Andrew Browna450fad2015-01-22 11:24:40 -080028
29/**
30 * Provide a server to simplify serving data over the NDN network. Exposes two
31 * main methods: put() for serving static, known data packets and on() for
32 * serving dynamically created packets on-demand.
33 *
34 * @author Andrew Brown <andrew.brown@intel.com>
35 */
36public class Server {
37
38 public static final long DEFAULT_SLEEP_TIME = 20;
39 public static final long DEFAULT_TIMEOUT = 2000;
Andrew Browndb457052015-02-21 15:41:58 -080040 private static final Logger logger = Logger.getLogger(Server.class.getName());
Andrew Browna450fad2015-01-22 11:24:40 -080041 private static Server defaultInstance;
Andrew Browna88e6ef2015-01-22 11:43:44 -080042 private KeyChain keyChain;
43 private Name certificateName;
Andrew Browna450fad2015-01-22 11:24:40 -080044
45 /**
46 * Singleton access for simpler server use
47 *
48 * @return
49 */
50 public static Server getDefault() {
51 if (defaultInstance == null) {
52 defaultInstance = new Server();
53 }
54 return defaultInstance;
55 }
56
57 /**
Andrew Browna88e6ef2015-01-22 11:43:44 -080058 * Constructor
59 */
60 public Server() {
61 // no signing
62 }
63
64 /**
65 * Constructor; enables signing
66 *
67 * @param keyChain
68 * @param certificateName
69 */
70 public Server(KeyChain keyChain, Name certificateName) {
71 this.keyChain = keyChain;
72 this.certificateName = certificateName;
73 }
74
75 /**
Andrew Browna450fad2015-01-22 11:24:40 -080076 * Synchronously serve a Data on the given face until one request accesses the
77 * data; will return incoming Interest request.
78 * <pre><code> Interest request = Client.putSync(face, data); </code></pre>
79 *
80 * @param face
81 * @param data
82 * @return
83 */
84 public Interest putSync(Face face, final Data data) {
85 // setup event
86 long startTime = System.currentTimeMillis();
87 final String dataName = data.getName().toUri();
88 final NDNEvent event = new NDNEvent();
89
90 // setup flags
91 ForwardingFlags flags = new ForwardingFlags();
92 flags.setCapture(true);
93
94 // register the data name on the face
95 try {
96 face.registerPrefix(data.getName(), new OnInterest() {
97 @Override
98 public void onInterest(Name prefix, Interest interest, Transport transport, long registeredPrefixId) {
Andrew Browna88e6ef2015-01-22 11:43:44 -080099 // sign packet
100 if (keyChain != null) {
101 try {
102 keyChain.sign(data, certificateName != null ? certificateName : keyChain.getDefaultCertificateName());
103 } catch (net.named_data.jndn.security.SecurityException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800104 logger.severe("Failed to sign data for: " + dataName + e);
Andrew Browna88e6ef2015-01-22 11:43:44 -0800105 event.fromPacket(e);
106 }
107 }
108
109 // send packet
Andrew Browna450fad2015-01-22 11:24:40 -0800110 try {
111 transport.send(data.wireEncode().buf());
Andrew Browndb457052015-02-21 15:41:58 -0800112 logger.fine("Sent data: " + dataName);
Andrew Browna450fad2015-01-22 11:24:40 -0800113 event.fromPacket(interest);
114 } catch (IOException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800115 logger.severe("Failed to send data for: " + dataName);
Andrew Browna450fad2015-01-22 11:24:40 -0800116 event.fromPacket(e);
117 }
118 }
119 }, new OnRegisterFailed() {
120 @Override
121 public void onRegisterFailed(Name prefix) {
122 event.fromPacket(new Exception("Failed to register name: " + dataName));
123 }
124 }, flags);
125 logger.info("Registered data: " + dataName);
126 } catch (IOException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800127 logger.severe("Could not connect to face to register prefix: " + dataName + e);
Andrew Browna450fad2015-01-22 11:24:40 -0800128 event.fromPacket(e);
129 } catch (net.named_data.jndn.security.SecurityException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800130 logger.severe("Error registering prefix: " + dataName + e);
Andrew Browna450fad2015-01-22 11:24:40 -0800131 event.fromPacket(e);
132 }
133
134 // process eventCount until one response is sent or error
135 while (event.getPacket() == null) {
136 try {
137 synchronized (face) {
138 face.processEvents();
139 }
140 } catch (IOException | EncodingException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800141 logger.warning("Failed to process events." + e);
Andrew Browna450fad2015-01-22 11:24:40 -0800142 event.fromPacket(e);
143 }
144 sleep();
145 }
146
147 // return
Andrew Browndb457052015-02-21 15:41:58 -0800148 logger.fine("Request time (ms): " + (event.getTimestamp() - startTime));
Andrew Browna450fad2015-01-22 11:24:40 -0800149 return (event.isSuccess()) ? (Interest) event.getPacket() : null;
150 }
151
152 /**
153 * Asynchronously serve a Data on the given face until an observer stops it.
154 * E.g.: NDNObserver observer = Client.put(face, data); // when finished
Andrew Browna88e6ef2015-01-22 11:43:44 -0800155 * serving the data, stop the background thread observer.stop();
Andrew Browna450fad2015-01-22 11:24:40 -0800156 *
157 * @param face
158 * @param data
159 * @return
160 */
161 public NDNObserver put(final Face face, final Data data) {
162 // setup observer
163 final NDNObserver observer = new NDNObserver();
164 final NDNObservable eventHandler = new NDNObservable();
165 eventHandler.addObserver(observer);
166
Andrew Browna88e6ef2015-01-22 11:43:44 -0800167 // setup interest handler
Andrew Browna450fad2015-01-22 11:24:40 -0800168 final OnInterest interestHandler = new OnInterest() {
169 @Override
170 public void onInterest(Name prefix, Interest interest, Transport transport, long registeredPrefixId) {
Andrew Browna88e6ef2015-01-22 11:43:44 -0800171 // sign packet
172 if (keyChain != null) {
173 try {
174 keyChain.sign(data, certificateName != null ? certificateName : keyChain.getDefaultCertificateName());
175 } catch (net.named_data.jndn.security.SecurityException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800176 logger.severe("Failed to sign data for: " + data.getName().toUri() + e);
Andrew Browna88e6ef2015-01-22 11:43:44 -0800177 eventHandler.notify(e);
178 }
179 }
180
181 // send packet
Andrew Browna450fad2015-01-22 11:24:40 -0800182 try {
183 transport.send(data.wireEncode().buf());
184 } catch (IOException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800185 logger.severe("Failed to send data for: " + data.getName().toUri());
Andrew Browna450fad2015-01-22 11:24:40 -0800186 eventHandler.notify(e);
187 }
188 }
189 };
Andrew Browna88e6ef2015-01-22 11:43:44 -0800190
191 // setup failure handler
Andrew Browna450fad2015-01-22 11:24:40 -0800192 final OnRegisterFailed failureHandler = new OnRegisterFailed() {
193 @Override
194 public void onRegisterFailed(Name prefix) {
Andrew Browndb457052015-02-21 15:41:58 -0800195 logger.severe("Failed to register name to put: " + data.getName().toUri());
Andrew Browna450fad2015-01-22 11:24:40 -0800196 eventHandler.notify(new Exception("Failed to register name to put: " + data.getName().toUri()));
197 }
198 };
Andrew Browna88e6ef2015-01-22 11:43:44 -0800199
200 // setup forwarding flags
Andrew Browna450fad2015-01-22 11:24:40 -0800201 final ForwardingFlags flags = new ForwardingFlags();
202 flags.setCapture(true); // no shorter routes will answer for this prefix, see http://redmine.named-data.net/projects/nfd/wiki/RibMgmt#Route-inheritance
203 flags.setChildInherit(false); // the interest name must be exact, no child components after the prefix
204
Andrew Browna88e6ef2015-01-22 11:43:44 -0800205 // start background thread
Andrew Browna450fad2015-01-22 11:24:40 -0800206 Thread backgroundThread = new Thread(new Runnable() {
207 @Override
208 public void run() {
209 // register name on the face
210 try {
211 face.registerPrefix(data.getName(), interestHandler, failureHandler, flags);
212 logger.info("Registered data : " + data.getName().toUri());
213 } catch (IOException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800214 logger.severe("Could not connect to face to register prefix: " + data.getName().toUri() + e);
Andrew Browna450fad2015-01-22 11:24:40 -0800215 eventHandler.notify(e);
216 } catch (net.named_data.jndn.security.SecurityException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800217 logger.severe("Error registering prefix: " + data.getName().toUri() + e);
Andrew Browna450fad2015-01-22 11:24:40 -0800218 eventHandler.notify(e);
219 }
220
221 // process eventCount until a request is received
222 while (observer.interestCount() == 0 && observer.errorCount() == 0 && !observer.mustStop()) {
223 try {
224 synchronized (face) {
225 face.processEvents();
226 }
227 } catch (IOException | EncodingException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800228 logger.warning("Failed to process events." + e);
Andrew Browna450fad2015-01-22 11:24:40 -0800229 eventHandler.notify(e);
230 }
231 sleep();
232 }
233 }
234 });
235 backgroundThread.setName(String.format("Server.put(%s)", data.getName().toUri()));
236 backgroundThread.setDaemon(true);
237 backgroundThread.start();
238
239 return observer;
240 }
241
242 /**
243 * Register a prefix on the face to serve Data packets for incoming Interests.
Andrew Browna88e6ef2015-01-22 11:43:44 -0800244 * This method will create a background thread to process events until the
245 * user calls stop() on the returned observer
246 *
Andrew Browna450fad2015-01-22 11:24:40 -0800247 * @param face
248 * @param prefix
249 * @param handler
Andrew Browna88e6ef2015-01-22 11:43:44 -0800250 * @return
Andrew Browna450fad2015-01-22 11:24:40 -0800251 */
252 public NDNObserver on(final Face face, final Name prefix, final OnServeInterest handler) {
253 // setup observer
254 final NDNObserver observer = new NDNObserver();
255 final NDNObservable eventHandler = new NDNObservable();
256 eventHandler.addObserver(observer);
257
Andrew Browna88e6ef2015-01-22 11:43:44 -0800258 // setup interest handler
Andrew Browna450fad2015-01-22 11:24:40 -0800259 final OnInterest interestHandler = new OnInterest() {
260 @Override
261 public void onInterest(Name prefix, Interest interest, Transport transport, long registeredPrefixId) {
Andrew Browna88e6ef2015-01-22 11:43:44 -0800262 // notify observers of interest received
Andrew Browna450fad2015-01-22 11:24:40 -0800263 eventHandler.notify(interest);
Andrew Browna88e6ef2015-01-22 11:43:44 -0800264
265 // grab data from OnServeInterest handler
266 Data data = handler.onInterest(prefix, interest);
267
268 // sign packet
269 if (keyChain != null) {
270 try {
271 keyChain.sign(data, certificateName != null ? certificateName : keyChain.getDefaultCertificateName());
272 } catch (net.named_data.jndn.security.SecurityException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800273 logger.severe("Failed to sign data for: " + interest.getName().toUri() + e);
Andrew Browna88e6ef2015-01-22 11:43:44 -0800274 eventHandler.notify(e);
275 }
276 }
277
278 // send packet
Andrew Browna450fad2015-01-22 11:24:40 -0800279 try {
Andrew Browna450fad2015-01-22 11:24:40 -0800280 transport.send(data.wireEncode().buf());
Andrew Browna88e6ef2015-01-22 11:43:44 -0800281 eventHandler.notify(data); // notify observers of data sent
Andrew Browna450fad2015-01-22 11:24:40 -0800282 } catch (IOException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800283 logger.severe("Failed to send data for: " + interest.getName().toUri());
Andrew Browna450fad2015-01-22 11:24:40 -0800284 eventHandler.notify(e);
285 }
286 }
287 };
Andrew Browna88e6ef2015-01-22 11:43:44 -0800288
289 // setup failure handler
Andrew Browna450fad2015-01-22 11:24:40 -0800290 final OnRegisterFailed failureHandler = new OnRegisterFailed() {
291 @Override
292 public void onRegisterFailed(Name prefix) {
Andrew Browndb457052015-02-21 15:41:58 -0800293 logger.severe("Failed to register name to put: " + prefix.toUri());
Andrew Browna450fad2015-01-22 11:24:40 -0800294 eventHandler.notify(new Exception("Failed to register name to put: " + prefix.toUri()));
295 }
296 };
Andrew Browna88e6ef2015-01-22 11:43:44 -0800297
298 // setup forwarding flags
Andrew Browna450fad2015-01-22 11:24:40 -0800299 final ForwardingFlags flags = new ForwardingFlags();
300 flags.setCapture(true); // no shorter routes will answer for this prefix, see http://redmine.named-data.net/projects/nfd/wiki/RibMgmt#Route-inheritance
301 flags.setChildInherit(true); // the interest name may have child components after the prefix
302
Andrew Browna88e6ef2015-01-22 11:43:44 -0800303 // start background thread
Andrew Browna450fad2015-01-22 11:24:40 -0800304 Thread backgroundThread = new Thread(new Runnable() {
305 @Override
306 public void run() {
307 // register name on the face
308 try {
309 face.registerPrefix(prefix, interestHandler, failureHandler, flags);
310 logger.info("Registered data : " + prefix.toUri());
311 } catch (IOException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800312 logger.severe("Could not connect to face to register prefix: " + prefix.toUri() + e);
Andrew Browna450fad2015-01-22 11:24:40 -0800313 eventHandler.notify(e);
314 } catch (net.named_data.jndn.security.SecurityException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800315 logger.severe("Error registering prefix: " + prefix.toUri() + e);
Andrew Browna450fad2015-01-22 11:24:40 -0800316 eventHandler.notify(e);
317 }
318
319 // process events until told to stop or error bubbles up
320 while (observer.errorCount() == 0 && !observer.mustStop()) {
321 try {
322 synchronized (face) {
323 face.processEvents();
324 }
325 } catch (IOException | EncodingException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800326 logger.warning("Failed to process events." + e);
Andrew Browna450fad2015-01-22 11:24:40 -0800327 eventHandler.notify(e);
328 }
329 sleep();
330 }
331 }
332 });
Andrew Brown665c0c12015-01-22 15:57:53 -0800333 backgroundThread.setName(String.format("Server.on(%s)", prefix.toUri()));
Andrew Browna450fad2015-01-22 11:24:40 -0800334 backgroundThread.setDaemon(true);
335 backgroundThread.start();
336
337 return observer;
338 }
339
340 /**
341 * Put the current thread to sleep to allow time for IO
342 */
343 protected void sleep() {
344 try {
345 Thread.currentThread().sleep(DEFAULT_SLEEP_TIME);
346 } catch (InterruptedException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800347 logger.severe("Event loop interrupted." + e);
Andrew Browna450fad2015-01-22 11:24:40 -0800348 }
349 }
350
351}