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