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