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