|
1 /* Copyright 2004-2006 BBN Technologies Corporation |
|
2 * |
|
3 * Licensed under the Apache License, Version 2.0 (the "License"); you may not |
|
4 * use this file except in compliance with the License. You may obtain a copy |
|
5 * of the License at http://www.apache.org/licenses/LICENSE-2.0 |
|
6 * |
|
7 * Unless required by applicable law or agreed to in writing, software |
|
8 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
|
9 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
10 * |
|
11 * See the License for the specific language governing permissions and |
|
12 * limitations under the License. |
|
13 * |
|
14 */ |
|
15 |
|
16 #ifndef _EXTERNAL_CONVERGENCE_LAYER_H_ |
|
17 #define _EXTERNAL_CONVERGENCE_LAYER_H_ |
|
18 |
|
19 #ifndef DTN_CONFIG_STATE |
|
20 #error "MUST INCLUDE dtn-config.h before including this file" |
|
21 #endif |
|
22 |
|
23 #if defined(XERCES_C_ENABLED) && defined(EXTERNAL_CL_ENABLED) |
|
24 |
|
25 #include <string> |
|
26 #include <list> |
|
27 |
|
28 /* Note that these classes are now deprecated, we'll need to rewrite */ |
|
29 /* the code at some point to use the new standard classes. In the */ |
|
30 /* meantime, quiet the warnings. */ |
|
31 /* undefine __DEPRECATED and remember it was set*/ |
|
32 #ifdef __DEPRECATED |
|
33 # define __DEPRECATED_save |
|
34 # undef __DEPRECATED |
|
35 #endif |
|
36 |
|
37 #include <ext/hash_map> |
|
38 |
|
39 /* re-define __DEPRECATED if it was set */ |
|
40 #ifdef __DEPRECATED_save |
|
41 # define __DEPRECATED |
|
42 #endif |
|
43 |
|
44 #include <oasys/thread/Thread.h> |
|
45 #include <oasys/thread/Mutex.h> |
|
46 #include <oasys/io/TCPServer.h> |
|
47 |
|
48 #include "ConvergenceLayer.h" |
|
49 #include "clevent.h" |
|
50 #include "bundling/BundleList.h" |
|
51 #include "bundling/BundleEvent.h" |
|
52 #include "contacts/NamedAttribute.h" |
|
53 |
|
54 namespace dtn { |
|
55 |
|
56 // g++ 4.3.x needs this unrolled, can't use a forward decl of the form |
|
57 // class dtn::clmessage::bundle_attributes; |
|
58 namespace clmessage { |
|
59 class bundle_attributes; |
|
60 class link_config_parameters; |
|
61 }; |
|
62 |
|
63 using __gnu_cxx::hash_multimap; |
|
64 using __gnu_cxx::hash; |
|
65 |
|
66 class Interface; |
|
67 class Contact; |
|
68 class ECLModule; |
|
69 |
|
70 typedef ::xsd::cxx::tree::sequence<clmessage::key_value_pair> KeyValueSequence; |
|
71 |
|
72 /** Base class for resources that should be owned by an ECLModule. |
|
73 * |
|
74 * Classes derived from this class are used for keeping track of various |
|
75 * resources (interfaces and links, for instance) that belong to a particular |
|
76 * module. This base class holds info about the owner module as well as a copy |
|
77 * of the CLEvent that tells the external module to create the resource. |
|
78 */ |
|
79 class ECLResource : public CLInfo { |
|
80 public: |
|
81 virtual ~ECLResource() { |
|
82 delete create_message_; |
|
83 } |
|
84 |
|
85 /// The protocol that this resource is intended for. |
|
86 std::string protocol_; |
|
87 |
|
88 /// The CLEvent that will create this resource, in case we must send |
|
89 /// it again. |
|
90 clmessage::cl_message* create_message_; |
|
91 |
|
92 /// The module that owns this resource (this will be NULL if the resource |
|
93 /// is unclaimed). |
|
94 ECLModule* module_; |
|
95 |
|
96 oasys::Mutex lock_; |
|
97 |
|
98 bool should_delete_; |
|
99 |
|
100 protected: |
|
101 ECLResource(std::string p, clmessage::cl_message* create) : |
|
102 lock_("ECLResource") { |
|
103 protocol_ = p; |
|
104 create_message_ = create; |
|
105 module_ = NULL; |
|
106 should_delete_ = true; |
|
107 } |
|
108 }; |
|
109 |
|
110 |
|
111 /** Represents a single Interface. |
|
112 */ |
|
113 class ECLInterfaceResource : public ECLResource { |
|
114 public: |
|
115 ECLInterfaceResource(std::string p, clmessage::cl_message* create, |
|
116 Interface* i) : ECLResource(p, create) { |
|
117 interface_ = i; |
|
118 } |
|
119 |
|
120 Interface* interface_; |
|
121 }; |
|
122 |
|
123 |
|
124 /** Represents a single Link. |
|
125 */ |
|
126 class ECLLinkResource : public ECLResource { |
|
127 public: |
|
128 ECLLinkResource(std::string p, clmessage::cl_message* create, |
|
129 const LinkRef& l, bool disc); |
|
130 |
|
131 /// Reference to the link that this Resource represents. |
|
132 LinkRef link_; |
|
133 |
|
134 /// The state that the ECLModule knows the link to be in, independent of |
|
135 /// the state in the link itself. This is useful for state changes that |
|
136 /// originate at the CL rather than the BPA. |
|
137 Link::state_t known_state_; |
|
138 |
|
139 /// True if this link was discovered rather than created by the BPA. |
|
140 bool is_discovered_; |
|
141 |
|
142 |
|
143 /** Add a bundle to this link's outgoing bundle list. |
|
144 * |
|
145 * @param bundle The bundle to be placed on the outgoing list. A new |
|
146 * BundleRef will be created for the bundle. |
|
147 */ |
|
148 void add_outgoing_bundle(Bundle* bundle); |
|
149 |
|
150 |
|
151 /** Retrieve a bundle from this link's outgoing bundle list. |
|
152 * |
|
153 * @param bundleid The ID of the bundle to retrieve. |
|
154 * |
|
155 * @return The OutgoingBundle object for the requested bundle if it |
|
156 * exists on the outgoing bundle list, NULL if it does not. |
|
157 */ |
|
158 BundleRef get_outgoing_bundle(clmessage::bundle_attributes bundle_attribs); |
|
159 |
|
160 bool has_outgoing_bundle(Bundle* bundle); |
|
161 |
|
162 |
|
163 /** Erase a bundle from this link's outgoing bundle list. |
|
164 * |
|
165 * @param outgoing_bundle The bundle to be removed from the outgoing list. |
|
166 */ |
|
167 bool erase_outgoing_bundle(Bundle* bundle); |
|
168 |
|
169 |
|
170 /** Get the actual outgoing bundle list. |
|
171 * |
|
172 * This is used in ECLModule::cleanup() to iterate through the list. |
|
173 */ |
|
174 BundleList& get_bundle_set(); |
|
175 |
|
176 /** Set the link's high-water mark. |
|
177 */ |
|
178 void set_high_water_mark(int high_water_mark) { |
|
179 high_water_mark_ = high_water_mark; |
|
180 } |
|
181 |
|
182 /** Check if the high-water mark would be crossed. |
|
183 * @param queued_bytes The number of bytes queued on the link. |
|
184 * @return True if queued_bytes is greater than or equal to the link's |
|
185 * high-water mark; false otherwise. |
|
186 */ |
|
187 bool high_water_mark_crossed(int queued_bytes) const { |
|
188 return (high_water_mark_ > 0 && queued_bytes >= high_water_mark_); |
|
189 } |
|
190 |
|
191 /** Set the link's low-water mark. |
|
192 */ |
|
193 void set_low_water_mark(int low_water_mark) { |
|
194 low_water_mark_ = low_water_mark; |
|
195 } |
|
196 |
|
197 /** Check if the low-water mark would be crossed. |
|
198 * @param queued_bytes The number of bytes queued on the link. |
|
199 * @return True if queued_bytes is greater than or equal to the link's |
|
200 * low-water mark; false otherwise. |
|
201 */ |
|
202 bool low_water_mark_crossed(int queued_bytes) const { |
|
203 return (queued_bytes <= low_water_mark_); |
|
204 } |
|
205 |
|
206 private: |
|
207 /// The list of bundles going out on this link. |
|
208 BundleList outgoing_bundles_; |
|
209 |
|
210 /// The high-water mark for this link. |
|
211 int high_water_mark_; |
|
212 |
|
213 /// The low-water mark for this link. |
|
214 int low_water_mark_; |
|
215 }; |
|
216 |
|
217 |
|
218 /** Hash function for a std::string. |
|
219 */ |
|
220 struct StringHash { |
|
221 size_t operator()(std::string s) const { |
|
222 size_t h = 0; |
|
223 for (unsigned i = 0; i < s.length(); ++i) |
|
224 h = h * 5 + s[i]; |
|
225 |
|
226 return h; |
|
227 } |
|
228 }; |
|
229 |
|
230 typedef hash_multimap<std::string, ECLLinkResource*, StringHash> |
|
231 LinkHashMap; |
|
232 |
|
233 |
|
234 /** The external convergence layer proxy on the DTN2 side. |
|
235 * |
|
236 * This class interacts with DTN2 as any other conventional convergence layer. |
|
237 * All interfaces and links on an external CLA appear to DTN2 to be on this |
|
238 * CL. |
|
239 * |
|
240 * Every Interface or Link intended for an external module must specify this |
|
241 * convergence layer's name ('extcl') as its convergence layer at startup. A |
|
242 * parameter 'protocol={module name}' must appear before any CL-specific |
|
243 * parameters for the resource to indicate which external module it is for. |
|
244 * A list of any resources intended for an external module that has not yet |
|
245 * connected to DTN2 is maintained (this is known as the 'unclaimed resource |
|
246 * list'). |
|
247 */ |
|
248 class ExternalConvergenceLayer : public ConvergenceLayer { |
|
249 public: |
|
250 ExternalConvergenceLayer(); |
|
251 ~ExternalConvergenceLayer(); |
|
252 |
|
253 /** Start the ECLA listener thread. |
|
254 * |
|
255 * This should be called before an instance of ExternalConvergenceLayer is |
|
256 * given to ConvergenceLayer. |
|
257 */ |
|
258 void start(); |
|
259 |
|
260 bool set_cla_parameters(AttributeVector ¶ms); |
|
261 bool set_interface_defaults(int argc, const char* argv[], |
|
262 const char** invalidp); |
|
263 bool interface_up(Interface* iface, int argc, const char* argv[]); |
|
264 bool interface_down(Interface* iface); |
|
265 void dump_interface(Interface* iface, oasys::StringBuffer* buf); |
|
266 bool set_link_defaults(int argc, const char* argv[], const char** invalidp); |
|
267 bool init_link(const LinkRef& link, int argc, const char* argv[]); |
|
268 void delete_link(const LinkRef& link); |
|
269 void dump_link(const LinkRef& link, oasys::StringBuffer* buf); |
|
270 bool reconfigure_link(const LinkRef& link, int argc, const char* argv[]); |
|
271 void reconfigure_link(const LinkRef& link, AttributeVector& params); |
|
272 bool open_contact(const ContactRef& contact); |
|
273 bool close_contact(const ContactRef& contact); |
|
274 void bundle_queued(const LinkRef& link, const BundleRef& bundle); |
|
275 void cancel_bundle(const LinkRef& link, const BundleRef& bundle); |
|
276 bool is_queued(const LinkRef& link, Bundle* bundle); |
|
277 void is_eid_reachable(const std::string& query_id, Interface* iface, |
|
278 const std::string& endpoint); |
|
279 void query_link_attributes(const std::string& query_id,const LinkRef& link, |
|
280 const AttributeNameVector& attributes); |
|
281 void query_iface_attributes(const std::string& query_id, Interface* iface, |
|
282 const AttributeNameVector& attributes); |
|
283 void query_cla_parameters(const std::string& query_id, |
|
284 const AttributeNameVector& parameters); |
|
285 void shutdown(); |
|
286 |
|
287 |
|
288 /** Take unclaimed resources intended for a given protocol. |
|
289 * |
|
290 * This will assign to the given module any resource on the unclaimed |
|
291 * resource list matching the given protocol by setting the |
|
292 * ECLResource::module field. All matching resources are removed from the |
|
293 * unclaimed resource list and returned. |
|
294 * |
|
295 * @param protocol - The name of the protocol to match. |
|
296 * @param owner - The module that will own the matching resources. |
|
297 * |
|
298 * @return A list containing all resources that matched the protocol. |
|
299 */ |
|
300 std::list<ECLResource*> take_resources(std::string protocol); |
|
301 |
|
302 |
|
303 /** Give a list of Interface resources back to the unclaimed resource list. |
|
304 * |
|
305 * The resources will be placed back on the unclaimed resource list and |
|
306 * the ECLResource::module field set to NULL. |
|
307 */ |
|
308 void give_resources(std::list<ECLInterfaceResource*>& list); |
|
309 |
|
310 |
|
311 /** Give a list of Interface resources back to the unclaimed resource list. |
|
312 * |
|
313 * The resources will be placed back on the unclaimed resource list and |
|
314 * the ECLResource::module field set to NULL. |
|
315 */ |
|
316 void give_resources(LinkHashMap& list); |
|
317 |
|
318 |
|
319 /** Delete a resource. |
|
320 * |
|
321 * This will remove the resource from the list of unclaimed resources and |
|
322 * call 'delete' on the pointer. |
|
323 */ |
|
324 void delete_resource(ECLResource* resource); |
|
325 |
|
326 |
|
327 /** Add a module to the active module list. |
|
328 */ |
|
329 void add_module(ECLModule* module); |
|
330 |
|
331 |
|
332 /** Remove a module from the active module list. |
|
333 */ |
|
334 void remove_module(ECLModule* module); |
|
335 |
|
336 |
|
337 /** Retrieve a module matching the given protocol name. |
|
338 * |
|
339 * @param protocol - The name of the protocol to match. |
|
340 * @return A pointer to the module matching the protocol, or NULL if no |
|
341 * such module exists. |
|
342 */ |
|
343 ECLModule* get_module(const std::string& protocol); |
|
344 |
|
345 /// The path to the XSD file that specifies the XML messages between the |
|
346 /// BPA and the CLA. This is set with the command 'ecla set xsd_file' |
|
347 static std::string schema_; |
|
348 |
|
349 static bool client_validation_; |
|
350 |
|
351 /// The address on which the Listener thread will listen. This is set with |
|
352 /// the command 'ecla set listen_addr' |
|
353 static in_addr_t server_addr_; |
|
354 |
|
355 /// The address on which the Listener thread will listen. This is set with |
|
356 /// the command 'ecla set listen_port' |
|
357 static u_int16_t server_port_; |
|
358 |
|
359 static bool create_discovered_links_; |
|
360 |
|
361 static bool discovered_prev_hop_header_; |
|
362 |
|
363 /// This is used in ECLModule::send_message() to generate the XML |
|
364 /// namespace/schema info at the start of every message. |
|
365 static xml_schema::namespace_infomap namespace_map_; |
|
366 |
|
367 |
|
368 /// ECLModule locks this when it enters ECLModule::cleanup() to prevent |
|
369 /// race conditions on resources that are being cleaned up. |
|
370 oasys::Mutex global_resource_lock_; |
|
371 |
|
372 |
|
373 private: |
|
374 /** Thread to listen for connections from new external modules. |
|
375 * |
|
376 * This thread will wait on accept() for connections on the designated |
|
377 * port (where this port is specified is TBD) on localhost for connections |
|
378 * from new external modules. For each new connection, an ECLModule is |
|
379 * created and started. |
|
380 */ |
|
381 class Listener : public oasys::TCPServerThread { |
|
382 public: |
|
383 Listener(ExternalConvergenceLayer& cl); |
|
384 virtual ~Listener(); |
|
385 |
|
386 void start(); |
|
387 virtual void accepted(int fd, in_addr_t addr, u_int16_t port); |
|
388 |
|
389 private: |
|
390 /// Reference back to the convergence layer. |
|
391 ExternalConvergenceLayer& cl_; |
|
392 }; // class Listener |
|
393 |
|
394 |
|
395 /** Add a resource to the unclaimed resource list. |
|
396 */ |
|
397 void add_resource(ECLResource* resource); |
|
398 |
|
399 /** Convert an arg vector to a KeyValueSequence. |
|
400 * |
|
401 * This will take a number of strings (in argv) in the form 'name=value' |
|
402 * and convert them to a KeyValueSequence suitable for XML messages. |
|
403 * |
|
404 * @param argc Number of arguments in argv. |
|
405 * @param argv The vector of arguments. |
|
406 * @param param_sequence An instance of KeyValueSequence that will be |
|
407 * populated with the parameters. |
|
408 */ |
|
409 void build_param_sequence(int argc, const char* argv[], |
|
410 KeyValueSequence& param_sequence); |
|
411 |
|
412 /** Fill in the fields of a bundle_attributes object. |
|
413 * |
|
414 * This will complete the bundle_attributes instance based on the given |
|
415 * bundle. |
|
416 */ |
|
417 void fill_bundle_attributes(const BundleRef& bundle, |
|
418 clmessage::bundle_attributes& attribs); |
|
419 |
|
420 /// The list of active modules. |
|
421 std::list<ECLModule*> module_list_; |
|
422 |
|
423 /// Mutex for module_list_ access. |
|
424 oasys::Mutex module_mutex_; |
|
425 |
|
426 /// The unclaimed resource list. |
|
427 std::list<ECLResource*> resource_list_; |
|
428 |
|
429 /// Mutex for resource_list_ access. |
|
430 oasys::Mutex resource_mutex_; |
|
431 |
|
432 /// The thread listening for new modules. |
|
433 Listener listener_; |
|
434 }; |
|
435 |
|
436 |
|
437 /** Functions for converting between various DTN2 types and their corresponding |
|
438 * value in the clmessage namespace. |
|
439 */ |
|
440 class XMLConvert { |
|
441 public: |
|
442 static clmessage::linkTypeType convert_link_type(Link::link_type_t type); |
|
443 static Link::link_type_t convert_link_type(clmessage::linkTypeType type); |
|
444 |
|
445 static Link::state_t convert_link_state(clmessage::linkStateType state); |
|
446 |
|
447 static ContactEvent::reason_t convert_link_reason( |
|
448 clmessage::linkReasonType reason); |
|
449 }; |
|
450 |
|
451 } // namespace dtn |
|
452 |
|
453 #endif // XERCES_C_ENABLED && EXTERNAL_CL_ENABLED |
|
454 #endif // _EXTERNAL_CONVERGENCE_LAYER_H_ |
|
455 |