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