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