blob: 437d4804334a4584952b6b5b5a66c7582b32330a [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;
20import net.named_data.jndn.Data;
21import net.named_data.jndn.Face;
22import net.named_data.jndn.ForwardingFlags;
23import net.named_data.jndn.Interest;
24import net.named_data.jndn.Name;
25import net.named_data.jndn.OnInterest;
26import net.named_data.jndn.OnRegisterFailed;
27import net.named_data.jndn.encoding.EncodingException;
Andrew Browna88e6ef2015-01-22 11:43:44 -080028import net.named_data.jndn.security.KeyChain;
Andrew Browna450fad2015-01-22 11:24:40 -080029import net.named_data.jndn.transport.Transport;
Andrew Browndb457052015-02-21 15:41:58 -080030import java.util.logging.Logger;
Andrew Browna450fad2015-01-22 11:24:40 -080031
32/**
33 * Provide a server to simplify serving data over the NDN network. Exposes two
34 * main methods: put() for serving static, known data packets and on() for
35 * serving dynamically created packets on-demand.
36 *
37 * @author Andrew Brown <andrew.brown@intel.com>
38 */
39public class Server {
40
41 public static final long DEFAULT_SLEEP_TIME = 20;
42 public static final long DEFAULT_TIMEOUT = 2000;
Andrew Browndb457052015-02-21 15:41:58 -080043 private static final Logger logger = Logger.getLogger(Server.class.getName());
Andrew Browna450fad2015-01-22 11:24:40 -080044 private static Server defaultInstance;
Andrew Browna88e6ef2015-01-22 11:43:44 -080045 private KeyChain keyChain;
46 private Name certificateName;
Andrew Browna450fad2015-01-22 11:24:40 -080047
48 /**
49 * Singleton access for simpler server use
50 *
51 * @return
52 */
53 public static Server getDefault() {
54 if (defaultInstance == null) {
55 defaultInstance = new Server();
56 }
57 return defaultInstance;
58 }
59
60 /**
Andrew Browna88e6ef2015-01-22 11:43:44 -080061 * Constructor
62 */
63 public Server() {
64 // no signing
65 }
66
67 /**
68 * Constructor; enables signing
69 *
70 * @param keyChain
71 * @param certificateName
72 */
73 public Server(KeyChain keyChain, Name certificateName) {
74 this.keyChain = keyChain;
75 this.certificateName = certificateName;
76 }
77
78 /**
Andrew Browna450fad2015-01-22 11:24:40 -080079 * Synchronously serve a Data on the given face until one request accesses the
80 * data; will return incoming Interest request.
81 * <pre><code> Interest request = Client.putSync(face, data); </code></pre>
82 *
83 * @param face
84 * @param data
85 * @return
86 */
87 public Interest putSync(Face face, final Data data) {
88 // setup event
89 long startTime = System.currentTimeMillis();
90 final String dataName = data.getName().toUri();
91 final NDNEvent event = new NDNEvent();
92
93 // setup flags
94 ForwardingFlags flags = new ForwardingFlags();
95 flags.setCapture(true);
96
97 // register the data name on the face
98 try {
99 face.registerPrefix(data.getName(), new OnInterest() {
100 @Override
101 public void onInterest(Name prefix, Interest interest, Transport transport, long registeredPrefixId) {
Andrew Browna88e6ef2015-01-22 11:43:44 -0800102 // sign packet
103 if (keyChain != null) {
104 try {
105 keyChain.sign(data, certificateName != null ? certificateName : keyChain.getDefaultCertificateName());
106 } catch (net.named_data.jndn.security.SecurityException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800107 logger.severe("Failed to sign data for: " + dataName + e);
Andrew Browna88e6ef2015-01-22 11:43:44 -0800108 event.fromPacket(e);
109 }
110 }
111
112 // send packet
Andrew Browna450fad2015-01-22 11:24:40 -0800113 try {
114 transport.send(data.wireEncode().buf());
Andrew Browndb457052015-02-21 15:41:58 -0800115 logger.fine("Sent data: " + dataName);
Andrew Browna450fad2015-01-22 11:24:40 -0800116 event.fromPacket(interest);
117 } catch (IOException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800118 logger.severe("Failed to send data for: " + dataName);
Andrew Browna450fad2015-01-22 11:24:40 -0800119 event.fromPacket(e);
120 }
121 }
122 }, new OnRegisterFailed() {
123 @Override
124 public void onRegisterFailed(Name prefix) {
125 event.fromPacket(new Exception("Failed to register name: " + dataName));
126 }
127 }, flags);
128 logger.info("Registered data: " + dataName);
129 } catch (IOException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800130 logger.severe("Could not connect to face to register prefix: " + dataName + e);
Andrew Browna450fad2015-01-22 11:24:40 -0800131 event.fromPacket(e);
132 } catch (net.named_data.jndn.security.SecurityException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800133 logger.severe("Error registering prefix: " + dataName + e);
Andrew Browna450fad2015-01-22 11:24:40 -0800134 event.fromPacket(e);
135 }
136
137 // process eventCount until one response is sent or error
138 while (event.getPacket() == null) {
139 try {
140 synchronized (face) {
141 face.processEvents();
142 }
143 } catch (IOException | EncodingException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800144 logger.warning("Failed to process events." + e);
Andrew Browna450fad2015-01-22 11:24:40 -0800145 event.fromPacket(e);
146 }
147 sleep();
148 }
149
150 // return
Andrew Browndb457052015-02-21 15:41:58 -0800151 logger.fine("Request time (ms): " + (event.getTimestamp() - startTime));
Andrew Browna450fad2015-01-22 11:24:40 -0800152 return (event.isSuccess()) ? (Interest) event.getPacket() : null;
153 }
154
155 /**
156 * Asynchronously serve a Data on the given face until an observer stops it.
157 * E.g.: NDNObserver observer = Client.put(face, data); // when finished
Andrew Browna88e6ef2015-01-22 11:43:44 -0800158 * serving the data, stop the background thread observer.stop();
Andrew Browna450fad2015-01-22 11:24:40 -0800159 *
160 * @param face
161 * @param data
162 * @return
163 */
164 public NDNObserver put(final Face face, final Data data) {
165 // setup observer
166 final NDNObserver observer = new NDNObserver();
167 final NDNObservable eventHandler = new NDNObservable();
168 eventHandler.addObserver(observer);
169
Andrew Browna88e6ef2015-01-22 11:43:44 -0800170 // setup interest handler
Andrew Browna450fad2015-01-22 11:24:40 -0800171 final OnInterest interestHandler = new OnInterest() {
172 @Override
173 public void onInterest(Name prefix, Interest interest, Transport transport, long registeredPrefixId) {
Andrew Browna88e6ef2015-01-22 11:43:44 -0800174 // sign packet
175 if (keyChain != null) {
176 try {
177 keyChain.sign(data, certificateName != null ? certificateName : keyChain.getDefaultCertificateName());
178 } catch (net.named_data.jndn.security.SecurityException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800179 logger.severe("Failed to sign data for: " + data.getName().toUri() + e);
Andrew Browna88e6ef2015-01-22 11:43:44 -0800180 eventHandler.notify(e);
181 }
182 }
183
184 // send packet
Andrew Browna450fad2015-01-22 11:24:40 -0800185 try {
186 transport.send(data.wireEncode().buf());
187 } catch (IOException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800188 logger.severe("Failed to send data for: " + data.getName().toUri());
Andrew Browna450fad2015-01-22 11:24:40 -0800189 eventHandler.notify(e);
190 }
191 }
192 };
Andrew Browna88e6ef2015-01-22 11:43:44 -0800193
194 // setup failure handler
Andrew Browna450fad2015-01-22 11:24:40 -0800195 final OnRegisterFailed failureHandler = new OnRegisterFailed() {
196 @Override
197 public void onRegisterFailed(Name prefix) {
Andrew Browndb457052015-02-21 15:41:58 -0800198 logger.severe("Failed to register name to put: " + data.getName().toUri());
Andrew Browna450fad2015-01-22 11:24:40 -0800199 eventHandler.notify(new Exception("Failed to register name to put: " + data.getName().toUri()));
200 }
201 };
Andrew Browna88e6ef2015-01-22 11:43:44 -0800202
203 // setup forwarding flags
Andrew Browna450fad2015-01-22 11:24:40 -0800204 final ForwardingFlags flags = new ForwardingFlags();
205 flags.setCapture(true); // no shorter routes will answer for this prefix, see http://redmine.named-data.net/projects/nfd/wiki/RibMgmt#Route-inheritance
206 flags.setChildInherit(false); // the interest name must be exact, no child components after the prefix
207
Andrew Browna88e6ef2015-01-22 11:43:44 -0800208 // start background thread
Andrew Browna450fad2015-01-22 11:24:40 -0800209 Thread backgroundThread = new Thread(new Runnable() {
210 @Override
211 public void run() {
212 // register name on the face
213 try {
214 face.registerPrefix(data.getName(), interestHandler, failureHandler, flags);
215 logger.info("Registered data : " + data.getName().toUri());
216 } catch (IOException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800217 logger.severe("Could not connect to face to register prefix: " + data.getName().toUri() + e);
Andrew Browna450fad2015-01-22 11:24:40 -0800218 eventHandler.notify(e);
219 } catch (net.named_data.jndn.security.SecurityException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800220 logger.severe("Error registering prefix: " + data.getName().toUri() + e);
Andrew Browna450fad2015-01-22 11:24:40 -0800221 eventHandler.notify(e);
222 }
223
224 // process eventCount until a request is received
225 while (observer.interestCount() == 0 && observer.errorCount() == 0 && !observer.mustStop()) {
226 try {
227 synchronized (face) {
228 face.processEvents();
229 }
230 } catch (IOException | EncodingException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800231 logger.warning("Failed to process events." + e);
Andrew Browna450fad2015-01-22 11:24:40 -0800232 eventHandler.notify(e);
233 }
234 sleep();
235 }
236 }
237 });
238 backgroundThread.setName(String.format("Server.put(%s)", data.getName().toUri()));
239 backgroundThread.setDaemon(true);
240 backgroundThread.start();
241
242 return observer;
243 }
244
245 /**
246 * Register a prefix on the face to serve Data packets for incoming Interests.
Andrew Browna88e6ef2015-01-22 11:43:44 -0800247 * This method will create a background thread to process events until the
248 * user calls stop() on the returned observer
249 *
Andrew Browna450fad2015-01-22 11:24:40 -0800250 * @param face
251 * @param prefix
252 * @param handler
Andrew Browna88e6ef2015-01-22 11:43:44 -0800253 * @return
Andrew Browna450fad2015-01-22 11:24:40 -0800254 */
255 public NDNObserver on(final Face face, final Name prefix, final OnServeInterest handler) {
256 // setup observer
257 final NDNObserver observer = new NDNObserver();
258 final NDNObservable eventHandler = new NDNObservable();
259 eventHandler.addObserver(observer);
260
Andrew Browna88e6ef2015-01-22 11:43:44 -0800261 // setup interest handler
Andrew Browna450fad2015-01-22 11:24:40 -0800262 final OnInterest interestHandler = new OnInterest() {
263 @Override
264 public void onInterest(Name prefix, Interest interest, Transport transport, long registeredPrefixId) {
Andrew Browna88e6ef2015-01-22 11:43:44 -0800265 // notify observers of interest received
Andrew Browna450fad2015-01-22 11:24:40 -0800266 eventHandler.notify(interest);
Andrew Browna88e6ef2015-01-22 11:43:44 -0800267
268 // grab data from OnServeInterest handler
269 Data data = handler.onInterest(prefix, interest);
270
271 // sign packet
272 if (keyChain != null) {
273 try {
274 keyChain.sign(data, certificateName != null ? certificateName : keyChain.getDefaultCertificateName());
275 } catch (net.named_data.jndn.security.SecurityException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800276 logger.severe("Failed to sign data for: " + interest.getName().toUri() + e);
Andrew Browna88e6ef2015-01-22 11:43:44 -0800277 eventHandler.notify(e);
278 }
279 }
280
281 // send packet
Andrew Browna450fad2015-01-22 11:24:40 -0800282 try {
Andrew Browna450fad2015-01-22 11:24:40 -0800283 transport.send(data.wireEncode().buf());
Andrew Browna88e6ef2015-01-22 11:43:44 -0800284 eventHandler.notify(data); // notify observers of data sent
Andrew Browna450fad2015-01-22 11:24:40 -0800285 } catch (IOException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800286 logger.severe("Failed to send data for: " + interest.getName().toUri());
Andrew Browna450fad2015-01-22 11:24:40 -0800287 eventHandler.notify(e);
288 }
289 }
290 };
Andrew Browna88e6ef2015-01-22 11:43:44 -0800291
292 // setup failure handler
Andrew Browna450fad2015-01-22 11:24:40 -0800293 final OnRegisterFailed failureHandler = new OnRegisterFailed() {
294 @Override
295 public void onRegisterFailed(Name prefix) {
Andrew Browndb457052015-02-21 15:41:58 -0800296 logger.severe("Failed to register name to put: " + prefix.toUri());
Andrew Browna450fad2015-01-22 11:24:40 -0800297 eventHandler.notify(new Exception("Failed to register name to put: " + prefix.toUri()));
298 }
299 };
Andrew Browna88e6ef2015-01-22 11:43:44 -0800300
301 // setup forwarding flags
Andrew Browna450fad2015-01-22 11:24:40 -0800302 final ForwardingFlags flags = new ForwardingFlags();
303 flags.setCapture(true); // no shorter routes will answer for this prefix, see http://redmine.named-data.net/projects/nfd/wiki/RibMgmt#Route-inheritance
304 flags.setChildInherit(true); // the interest name may have child components after the prefix
305
Andrew Browna88e6ef2015-01-22 11:43:44 -0800306 // start background thread
Andrew Browna450fad2015-01-22 11:24:40 -0800307 Thread backgroundThread = new Thread(new Runnable() {
308 @Override
309 public void run() {
310 // register name on the face
311 try {
312 face.registerPrefix(prefix, interestHandler, failureHandler, flags);
313 logger.info("Registered data : " + prefix.toUri());
314 } catch (IOException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800315 logger.severe("Could not connect to face to register prefix: " + prefix.toUri() + e);
Andrew Browna450fad2015-01-22 11:24:40 -0800316 eventHandler.notify(e);
317 } catch (net.named_data.jndn.security.SecurityException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800318 logger.severe("Error registering prefix: " + prefix.toUri() + e);
Andrew Browna450fad2015-01-22 11:24:40 -0800319 eventHandler.notify(e);
320 }
321
322 // process events until told to stop or error bubbles up
323 while (observer.errorCount() == 0 && !observer.mustStop()) {
324 try {
325 synchronized (face) {
326 face.processEvents();
327 }
328 } catch (IOException | EncodingException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800329 logger.warning("Failed to process events." + e);
Andrew Browna450fad2015-01-22 11:24:40 -0800330 eventHandler.notify(e);
331 }
332 sleep();
333 }
334 }
335 });
Andrew Brown665c0c12015-01-22 15:57:53 -0800336 backgroundThread.setName(String.format("Server.on(%s)", prefix.toUri()));
Andrew Browna450fad2015-01-22 11:24:40 -0800337 backgroundThread.setDaemon(true);
338 backgroundThread.start();
339
340 return observer;
341 }
342
343 /**
344 * Put the current thread to sleep to allow time for IO
345 */
346 protected void sleep() {
347 try {
348 Thread.currentThread().sleep(DEFAULT_SLEEP_TIME);
349 } catch (InterruptedException e) {
Andrew Browndb457052015-02-21 15:41:58 -0800350 logger.severe("Event loop interrupted." + e);
Andrew Browna450fad2015-01-22 11:24:40 -0800351 }
352 }
353
354}