]> git.evergreen-ils.org Git - OpenSRF.git/blob - src/router/osrf_router.c
1. Changed several functions that were returning int so that
[OpenSRF.git] / src / router / osrf_router.c
1 #include "osrf_router.h"
2
3 /**
4         @file osrf_router.c
5         @brief Implementation of osrfRouter.
6
7         The router opens multiple Jabber sessions for the same username and domain, one for
8         each server class.  The Jabber IDs for these sessions are distinguished by the use of
9         the class names as Jabber resource names.
10
11         For each server class there may be multiple server nodes.
12 */
13
14 /* a router maintains a list of server classes */
15
16 /**
17         @brief Collection of server classes, with connection parameters for Jabber.
18  */
19 struct osrfRouterStruct {
20
21         /** 
22                 @brief Hash store of server classes.
23         
24                 For each entry, the key is the class name, and the corresponding datum is an
25                 osrfRouterClass.
26         */
27         osrfHash* classes;
28         char* domain;         /**< Domain name of Jabber server. */
29         char* name;           /**< Router's username for the Jabber logon. */
30         char* resource;       /**< Router's resource name for the Jabber logon. */
31         char* password;       /**< Router's password for the Jabber logon. */
32         int port;             /**< Jabber's port number. */
33         sig_atomic_t stop;    /**< To be set by signal handler to interrupt main loop */
34
35         /** Array of client domains that we allow to send requests through us. */
36         osrfStringArray* trustedClients;
37         /** Array of server domains that we allow to register, etc. with us. */
38         osrfStringArray* trustedServers;
39
40         transport_client* connection;
41 };
42
43 /**
44         @brief Maintains a set of server nodes belonging to the same class.
45 */
46 struct _osrfRouterClassStruct {
47         osrfRouter* router;         /**< The osrfRouter that owns this osrfRouterClass. */
48         osrfHashIterator* itr;      /**< Iterator for set of osrfRouterNodes. */
49         /**
50                 @brief Hash store of server nodes.
51
52                 The key of each entry is a node name, and the associated data is an osrfRouterNode.
53                 We install a callback for freeing the entries.
54         */
55         osrfHash* nodes;
56         /** The transport_client used for communicating with this server. */
57         transport_client* connection;
58 };
59 typedef struct _osrfRouterClassStruct osrfRouterClass;
60
61 /**
62         @brief Represents a link to a single server's inbound connection.
63 */
64 struct _osrfRouterNodeStruct {
65         char* remoteId;     /**< Send message to me via this login. */
66         int count;          /**< How many message have been sent to this node. */
67         transport_message* lastMessage;
68 };
69 typedef struct _osrfRouterNodeStruct osrfRouterNode;
70
71 static osrfRouterClass* osrfRouterAddClass( osrfRouter* router, const char* classname );
72 static void osrfRouterClassAddNode( osrfRouterClass* rclass, const char* remoteId );
73 static void osrfRouterHandleCommand( osrfRouter* router, transport_message* msg );
74 static int osrfRouterClassHandleMessage( osrfRouter* router,
75                 osrfRouterClass* rclass, transport_message* msg );
76 static void osrfRouterRemoveClass( osrfRouter* router, const char* classname );
77 static int osrfRouterClassRemoveNode( osrfRouter* router, const char* classname,
78                 const char* remoteId );
79 static void osrfRouterClassFree( char* classname, void* rclass );
80 static void osrfRouterNodeFree( char* remoteId, void* node );
81 static osrfRouterClass* osrfRouterFindClass( osrfRouter* router, const char* classname );
82 static osrfRouterNode* osrfRouterClassFindNode( osrfRouterClass* rclass,
83                 const char* remoteId );
84 static int _osrfRouterFillFDSet( osrfRouter* router, fd_set* set );
85 static void osrfRouterHandleIncoming( osrfRouter* router );
86 static int osrfRouterClassHandleIncoming( osrfRouter* router,
87                 const char* classname,  osrfRouterClass* class );
88 static transport_message* osrfRouterClassHandleBounce( osrfRouter* router,
89                 const char* classname, osrfRouterClass* rclass, transport_message* msg );
90 static void osrfRouterHandleAppRequest( osrfRouter* router, transport_message* msg );
91 static int osrfRouterRespondConnect( osrfRouter* router, transport_message* msg,
92                 osrfMessage* omsg );
93 static int osrfRouterProcessAppRequest( osrfRouter* router, transport_message* msg,
94                 osrfMessage* omsg );
95 static int osrfRouterHandleAppResponse( osrfRouter* router,
96                 transport_message* msg, osrfMessage* omsg, const jsonObject* response );
97 static int osrfRouterHandleMethodNFound( osrfRouter* router, transport_message* msg,
98                 osrfMessage* omsg );
99
100 #define ROUTER_REGISTER "register"
101 #define ROUTER_UNREGISTER "unregister"
102
103 #define ROUTER_REQUEST_CLASS_LIST "opensrf.router.info.class.list"
104 #define ROUTER_REQUEST_STATS_NODE_FULL "opensrf.router.info.stats.class.node.all"
105 #define ROUTER_REQUEST_STATS_CLASS_FULL "opensrf.router.info.stats.class.all"
106 #define ROUTER_REQUEST_STATS_CLASS "opensrf.router.info.stats.class"
107 #define ROUTER_REQUEST_STATS_CLASS_SUMMARY "opensrf.router.info.stats.class.summary"
108
109 /**
110         @brief Stop the otherwise infinite main loop of the router.
111         @param router Pointer to the osrfRouter to be stopped.
112
113         To be called by a signal handler.
114 */
115 void router_stop( osrfRouter* router )
116 {
117         if( router )
118                 router->stop = 1;
119 }
120
121 /**
122         @brief Allocate and initialize a new osrfRouter.
123         @param domain Domain name of Jabber server
124         @param name Router's username for the Jabber logon.
125         @param resource Router's resource name for the Jabber logon.
126         @param password Router's password for the Jabber logon.
127         @param port Jabber's port number.
128         @param trustedClients Array of client domains that we allow to send requests through us.
129         @param trustedServers Array of server domains that we allow to register, etc. with us.
130         @return Pointer to the newly allocated osrfRouter.
131
132         Don't connect to Jabber yet.  We'll do that later, upon a call to osrfRouterConnect().
133
134         The calling code is responsible for freeing the osrfRouter by calling osrfRouterFree().
135 */
136 osrfRouter* osrfNewRouter(
137                 const char* domain, const char* name,
138                 const char* resource, const char* password, int port,
139                 osrfStringArray* trustedClients, osrfStringArray* trustedServers ) {
140
141         if(!( domain && name && resource && password && port && trustedClients && trustedServers ))
142                 return NULL;
143
144         osrfRouter* router     = safe_malloc(sizeof(osrfRouter));
145         router->domain         = strdup(domain);
146         router->name           = strdup(name);
147         router->password       = strdup(password);
148         router->resource       = strdup(resource);
149         router->port           = port;
150         router->stop           = 0;
151
152         router->trustedClients = trustedClients;
153         router->trustedServers = trustedServers;
154
155
156         router->classes = osrfNewHash();
157         osrfHashSetCallback(router->classes, &osrfRouterClassFree);
158
159         // Prepare to connect to Jabber, as a non-component, over TCP (not UNIX domain).
160         router->connection = client_init( domain, port, NULL, 0 );
161
162         return router;
163 }
164
165 /**
166         @brief Connect to Jabber.
167         @param router Pointer to the osrfRouter to connect to Jabber
168         @return 0 if successful, or -1 on error.
169
170         Allow up to 10 seconds for the logon to succeed.
171
172         We connect over TCP (not over a UNIX domain), as a non-component.
173 */
174 int osrfRouterConnect( osrfRouter* router ) {
175         if(!router) return -1;
176         int ret = client_connect( router->connection, router->name,
177                         router->password, router->resource, 10, AUTH_DIGEST );
178         if( ret == 0 ) return -1;
179         return 0;
180 }
181
182 /**
183         @brief Enter endless loop to receive and respond to input.
184         @param router Pointer to the osrfRouter that's looping.
185         @return 
186
187         On each iteration: wait for incoming messages to arrive on any of our sockets -- i.e.
188         either the top level socket belong to the router or any of the lower level sockets
189         belonging to the classes.  React to the incoming activity as needed.
190
191         We don't exit the loop until we receive a signal to stop, or until we encounter an error.
192 */
193 void osrfRouterRun( osrfRouter* router ) {
194         if(!(router && router->classes)) return;
195
196         int routerfd = client_sock_fd( router->connection );
197         int selectret = 0;
198
199         // Loop until a signal handler sets router->stop
200         while( ! router->stop ) {
201
202                 fd_set set;
203                 int maxfd = _osrfRouterFillFDSet( router, &set );
204                 int numhandled = 0;
205
206                 if( (selectret = select(maxfd + 1, &set, NULL, NULL, NULL)) < 0 ) {
207                         if( EINTR == errno ) {
208                                 if( router->stop ) {
209                                         osrfLogWarning( OSRF_LOG_MARK, "Top level select call interrupted by signal" );
210                                         break;
211                                 }
212                                 else
213                                         continue;    // Irrelevant signal; ignore it
214                         } else {
215                                 osrfLogWarning( OSRF_LOG_MARK, "Top level select call failed with errno %d: %s",
216                                                 errno, strerror( errno ) );
217                                 break;
218                         }
219                 }
220
221                 /* see if there is a top level router message */
222
223                 if( FD_ISSET(routerfd, &set) ) {
224                         osrfLogDebug( OSRF_LOG_MARK, "Top router socket is active: %d", routerfd );
225                         numhandled++;
226                         osrfRouterHandleIncoming( router );
227                 }
228
229                 /* now check each of the connected classes and see if they have data to route */
230                 while( numhandled < selectret ) {
231
232                         osrfRouterClass* class;
233                         osrfHashIterator* itr = osrfNewHashIterator(router->classes);
234
235                         while( (class = osrfHashIteratorNext(itr)) ) {
236
237                                 const char* classname = osrfHashIteratorKey(itr);
238
239                                 if( classname && (class = osrfRouterFindClass( router, classname )) ) {
240
241                                         osrfLogDebug( OSRF_LOG_MARK, "Checking %s for activity...", classname );
242
243                                         int sockfd = client_sock_fd( class->connection );
244                                         if(FD_ISSET( sockfd, &set )) {
245                                                 osrfLogDebug( OSRF_LOG_MARK, "Socket is active: %d", sockfd );
246                                                 numhandled++;
247                                                 osrfRouterClassHandleIncoming( router, classname, class );
248                                         }
249                                 }
250                         }
251
252                         osrfHashIteratorFree(itr);
253                 }
254         }
255 }
256
257
258 /**
259         @brief Handle incoming requests to the router.
260         @param router Pointer to the osrfRouter.
261
262         Read all available input messages from the top-level transport_client.  For each one:
263         if the domain of the sender's Jabber id is on the list of approved domains, pass the
264         message to osrfRouterHandleCommand() (if there's a message) or osrfRouterHandleAppRequest()
265         (if there isn't).  If the domain is @em not on the approved list, log a warning and
266         discard the message.
267 */
268 static void osrfRouterHandleIncoming( osrfRouter* router ) {
269         if(!router) return;
270
271         transport_message* msg = NULL;
272
273         while( (msg = client_recv( router->connection, 0 )) ) {  // for each message
274
275                 if( msg->sender ) {
276
277                         osrfLogDebug(OSRF_LOG_MARK,
278                                 "osrfRouterHandleIncoming(): investigating message from %s", msg->sender);
279
280                         /* if the sender is not on a trusted domain, drop the message */
281                         int len = strlen(msg->sender) + 1;
282                         char domain[len];
283                         jid_get_domain( msg->sender, domain, len - 1 );
284
285                         if(osrfStringArrayContains( router->trustedServers, domain)) {
286
287                                 // If there's a command, obey it.  Otherwise, treat
288                                 // the message as an app session level request.
289                                 if( msg->router_command && *msg->router_command )
290                                         osrfRouterHandleCommand( router, msg );
291                                 else
292                                         osrfRouterHandleAppRequest( router, msg );
293                         }
294                         else
295                                 osrfLogWarning( OSRF_LOG_MARK, 
296                                                 "Received message from un-trusted server domain %s", msg->sender);
297                 }
298
299                 message_free(msg);
300         }
301 }
302
303 /**
304         @brief Handle incoming requests to a router class.
305         @param router Pointer to the osrfRouter.
306         @param classname Class name.
307         @param class Pointer to an osrfRouterClass.
308
309         Make sure sender is a trusted client.
310 */
311 static int osrfRouterClassHandleIncoming( osrfRouter* router, const char* classname,
312                 osrfRouterClass* class ) {
313         if(!(router && class)) return -1;
314
315         transport_message* msg;
316         osrfLogDebug( OSRF_LOG_MARK, "osrfRouterClassHandleIncoming()");
317
318         while( (msg = client_recv( class->connection, 0 )) ) {
319
320                 osrfLogSetXid(msg->osrf_xid);
321
322                 if( msg->sender ) {
323
324                         osrfLogDebug(OSRF_LOG_MARK,
325                                 "osrfRouterClassHandleIncoming(): investigating message from %s", msg->sender);
326
327                         /* if the client is not from a trusted domain, drop the message */
328                         int len = strlen(msg->sender) + 1;
329                         char domain[len];
330                         memset(domain, 0, sizeof(domain));
331                         jid_get_domain( msg->sender, domain, len - 1 );
332
333                         if(osrfStringArrayContains( router->trustedClients, domain)) {
334
335                                 transport_message* bouncedMessage = NULL;
336                                 if( msg->is_error )  {
337
338                                         /* handle bounced message */
339                                         if( !(bouncedMessage = osrfRouterClassHandleBounce( router, classname,
340                                                         class, msg )) )
341                                                 return -1; /* we have no one to send the requested message to */
342
343                                         message_free( msg );
344                                         msg = bouncedMessage;
345                                 }
346                                 osrfRouterClassHandleMessage( router, class, msg );
347
348                         } else {
349                                 osrfLogWarning( OSRF_LOG_MARK, 
350                                                 "Received client message from untrusted client domain %s", domain );
351                         }
352                 }
353
354                 osrfLogClearXid();
355                 message_free( msg );
356         }
357
358         return 0;
359 }
360
361 /**
362         @brief Handle a top level router command.
363         @param router Pointer to the osrfRouter.
364         @param msg Pointer to the transport_message to be handled.
365
366         Currently supported commands:
367         - "register" -- Add a server class and/or a server node to our lists.
368         - "unregister" -- Remove a server class (and any associated nodes) from our list.
369 */
370 static void osrfRouterHandleCommand( osrfRouter* router, transport_message* msg ) {
371         if(!(router && msg && msg->router_class)) return;
372
373         if( !strcmp( msg->router_command, ROUTER_REGISTER ) ) {
374
375                 osrfLogInfo( OSRF_LOG_MARK, "Registering class %s", msg->router_class );
376
377                 // Add the server class to the list, if it isn't already there
378                 osrfRouterClass* class = osrfRouterFindClass( router, msg->router_class );
379                 if(!class)
380                         class = osrfRouterAddClass( router, msg->router_class );
381
382                 // Add the node to the osrfRouterClass's list, if it isn't already there
383                 if(class && ! osrfRouterClassFindNode( class, msg->sender ) )
384                         osrfRouterClassAddNode( class, msg->sender );
385
386         } else if( !strcmp( msg->router_command, ROUTER_UNREGISTER ) ) {
387
388                 if( msg->router_class && *msg->router_class ) {
389                         osrfLogInfo( OSRF_LOG_MARK, "Unregistering router class %s", msg->router_class );
390                         osrfRouterClassRemoveNode( router, msg->router_class, msg->sender );
391                 }
392         }
393 }
394
395
396 /**
397         @brief Adds an osrfRouterClass to a router, and open a connection for it.
398         @param router Pointer to the osrfRouter.
399         @param classname The name of the class this node handles.
400         @return A pointer to the new osrfRouterClass, or NULL upon error.
401
402         Open a Jabber session to be used for this server class.  The Jabber ID incorporates the
403         class name as the resource name.
404 */
405 static osrfRouterClass* osrfRouterAddClass( osrfRouter* router, const char* classname ) {
406         if(!(router && router->classes && classname)) return NULL;
407
408         osrfRouterClass* class = safe_malloc(sizeof(osrfRouterClass));
409         class->nodes = osrfNewHash();
410         class->itr = osrfNewHashIterator(class->nodes);
411         osrfHashSetCallback(class->nodes, &osrfRouterNodeFree);
412         class->router = router;
413
414         class->connection = client_init( router->domain, router->port, NULL, 0 );
415
416         if(!client_connect( class->connection, router->name,
417                         router->password, classname, 10, AUTH_DIGEST ) ) {
418                 // Cast away the constness of classname.  Though ugly, this
419                 // cast is benign because osrfRouterClassFree doesn't actually
420                 // write through the pointer.  We can't readily change its
421                 // signature because it is used for a function pointer, and
422                 // we would have to change other signatures the same way.
423                 osrfRouterClassFree( (char *) classname, class );
424                 return NULL;
425         }
426
427         osrfHashSet( router->classes, class, classname );
428         return class;
429 }
430
431
432 /**
433         @brief Add a new server node to an osrfRouterClass.
434         @param rclass Pointer to the osrfRouterClass to add the node to.
435         @param remoteId The remote login of the osrfRouterNode.
436 */
437 static void osrfRouterClassAddNode( osrfRouterClass* rclass, const char* remoteId ) {
438         if(!(rclass && rclass->nodes && remoteId)) return;
439
440         osrfLogInfo( OSRF_LOG_MARK, "Adding router node for remote id %s", remoteId );
441
442         osrfRouterNode* node = safe_malloc(sizeof(osrfRouterNode));
443         node->count = 0;
444         node->lastMessage = NULL;
445         node->remoteId = strdup(remoteId);
446
447         osrfHashSet( rclass->nodes, node, remoteId );
448 }
449
450 /* copy off the lastMessage, remove the offending node, send error if it's tht last node
451         ? return NULL if it's the last node ?
452 */
453
454 /* handles case where router node is not longer reachable.  copies over the
455         data from the last sent message and returns a newly crafted suitable for treating
456         as a newly inconing message.  Removes the dead node and If there are no more
457         nodes to send the new message to, returns NULL.
458 */
459 static transport_message* osrfRouterClassHandleBounce( osrfRouter* router,
460                 const char* classname, osrfRouterClass* rclass, transport_message* msg ) {
461
462         osrfLogDebug( OSRF_LOG_MARK, "osrfRouterClassHandleBounce()");
463
464         osrfLogInfo( OSRF_LOG_MARK, "Received network layer error message from %s", msg->sender );
465         osrfRouterNode* node = osrfRouterClassFindNode( rclass, msg->sender );
466         transport_message* lastSent = NULL;
467
468         if( node && osrfHashGetCount(rclass->nodes) == 1 ) { /* the last node is dead */
469
470                 if( node->lastMessage ) {
471                         osrfLogWarning( OSRF_LOG_MARK,
472                                         "We lost the last node in the class, responding with error and removing...");
473
474                         transport_message* error = message_init(
475                                 node->lastMessage->body, node->lastMessage->subject,
476                                 node->lastMessage->thread, node->lastMessage->router_from,
477                                 node->lastMessage->recipient );
478                         message_set_osrf_xid(error, node->lastMessage->osrf_xid);
479                         set_msg_error( error, "cancel", 501 );
480
481                         /* send the error message back to the original sender */
482                         client_send_message( rclass->connection, error );
483                         message_free( error );
484                 }
485
486                 return NULL;
487
488         } else {
489
490                 if( node ) {
491                         if( node->lastMessage ) {
492                                 osrfLogDebug( OSRF_LOG_MARK, "Cloning lastMessage so next node can send it");
493                                 lastSent = message_init( node->lastMessage->body,
494                                         node->lastMessage->subject, node->lastMessage->thread, "", node->lastMessage->router_from );
495                                 message_set_router_info( lastSent, node->lastMessage->router_from, NULL, NULL, NULL, 0 );
496                         message_set_osrf_xid( lastSent, node->lastMessage->osrf_xid );
497                         }
498                 } else {
499
500                         osrfLogInfo(OSRF_LOG_MARK, "network error occurred after we removed the class.. ignoring");
501                         return NULL;
502                 }
503         }
504
505         /* remove the dead node */
506         osrfRouterClassRemoveNode( router, classname, msg->sender);
507         return lastSent;
508 }
509
510
511 /*
512         Handles class level requests
513         If we get a regular message, we send it to the next node in the list of nodes
514         if we get an error, it's a bounce back from a previous attempt.  We take the
515         body and thread from the last sent on the node that had the bounced message
516         and propogate them on to the new message being sent
517         @return 0 on success
518 */
519 static int osrfRouterClassHandleMessage(
520                 osrfRouter* router, osrfRouterClass* rclass, transport_message* msg ) {
521         if(!(router && rclass && msg)) return -1;
522
523         osrfLogDebug( OSRF_LOG_MARK, "osrfRouterClassHandleMessage()");
524
525         osrfRouterNode* node = osrfHashIteratorNext( rclass->itr );
526         if(!node) {
527                 osrfHashIteratorReset(rclass->itr);
528                 node = osrfHashIteratorNext( rclass->itr );
529         }
530
531         if(node) {
532
533                 transport_message* new_msg= message_init( msg->body,
534                                 msg->subject, msg->thread, node->remoteId, msg->sender );
535                 message_set_router_info( new_msg, msg->sender, NULL, NULL, NULL, 0 );
536                 message_set_osrf_xid( new_msg, msg->osrf_xid );
537
538                 osrfLogInfo( OSRF_LOG_MARK,  "Routing message:\nfrom: [%s]\nto: [%s]",
539                                 new_msg->router_from, new_msg->recipient );
540
541                 message_free( node->lastMessage );
542                 node->lastMessage = new_msg;
543
544                 if ( client_send_message( rclass->connection, new_msg ) == 0 )
545                         node->count++;
546
547                 else {
548                         message_prepare_xml(new_msg);
549                         osrfLogWarning( OSRF_LOG_MARK, "Error sending message from %s to %s\n%s",
550                                         new_msg->sender, new_msg->recipient, new_msg->msg_xml );
551                 }
552
553         }
554
555         return 0;
556 }
557
558
559 /**
560         @brief Remove a given osrfRouterClass from an osrfRouter
561         @param router Pointer to the osrfRouter.
562         @param classname The name of the class to be removed.
563
564         A callback function, installed in the osrfHash, frees the osrfRouterClass and any
565         associated nodes.
566 */
567 static void osrfRouterRemoveClass( osrfRouter* router, const char* classname ) {
568         if( router && router->classes && classname ) {
569                 osrfLogInfo( OSRF_LOG_MARK, "Removing router class %s", classname );
570                 osrfHashRemove( router->classes, classname );
571         }
572 }
573
574
575 /*
576         Removes the given node from the class.  Also, if this is that last node in the set,
577         removes the class from the router
578         @return 0 on successful removal with no class removal
579         @return 1 on successful remove with class removal
580         @return -1 error on removal
581 */
582 static int osrfRouterClassRemoveNode(
583                 osrfRouter* router, const char* classname, const char* remoteId ) {
584
585         if(!(router && router->classes && classname && remoteId)) return 0;
586
587         osrfLogInfo( OSRF_LOG_MARK, "Removing router node %s", remoteId );
588
589         osrfRouterClass* class = osrfRouterFindClass( router, classname );
590
591         if( class ) {
592
593                 osrfHashRemove( class->nodes, remoteId );
594                 if( osrfHashGetCount(class->nodes) == 0 ) {
595                         osrfRouterRemoveClass( router, classname );
596                         return 1;
597                 }
598
599                 return 0;
600         }
601
602         return -1;
603 }
604
605
606 /**
607         @brief Free a router class object.
608         @param classname Class name.
609         @param c Pointer to the osrfRouterClass, cast to a void pointer.
610
611         This function is designated to the osrfHash as a callback.
612 */
613 static void osrfRouterClassFree( char* classname, void* c ) {
614         if(!(classname && c)) return;
615         osrfRouterClass* rclass = (osrfRouterClass*) c;
616         client_disconnect( rclass->connection );
617         client_free( rclass->connection );
618
619         osrfHashIteratorReset( rclass->itr );
620         osrfRouterNode* node;
621
622         while( (node = osrfHashIteratorNext(rclass->itr)) )
623                 osrfHashRemove( rclass->nodes, node->remoteId );
624
625         osrfHashIteratorFree(rclass->itr);
626         osrfHashFree(rclass->nodes);
627
628         free(rclass);
629 }
630
631 /**
632         @brief Free an osrfRouterNode.
633         @param remoteId Name of router (not used).
634         @param n Pointer to the osrfRouterNode to be freed, cast to a void pointer.
635
636         This is a callback installed in an osrfHash (the nodes member of an osrfRouterClass).
637 */
638 static void osrfRouterNodeFree( char* remoteId, void* n ) {
639         if(!n) return;
640         osrfRouterNode* node = (osrfRouterNode*) n;
641         free(node->remoteId);
642         message_free(node->lastMessage);
643         free(node);
644 }
645
646
647 void osrfRouterFree( osrfRouter* router ) {
648         if(!router) return;
649
650         osrfHashFree(router->classes);
651         free(router->domain);
652         free(router->name);
653         free(router->resource);
654         free(router->password);
655
656         osrfStringArrayFree( router->trustedClients );
657         osrfStringArrayFree( router->trustedServers );
658
659         client_free( router->connection );
660         free(router);
661 }
662
663
664
665 /*
666         Finds the class associated with the given class name in the list of classes
667 */
668 static osrfRouterClass* osrfRouterFindClass( osrfRouter* router, const char* classname ) {
669         if(!( router && router->classes && classname )) return NULL;
670         return (osrfRouterClass*) osrfHashGet( router->classes, classname );
671 }
672
673
674 /*
675         Finds the router node within this class with the given remote id
676 */
677 static osrfRouterNode* osrfRouterClassFindNode( osrfRouterClass* rclass,
678                 const char* remoteId ) {
679         if(!(rclass && remoteId))  return NULL;
680         return (osrfRouterNode*) osrfHashGet( rclass->nodes, remoteId );
681 }
682
683
684 /*
685         Clears and populates the provided fd_set* with file descriptors
686         from the router's top level connection as well as each of the
687         router class connections
688         @return The largest file descriptor found in the filling process
689 */
690 /**
691         @brief Fill an fd_set with all the sockets owned by the osrfRouter.
692         @param router Pointer to the osrfRouter whose sockets are to be used.
693         @param set Pointer to the fd_set that is to be filled.
694         @return The largest file descriptor loaded into the fd_set; or -1 upon error.
695
696         There's one socket for the osrfRouter as a whole, and one for each osrfRouterClass
697         that belongs to it.  We load them all.
698 */
699 static int _osrfRouterFillFDSet( osrfRouter* router, fd_set* set ) {
700         if(!(router && router->classes && set)) return -1;
701
702         FD_ZERO(set);
703         int maxfd = client_sock_fd( router->connection );
704         FD_SET(maxfd, set);
705
706         int sockid;
707
708         osrfRouterClass* class = NULL;
709         osrfHashIterator* itr = osrfNewHashIterator(router->classes);
710
711         while( (class = osrfHashIteratorNext(itr)) ) {
712                 const char* classname = osrfHashIteratorKey(itr);
713
714                 if( classname && (class = osrfRouterFindClass( router, classname )) ) {
715                         sockid = client_sock_fd( class->connection );
716
717                         if( osrfUtilsCheckFileDescriptor( sockid ) ) {
718
719                                 osrfLogWarning(OSRF_LOG_MARK,
720                                         "Removing router class '%s' because of a bad top-level file descriptor [%d]",
721                                         classname, sockid );
722                                 osrfRouterRemoveClass( router, classname );
723
724                         } else {
725                                 if( sockid > maxfd ) maxfd = sockid;
726                                 FD_SET(sockid, set);
727                         }
728                 }
729         }
730
731         osrfHashIteratorFree(itr);
732         return maxfd;
733 }
734
735 /*
736         handles messages that don't have a 'router_command' set.  They are assumed to
737         be app request messages
738 */
739 static void osrfRouterHandleAppRequest( osrfRouter* router, transport_message* msg ) {
740
741         int T = 32;
742         osrfMessage* arr[T];
743         memset(arr, 0, sizeof(arr));
744
745         int num_msgs = osrf_message_deserialize( msg->body, arr, T );
746         osrfMessage* omsg = NULL;
747
748         int i;
749         for( i = 0; i != num_msgs; i++ ) {
750
751                 if( !(omsg = arr[i]) ) continue;
752
753                 switch( omsg->m_type ) {
754
755                         case CONNECT:
756                                 osrfRouterRespondConnect( router, msg, omsg );
757                                 break;
758
759                         case REQUEST:
760                                 osrfRouterProcessAppRequest( router, msg, omsg );
761                                 break;
762
763                         default: break;
764                 }
765
766                 osrfMessageFree( omsg );
767         }
768
769         return;
770 }
771
772 static int osrfRouterRespondConnect( osrfRouter* router, transport_message* msg,
773                 osrfMessage* omsg ) {
774         if(!(router && msg && omsg)) return -1;
775
776         osrfMessage* success = osrf_message_init( STATUS, omsg->thread_trace, omsg->protocol );
777
778         osrfLogDebug( OSRF_LOG_MARK, "router received a CONNECT message from %s", msg->sender );
779
780         osrf_message_set_status_info(
781                 success, "osrfConnectStatus", "Connection Successful", OSRF_STATUS_OK );
782
783         char* data = osrf_message_serialize(success);
784
785         transport_message* return_m = message_init(
786                 data, "", msg->thread, msg->sender, "" );
787
788         client_send_message(router->connection, return_m);
789
790         free(data);
791         osrfMessageFree(success);
792         message_free(return_m);
793
794         return 0;
795 }
796
797
798
799 static int osrfRouterProcessAppRequest( osrfRouter* router, transport_message* msg,
800                 osrfMessage* omsg ) {
801
802         if(!(router && msg && omsg && omsg->method_name)) return -1;
803
804         osrfLogInfo( OSRF_LOG_MARK, "Router received app request: %s", omsg->method_name );
805
806         jsonObject* jresponse = NULL;
807         if(!strcmp( omsg->method_name, ROUTER_REQUEST_CLASS_LIST )) {
808
809                 int i;
810                 jresponse = jsonNewObjectType(JSON_ARRAY);
811
812                 osrfStringArray* keys = osrfHashKeys( router->classes );
813                 for( i = 0; i != keys->size; i++ )
814                         jsonObjectPush( jresponse, jsonNewObject(osrfStringArrayGetString( keys, i )) );
815                 osrfStringArrayFree(keys);
816
817
818         } else if(!strcmp( omsg->method_name, ROUTER_REQUEST_STATS_CLASS_SUMMARY )) {
819
820                 osrfRouterClass* class;
821                 osrfRouterNode* node;
822                 int count = 0;
823
824                 char* classname = jsonObjectToSimpleString( jsonObjectGetIndex( omsg->_params, 0 ) );
825
826                 if (!classname)
827                         return -1;
828
829                 class = osrfHashGet(router->classes, classname);
830                 free(classname);
831
832                 osrfHashIterator* node_itr = osrfNewHashIterator(class->nodes);
833                 while( (node = osrfHashIteratorNext(node_itr)) ) {
834                         count += node->count;
835                         //jsonObjectSetKey( class_res, node->remoteId, jsonNewNumberObject( (double) node->count ) );
836                 }
837                 osrfHashIteratorFree(node_itr);
838
839                 jresponse = jsonNewNumberObject( (double) count );
840
841         } else if(!strcmp( omsg->method_name, ROUTER_REQUEST_STATS_CLASS )) {
842
843                 osrfRouterClass* class;
844                 osrfRouterNode* node;
845
846                 char* classname = jsonObjectToSimpleString( jsonObjectGetIndex( omsg->_params, 0 ) );
847
848                 if (!classname)
849                         return -1;
850
851                 jresponse = jsonNewObjectType(JSON_HASH);
852                 class = osrfHashGet(router->classes, classname);
853                 free(classname);
854
855                 osrfHashIterator* node_itr = osrfNewHashIterator(class->nodes);
856                 while( (node = osrfHashIteratorNext(node_itr)) ) {
857                         jsonObjectSetKey( jresponse, node->remoteId,
858                                         jsonNewNumberObject( (double) node->count ) );
859                 }
860                 osrfHashIteratorFree(node_itr);
861
862         } else if(!strcmp( omsg->method_name, ROUTER_REQUEST_STATS_CLASS_FULL )) {
863
864                 osrfRouterClass* class;
865                 osrfRouterNode* node;
866                 jresponse = jsonNewObjectType(JSON_HASH);
867
868                 osrfHashIterator* class_itr = osrfNewHashIterator(router->classes);
869                 while( (class = osrfHashIteratorNext(class_itr)) ) {
870
871                         jsonObject* class_res = jsonNewObjectType(JSON_HASH);
872                         const char* classname = osrfHashIteratorKey(class_itr);
873
874                         osrfHashIterator* node_itr = osrfNewHashIterator(class->nodes);
875                         while( (node = osrfHashIteratorNext(node_itr)) ) {
876                                 jsonObjectSetKey( class_res, node->remoteId,
877                                                 jsonNewNumberObject( (double) node->count ) );
878                         }
879                         osrfHashIteratorFree(node_itr);
880
881                         jsonObjectSetKey( jresponse, classname, class_res );
882                 }
883
884                 osrfHashIteratorFree(class_itr);
885
886         } else if(!strcmp( omsg->method_name, ROUTER_REQUEST_STATS_NODE_FULL )) {
887
888                 osrfRouterClass* class;
889                 osrfRouterNode* node;
890                 int count;
891                 jresponse = jsonNewObjectType(JSON_HASH);
892
893                 osrfHashIterator* class_itr = osrfNewHashIterator(router->classes);
894                 while( (class = osrfHashIteratorNext(class_itr)) ) {
895
896                         count = 0;
897                         const char* classname = osrfHashIteratorKey(class_itr);
898
899                         osrfHashIterator* node_itr = osrfNewHashIterator(class->nodes);
900                         while( (node = osrfHashIteratorNext(node_itr)) ) {
901                                 count += node->count;
902                         }
903                         osrfHashIteratorFree(node_itr);
904
905                         jsonObjectSetKey( jresponse, classname, jsonNewNumberObject( (double) count ) );
906                 }
907
908                 osrfHashIteratorFree(class_itr);
909
910         } else {
911
912                 return osrfRouterHandleMethodNFound( router, msg, omsg );
913         }
914
915
916         osrfRouterHandleAppResponse( router, msg, omsg, jresponse );
917         jsonObjectFree(jresponse);
918
919         return 0;
920
921 }
922
923
924 static int osrfRouterHandleMethodNFound(
925                 osrfRouter* router, transport_message* msg, osrfMessage* omsg ) {
926
927         osrfMessage* err = osrf_message_init( STATUS, omsg->thread_trace, 1);
928                 osrf_message_set_status_info( err,
929                                 "osrfMethodException", "Router method not found", OSRF_STATUS_NOTFOUND );
930
931                 char* data =  osrf_message_serialize(err);
932
933                 transport_message* tresponse = message_init(
934                                 data, "", msg->thread, msg->sender, msg->recipient );
935
936                 client_send_message(router->connection, tresponse );
937
938                 free(data);
939                 osrfMessageFree( err );
940                 message_free(tresponse);
941                 return 0;
942 }
943
944
945 static int osrfRouterHandleAppResponse( osrfRouter* router,
946         transport_message* msg, osrfMessage* omsg, const jsonObject* response ) {
947
948         if( response ) { /* send the response message */
949
950                 osrfMessage* oresponse = osrf_message_init(
951                                 RESULT, omsg->thread_trace, omsg->protocol );
952
953                 char* json = jsonObjectToJSON(response);
954                 osrf_message_set_result_content( oresponse, json);
955
956                 char* data =  osrf_message_serialize(oresponse);
957                 osrfLogDebug( OSRF_LOG_MARK,  "Responding to client app request with data: \n%s\n", data );
958
959                 transport_message* tresponse = message_init(
960                                 data, "", msg->thread, msg->sender, msg->recipient );
961
962                 client_send_message(router->connection, tresponse );
963
964                 osrfMessageFree(oresponse);
965                 message_free(tresponse);
966                 free(json);
967                 free(data);
968         }
969
970         /* now send the 'request complete' message */
971         osrfMessage* status = osrf_message_init( STATUS, omsg->thread_trace, 1);
972         osrf_message_set_status_info( status, "osrfConnectStatus", "Request Complete",
973                         OSRF_STATUS_COMPLETE );
974
975         char* statusdata = osrf_message_serialize(status);
976
977         transport_message* sresponse = message_init(
978                         statusdata, "", msg->thread, msg->sender, msg->recipient );
979         client_send_message(router->connection, sresponse );
980
981         free(statusdata);
982         osrfMessageFree(status);
983         message_free(sresponse);
984
985         return 0;
986 }
987
988
989
990