1 #include "osrf_router.h"
5 @brief Implementation of osrfRouter.
7 The router opens multiple Jabber sessions for the same username and domain, one for
8 each server class. The Jabber IDs for these sessions are distinguished by the use of
9 the class names as Jabber resource names.
11 For each server class there may be multiple server nodes.
14 /* a router maintains a list of server classes */
17 @brief Collection of server classes, with connection parameters for Jabber.
19 struct osrfRouterStruct {
22 @brief Hash store of server classes.
24 For each entry, the key is the class name, and the corresponding datum is an
28 char* domain; /**< Domain name of Jabber server. */
29 char* name; /**< Router's username for the Jabber logon. */
30 char* resource; /**< Router's resource name for the Jabber logon. */
31 char* password; /**< Router's password for the Jabber logon. */
32 int port; /**< Jabber's port number. */
33 sig_atomic_t stop; /**< To be set by signal handler to interrupt main loop */
35 /** Array of client domains that we allow to send requests through us. */
36 osrfStringArray* trustedClients;
37 /** Array of server domains that we allow to register, etc. with us. */
38 osrfStringArray* trustedServers;
40 transport_client* connection;
44 @brief Maintains a set of server nodes belonging to the same class.
46 struct _osrfRouterClassStruct {
47 osrfRouter* router; /**< The osrfRouter that owns this osrfRouterClass. */
48 osrfHashIterator* itr; /**< Iterator for set of osrfRouterNodes. */
50 @brief Hash store of server nodes.
52 The key of each entry is a node name, and the associated data is an osrfRouterNode.
53 We install a callback for freeing the entries.
56 /** The transport_client used for communicating with this server. */
57 transport_client* connection;
59 typedef struct _osrfRouterClassStruct osrfRouterClass;
62 @brief Represents a link to a single server's inbound connection.
64 struct _osrfRouterNodeStruct {
65 char* remoteId; /**< Send message to me via this login. */
66 int count; /**< How many message have been sent to this node. */
67 transport_message* lastMessage;
69 typedef struct _osrfRouterNodeStruct osrfRouterNode;
71 static osrfRouterClass* osrfRouterAddClass( osrfRouter* router, const char* classname );
72 static void osrfRouterClassAddNode( osrfRouterClass* rclass, const char* remoteId );
73 static void osrfRouterHandleCommand( osrfRouter* router, transport_message* msg );
74 static int osrfRouterClassHandleMessage( osrfRouter* router,
75 osrfRouterClass* rclass, transport_message* msg );
76 static void osrfRouterRemoveClass( osrfRouter* router, const char* classname );
77 static int osrfRouterClassRemoveNode( osrfRouter* router, const char* classname,
78 const char* remoteId );
79 static void osrfRouterClassFree( char* classname, void* rclass );
80 static void osrfRouterNodeFree( char* remoteId, void* node );
81 static osrfRouterClass* osrfRouterFindClass( osrfRouter* router, const char* classname );
82 static osrfRouterNode* osrfRouterClassFindNode( osrfRouterClass* rclass,
83 const char* remoteId );
84 static int _osrfRouterFillFDSet( osrfRouter* router, fd_set* set );
85 static void osrfRouterHandleIncoming( osrfRouter* router );
86 static int osrfRouterClassHandleIncoming( osrfRouter* router,
87 const char* classname, osrfRouterClass* class );
88 static transport_message* osrfRouterClassHandleBounce( osrfRouter* router,
89 const char* classname, osrfRouterClass* rclass, transport_message* msg );
90 static void osrfRouterHandleAppRequest( osrfRouter* router, transport_message* msg );
91 static int osrfRouterRespondConnect( osrfRouter* router, transport_message* msg,
93 static int osrfRouterProcessAppRequest( osrfRouter* router, transport_message* msg,
95 static int osrfRouterHandleAppResponse( osrfRouter* router,
96 transport_message* msg, osrfMessage* omsg, const jsonObject* response );
97 static int osrfRouterHandleMethodNFound( osrfRouter* router, transport_message* msg,
100 #define ROUTER_REGISTER "register"
101 #define ROUTER_UNREGISTER "unregister"
103 #define ROUTER_REQUEST_CLASS_LIST "opensrf.router.info.class.list"
104 #define ROUTER_REQUEST_STATS_NODE_FULL "opensrf.router.info.stats.class.node.all"
105 #define ROUTER_REQUEST_STATS_CLASS_FULL "opensrf.router.info.stats.class.all"
106 #define ROUTER_REQUEST_STATS_CLASS "opensrf.router.info.stats.class"
107 #define ROUTER_REQUEST_STATS_CLASS_SUMMARY "opensrf.router.info.stats.class.summary"
110 @brief Stop the otherwise infinite main loop of the router.
111 @param router Pointer to the osrfRouter to be stopped.
113 To be called by a signal handler.
115 void router_stop( osrfRouter* router )
122 @brief Allocate and initialize a new osrfRouter.
123 @param domain Domain name of Jabber server
124 @param name Router's username for the Jabber logon.
125 @param resource Router's resource name for the Jabber logon.
126 @param password Router's password for the Jabber logon.
127 @param port Jabber's port number.
128 @param trustedClients Array of client domains that we allow to send requests through us.
129 @param trustedServers Array of server domains that we allow to register, etc. with us.
130 @return Pointer to the newly allocated osrfRouter.
132 Don't connect to Jabber yet. We'll do that later, upon a call to osrfRouterConnect().
134 The calling code is responsible for freeing the osrfRouter by calling osrfRouterFree().
136 osrfRouter* osrfNewRouter(
137 const char* domain, const char* name,
138 const char* resource, const char* password, int port,
139 osrfStringArray* trustedClients, osrfStringArray* trustedServers ) {
141 if(!( domain && name && resource && password && port && trustedClients && trustedServers ))
144 osrfRouter* router = safe_malloc(sizeof(osrfRouter));
145 router->domain = strdup(domain);
146 router->name = strdup(name);
147 router->password = strdup(password);
148 router->resource = strdup(resource);
152 router->trustedClients = trustedClients;
153 router->trustedServers = trustedServers;
156 router->classes = osrfNewHash();
157 osrfHashSetCallback(router->classes, &osrfRouterClassFree);
159 // Prepare to connect to Jabber, as a non-component, over TCP (not UNIX domain).
160 router->connection = client_init( domain, port, NULL, 0 );
166 @brief Connect to Jabber.
167 @param router Pointer to the osrfRouter to connect to Jabber
168 @return 0 if successful, or -1 on error.
170 Allow up to 10 seconds for the logon to succeed.
172 We connect over TCP (not over a UNIX domain), as a non-component.
174 int osrfRouterConnect( osrfRouter* router ) {
175 if(!router) return -1;
176 int ret = client_connect( router->connection, router->name,
177 router->password, router->resource, 10, AUTH_DIGEST );
178 if( ret == 0 ) return -1;
183 @brief Enter endless loop to receive and respond to input.
184 @param router Pointer to the osrfRouter that's looping.
187 On each iteration: wait for incoming messages to arrive on any of our sockets -- i.e.
188 either the top level socket belong to the router or any of the lower level sockets
189 belonging to the classes. React to the incoming activity as needed.
191 We don't exit the loop until we receive a signal to stop, or until we encounter an error.
193 void osrfRouterRun( osrfRouter* router ) {
194 if(!(router && router->classes)) return;
196 int routerfd = client_sock_fd( router->connection );
199 // Loop until a signal handler sets router->stop
200 while( ! router->stop ) {
203 int maxfd = _osrfRouterFillFDSet( router, &set );
206 if( (selectret = select(maxfd + 1, &set, NULL, NULL, NULL)) < 0 ) {
207 if( EINTR == errno ) {
209 osrfLogWarning( OSRF_LOG_MARK, "Top level select call interrupted by signal" );
213 continue; // Irrelevant signal; ignore it
215 osrfLogWarning( OSRF_LOG_MARK, "Top level select call failed with errno %d: %s",
216 errno, strerror( errno ) );
221 /* see if there is a top level router message */
223 if( FD_ISSET(routerfd, &set) ) {
224 osrfLogDebug( OSRF_LOG_MARK, "Top router socket is active: %d", routerfd );
226 osrfRouterHandleIncoming( router );
229 /* now check each of the connected classes and see if they have data to route */
230 while( numhandled < selectret ) {
232 osrfRouterClass* class;
233 osrfHashIterator* itr = osrfNewHashIterator(router->classes);
235 while( (class = osrfHashIteratorNext(itr)) ) {
237 const char* classname = osrfHashIteratorKey(itr);
239 if( classname && (class = osrfRouterFindClass( router, classname )) ) {
241 osrfLogDebug( OSRF_LOG_MARK, "Checking %s for activity...", classname );
243 int sockfd = client_sock_fd( class->connection );
244 if(FD_ISSET( sockfd, &set )) {
245 osrfLogDebug( OSRF_LOG_MARK, "Socket is active: %d", sockfd );
247 osrfRouterClassHandleIncoming( router, classname, class );
252 osrfHashIteratorFree(itr);
259 @brief Handle incoming requests to the router.
260 @param router Pointer to the osrfRouter.
262 Read all available input messages from the top-level transport_client. For each one:
263 if the domain of the sender's Jabber id is on the list of approved domains, pass the
264 message to osrfRouterHandleCommand() (if there's a message) or osrfRouterHandleAppRequest()
265 (if there isn't). If the domain is @em not on the approved list, log a warning and
268 static void osrfRouterHandleIncoming( osrfRouter* router ) {
271 transport_message* msg = NULL;
273 while( (msg = client_recv( router->connection, 0 )) ) { // for each message
277 osrfLogDebug(OSRF_LOG_MARK,
278 "osrfRouterHandleIncoming(): investigating message from %s", msg->sender);
280 /* if the sender is not on a trusted domain, drop the message */
281 int len = strlen(msg->sender) + 1;
283 jid_get_domain( msg->sender, domain, len - 1 );
285 if(osrfStringArrayContains( router->trustedServers, domain)) {
287 // If there's a command, obey it. Otherwise, treat
288 // the message as an app session level request.
289 if( msg->router_command && *msg->router_command )
290 osrfRouterHandleCommand( router, msg );
292 osrfRouterHandleAppRequest( router, msg );
295 osrfLogWarning( OSRF_LOG_MARK,
296 "Received message from un-trusted server domain %s", msg->sender);
304 @brief Handle incoming requests to a router class.
305 @param router Pointer to the osrfRouter.
306 @param classname Class name.
307 @param class Pointer to an osrfRouterClass.
309 Make sure sender is a trusted client.
311 static int osrfRouterClassHandleIncoming( osrfRouter* router, const char* classname,
312 osrfRouterClass* class ) {
313 if(!(router && class)) return -1;
315 transport_message* msg;
316 osrfLogDebug( OSRF_LOG_MARK, "osrfRouterClassHandleIncoming()");
318 while( (msg = client_recv( class->connection, 0 )) ) {
320 osrfLogSetXid(msg->osrf_xid);
324 osrfLogDebug(OSRF_LOG_MARK,
325 "osrfRouterClassHandleIncoming(): investigating message from %s", msg->sender);
327 /* if the client is not from a trusted domain, drop the message */
328 int len = strlen(msg->sender) + 1;
330 memset(domain, 0, sizeof(domain));
331 jid_get_domain( msg->sender, domain, len - 1 );
333 if(osrfStringArrayContains( router->trustedClients, domain)) {
335 transport_message* bouncedMessage = NULL;
336 if( msg->is_error ) {
338 /* handle bounced message */
339 if( !(bouncedMessage = osrfRouterClassHandleBounce( router, classname,
341 return -1; /* we have no one to send the requested message to */
344 msg = bouncedMessage;
346 osrfRouterClassHandleMessage( router, class, msg );
349 osrfLogWarning( OSRF_LOG_MARK,
350 "Received client message from untrusted client domain %s", domain );
362 @brief Handle a top level router command.
363 @param router Pointer to the osrfRouter.
364 @param msg Pointer to the transport_message to be handled.
366 Currently supported commands:
367 - "register" -- Add a server class and/or a server node to our lists.
368 - "unregister" -- Remove a server class (and any associated nodes) from our list.
370 static void osrfRouterHandleCommand( osrfRouter* router, transport_message* msg ) {
371 if(!(router && msg && msg->router_class)) return;
373 if( !strcmp( msg->router_command, ROUTER_REGISTER ) ) {
375 osrfLogInfo( OSRF_LOG_MARK, "Registering class %s", msg->router_class );
377 // Add the server class to the list, if it isn't already there
378 osrfRouterClass* class = osrfRouterFindClass( router, msg->router_class );
380 class = osrfRouterAddClass( router, msg->router_class );
382 // Add the node to the osrfRouterClass's list, if it isn't already there
383 if(class && ! osrfRouterClassFindNode( class, msg->sender ) )
384 osrfRouterClassAddNode( class, msg->sender );
386 } else if( !strcmp( msg->router_command, ROUTER_UNREGISTER ) ) {
388 if( msg->router_class && *msg->router_class ) {
389 osrfLogInfo( OSRF_LOG_MARK, "Unregistering router class %s", msg->router_class );
390 osrfRouterClassRemoveNode( router, msg->router_class, msg->sender );
397 @brief Adds an osrfRouterClass to a router, and open a connection for it.
398 @param router Pointer to the osrfRouter.
399 @param classname The name of the class this node handles.
400 @return A pointer to the new osrfRouterClass, or NULL upon error.
402 Open a Jabber session to be used for this server class. The Jabber ID incorporates the
403 class name as the resource name.
405 static osrfRouterClass* osrfRouterAddClass( osrfRouter* router, const char* classname ) {
406 if(!(router && router->classes && classname)) return NULL;
408 osrfRouterClass* class = safe_malloc(sizeof(osrfRouterClass));
409 class->nodes = osrfNewHash();
410 class->itr = osrfNewHashIterator(class->nodes);
411 osrfHashSetCallback(class->nodes, &osrfRouterNodeFree);
412 class->router = router;
414 class->connection = client_init( router->domain, router->port, NULL, 0 );
416 if(!client_connect( class->connection, router->name,
417 router->password, classname, 10, AUTH_DIGEST ) ) {
418 // Cast away the constness of classname. Though ugly, this
419 // cast is benign because osrfRouterClassFree doesn't actually
420 // write through the pointer. We can't readily change its
421 // signature because it is used for a function pointer, and
422 // we would have to change other signatures the same way.
423 osrfRouterClassFree( (char *) classname, class );
427 osrfHashSet( router->classes, class, classname );
433 @brief Add a new server node to an osrfRouterClass.
434 @param rclass Pointer to the osrfRouterClass to add the node to.
435 @param remoteId The remote login of the osrfRouterNode.
437 static void osrfRouterClassAddNode( osrfRouterClass* rclass, const char* remoteId ) {
438 if(!(rclass && rclass->nodes && remoteId)) return;
440 osrfLogInfo( OSRF_LOG_MARK, "Adding router node for remote id %s", remoteId );
442 osrfRouterNode* node = safe_malloc(sizeof(osrfRouterNode));
444 node->lastMessage = NULL;
445 node->remoteId = strdup(remoteId);
447 osrfHashSet( rclass->nodes, node, remoteId );
450 /* copy off the lastMessage, remove the offending node, send error if it's tht last node
451 ? return NULL if it's the last node ?
454 /* handles case where router node is not longer reachable. copies over the
455 data from the last sent message and returns a newly crafted suitable for treating
456 as a newly inconing message. Removes the dead node and If there are no more
457 nodes to send the new message to, returns NULL.
459 static transport_message* osrfRouterClassHandleBounce( osrfRouter* router,
460 const char* classname, osrfRouterClass* rclass, transport_message* msg ) {
462 osrfLogDebug( OSRF_LOG_MARK, "osrfRouterClassHandleBounce()");
464 osrfLogInfo( OSRF_LOG_MARK, "Received network layer error message from %s", msg->sender );
465 osrfRouterNode* node = osrfRouterClassFindNode( rclass, msg->sender );
466 transport_message* lastSent = NULL;
468 if( node && osrfHashGetCount(rclass->nodes) == 1 ) { /* the last node is dead */
470 if( node->lastMessage ) {
471 osrfLogWarning( OSRF_LOG_MARK,
472 "We lost the last node in the class, responding with error and removing...");
474 transport_message* error = message_init(
475 node->lastMessage->body, node->lastMessage->subject,
476 node->lastMessage->thread, node->lastMessage->router_from,
477 node->lastMessage->recipient );
478 message_set_osrf_xid(error, node->lastMessage->osrf_xid);
479 set_msg_error( error, "cancel", 501 );
481 /* send the error message back to the original sender */
482 client_send_message( rclass->connection, error );
483 message_free( error );
491 if( node->lastMessage ) {
492 osrfLogDebug( OSRF_LOG_MARK, "Cloning lastMessage so next node can send it");
493 lastSent = message_init( node->lastMessage->body,
494 node->lastMessage->subject, node->lastMessage->thread, "", node->lastMessage->router_from );
495 message_set_router_info( lastSent, node->lastMessage->router_from, NULL, NULL, NULL, 0 );
496 message_set_osrf_xid( lastSent, node->lastMessage->osrf_xid );
500 osrfLogInfo(OSRF_LOG_MARK, "network error occurred after we removed the class.. ignoring");
505 /* remove the dead node */
506 osrfRouterClassRemoveNode( router, classname, msg->sender);
512 Handles class level requests
513 If we get a regular message, we send it to the next node in the list of nodes
514 if we get an error, it's a bounce back from a previous attempt. We take the
515 body and thread from the last sent on the node that had the bounced message
516 and propogate them on to the new message being sent
519 static int osrfRouterClassHandleMessage(
520 osrfRouter* router, osrfRouterClass* rclass, transport_message* msg ) {
521 if(!(router && rclass && msg)) return -1;
523 osrfLogDebug( OSRF_LOG_MARK, "osrfRouterClassHandleMessage()");
525 osrfRouterNode* node = osrfHashIteratorNext( rclass->itr );
527 osrfHashIteratorReset(rclass->itr);
528 node = osrfHashIteratorNext( rclass->itr );
533 transport_message* new_msg= message_init( msg->body,
534 msg->subject, msg->thread, node->remoteId, msg->sender );
535 message_set_router_info( new_msg, msg->sender, NULL, NULL, NULL, 0 );
536 message_set_osrf_xid( new_msg, msg->osrf_xid );
538 osrfLogInfo( OSRF_LOG_MARK, "Routing message:\nfrom: [%s]\nto: [%s]",
539 new_msg->router_from, new_msg->recipient );
541 message_free( node->lastMessage );
542 node->lastMessage = new_msg;
544 if ( client_send_message( rclass->connection, new_msg ) == 0 )
548 message_prepare_xml(new_msg);
549 osrfLogWarning( OSRF_LOG_MARK, "Error sending message from %s to %s\n%s",
550 new_msg->sender, new_msg->recipient, new_msg->msg_xml );
560 @brief Remove a given osrfRouterClass from an osrfRouter
561 @param router Pointer to the osrfRouter.
562 @param classname The name of the class to be removed.
564 A callback function, installed in the osrfHash, frees the osrfRouterClass and any
567 static void osrfRouterRemoveClass( osrfRouter* router, const char* classname ) {
568 if( router && router->classes && classname ) {
569 osrfLogInfo( OSRF_LOG_MARK, "Removing router class %s", classname );
570 osrfHashRemove( router->classes, classname );
576 Removes the given node from the class. Also, if this is that last node in the set,
577 removes the class from the router
578 @return 0 on successful removal with no class removal
579 @return 1 on successful remove with class removal
580 @return -1 error on removal
582 static int osrfRouterClassRemoveNode(
583 osrfRouter* router, const char* classname, const char* remoteId ) {
585 if(!(router && router->classes && classname && remoteId)) return 0;
587 osrfLogInfo( OSRF_LOG_MARK, "Removing router node %s", remoteId );
589 osrfRouterClass* class = osrfRouterFindClass( router, classname );
593 osrfHashRemove( class->nodes, remoteId );
594 if( osrfHashGetCount(class->nodes) == 0 ) {
595 osrfRouterRemoveClass( router, classname );
607 @brief Free a router class object.
608 @param classname Class name.
609 @param c Pointer to the osrfRouterClass, cast to a void pointer.
611 This function is designated to the osrfHash as a callback.
613 static void osrfRouterClassFree( char* classname, void* c ) {
614 if(!(classname && c)) return;
615 osrfRouterClass* rclass = (osrfRouterClass*) c;
616 client_disconnect( rclass->connection );
617 client_free( rclass->connection );
619 osrfHashIteratorReset( rclass->itr );
620 osrfRouterNode* node;
622 while( (node = osrfHashIteratorNext(rclass->itr)) )
623 osrfHashRemove( rclass->nodes, node->remoteId );
625 osrfHashIteratorFree(rclass->itr);
626 osrfHashFree(rclass->nodes);
632 @brief Free an osrfRouterNode.
633 @param remoteId Name of router (not used).
634 @param n Pointer to the osrfRouterNode to be freed, cast to a void pointer.
636 This is a callback installed in an osrfHash (the nodes member of an osrfRouterClass).
638 static void osrfRouterNodeFree( char* remoteId, void* n ) {
640 osrfRouterNode* node = (osrfRouterNode*) n;
641 free(node->remoteId);
642 message_free(node->lastMessage);
647 void osrfRouterFree( osrfRouter* router ) {
650 osrfHashFree(router->classes);
651 free(router->domain);
653 free(router->resource);
654 free(router->password);
656 osrfStringArrayFree( router->trustedClients );
657 osrfStringArrayFree( router->trustedServers );
659 client_free( router->connection );
666 Finds the class associated with the given class name in the list of classes
668 static osrfRouterClass* osrfRouterFindClass( osrfRouter* router, const char* classname ) {
669 if(!( router && router->classes && classname )) return NULL;
670 return (osrfRouterClass*) osrfHashGet( router->classes, classname );
675 Finds the router node within this class with the given remote id
677 static osrfRouterNode* osrfRouterClassFindNode( osrfRouterClass* rclass,
678 const char* remoteId ) {
679 if(!(rclass && remoteId)) return NULL;
680 return (osrfRouterNode*) osrfHashGet( rclass->nodes, remoteId );
685 Clears and populates the provided fd_set* with file descriptors
686 from the router's top level connection as well as each of the
687 router class connections
688 @return The largest file descriptor found in the filling process
691 @brief Fill an fd_set with all the sockets owned by the osrfRouter.
692 @param router Pointer to the osrfRouter whose sockets are to be used.
693 @param set Pointer to the fd_set that is to be filled.
694 @return The largest file descriptor loaded into the fd_set; or -1 upon error.
696 There's one socket for the osrfRouter as a whole, and one for each osrfRouterClass
697 that belongs to it. We load them all.
699 static int _osrfRouterFillFDSet( osrfRouter* router, fd_set* set ) {
700 if(!(router && router->classes && set)) return -1;
703 int maxfd = client_sock_fd( router->connection );
708 osrfRouterClass* class = NULL;
709 osrfHashIterator* itr = osrfNewHashIterator(router->classes);
711 while( (class = osrfHashIteratorNext(itr)) ) {
712 const char* classname = osrfHashIteratorKey(itr);
714 if( classname && (class = osrfRouterFindClass( router, classname )) ) {
715 sockid = client_sock_fd( class->connection );
717 if( osrfUtilsCheckFileDescriptor( sockid ) ) {
719 osrfLogWarning(OSRF_LOG_MARK,
720 "Removing router class '%s' because of a bad top-level file descriptor [%d]",
722 osrfRouterRemoveClass( router, classname );
725 if( sockid > maxfd ) maxfd = sockid;
731 osrfHashIteratorFree(itr);
736 handles messages that don't have a 'router_command' set. They are assumed to
737 be app request messages
739 static void osrfRouterHandleAppRequest( osrfRouter* router, transport_message* msg ) {
743 memset(arr, 0, sizeof(arr));
745 int num_msgs = osrf_message_deserialize( msg->body, arr, T );
746 osrfMessage* omsg = NULL;
749 for( i = 0; i != num_msgs; i++ ) {
751 if( !(omsg = arr[i]) ) continue;
753 switch( omsg->m_type ) {
756 osrfRouterRespondConnect( router, msg, omsg );
760 osrfRouterProcessAppRequest( router, msg, omsg );
766 osrfMessageFree( omsg );
772 static int osrfRouterRespondConnect( osrfRouter* router, transport_message* msg,
773 osrfMessage* omsg ) {
774 if(!(router && msg && omsg)) return -1;
776 osrfMessage* success = osrf_message_init( STATUS, omsg->thread_trace, omsg->protocol );
778 osrfLogDebug( OSRF_LOG_MARK, "router received a CONNECT message from %s", msg->sender );
780 osrf_message_set_status_info(
781 success, "osrfConnectStatus", "Connection Successful", OSRF_STATUS_OK );
783 char* data = osrf_message_serialize(success);
785 transport_message* return_m = message_init(
786 data, "", msg->thread, msg->sender, "" );
788 client_send_message(router->connection, return_m);
791 osrfMessageFree(success);
792 message_free(return_m);
799 static int osrfRouterProcessAppRequest( osrfRouter* router, transport_message* msg,
800 osrfMessage* omsg ) {
802 if(!(router && msg && omsg && omsg->method_name)) return -1;
804 osrfLogInfo( OSRF_LOG_MARK, "Router received app request: %s", omsg->method_name );
806 jsonObject* jresponse = NULL;
807 if(!strcmp( omsg->method_name, ROUTER_REQUEST_CLASS_LIST )) {
810 jresponse = jsonNewObjectType(JSON_ARRAY);
812 osrfStringArray* keys = osrfHashKeys( router->classes );
813 for( i = 0; i != keys->size; i++ )
814 jsonObjectPush( jresponse, jsonNewObject(osrfStringArrayGetString( keys, i )) );
815 osrfStringArrayFree(keys);
818 } else if(!strcmp( omsg->method_name, ROUTER_REQUEST_STATS_CLASS_SUMMARY )) {
820 osrfRouterClass* class;
821 osrfRouterNode* node;
824 char* classname = jsonObjectToSimpleString( jsonObjectGetIndex( omsg->_params, 0 ) );
829 class = osrfHashGet(router->classes, classname);
832 osrfHashIterator* node_itr = osrfNewHashIterator(class->nodes);
833 while( (node = osrfHashIteratorNext(node_itr)) ) {
834 count += node->count;
835 //jsonObjectSetKey( class_res, node->remoteId, jsonNewNumberObject( (double) node->count ) );
837 osrfHashIteratorFree(node_itr);
839 jresponse = jsonNewNumberObject( (double) count );
841 } else if(!strcmp( omsg->method_name, ROUTER_REQUEST_STATS_CLASS )) {
843 osrfRouterClass* class;
844 osrfRouterNode* node;
846 char* classname = jsonObjectToSimpleString( jsonObjectGetIndex( omsg->_params, 0 ) );
851 jresponse = jsonNewObjectType(JSON_HASH);
852 class = osrfHashGet(router->classes, classname);
855 osrfHashIterator* node_itr = osrfNewHashIterator(class->nodes);
856 while( (node = osrfHashIteratorNext(node_itr)) ) {
857 jsonObjectSetKey( jresponse, node->remoteId,
858 jsonNewNumberObject( (double) node->count ) );
860 osrfHashIteratorFree(node_itr);
862 } else if(!strcmp( omsg->method_name, ROUTER_REQUEST_STATS_CLASS_FULL )) {
864 osrfRouterClass* class;
865 osrfRouterNode* node;
866 jresponse = jsonNewObjectType(JSON_HASH);
868 osrfHashIterator* class_itr = osrfNewHashIterator(router->classes);
869 while( (class = osrfHashIteratorNext(class_itr)) ) {
871 jsonObject* class_res = jsonNewObjectType(JSON_HASH);
872 const char* classname = osrfHashIteratorKey(class_itr);
874 osrfHashIterator* node_itr = osrfNewHashIterator(class->nodes);
875 while( (node = osrfHashIteratorNext(node_itr)) ) {
876 jsonObjectSetKey( class_res, node->remoteId,
877 jsonNewNumberObject( (double) node->count ) );
879 osrfHashIteratorFree(node_itr);
881 jsonObjectSetKey( jresponse, classname, class_res );
884 osrfHashIteratorFree(class_itr);
886 } else if(!strcmp( omsg->method_name, ROUTER_REQUEST_STATS_NODE_FULL )) {
888 osrfRouterClass* class;
889 osrfRouterNode* node;
891 jresponse = jsonNewObjectType(JSON_HASH);
893 osrfHashIterator* class_itr = osrfNewHashIterator(router->classes);
894 while( (class = osrfHashIteratorNext(class_itr)) ) {
897 const char* classname = osrfHashIteratorKey(class_itr);
899 osrfHashIterator* node_itr = osrfNewHashIterator(class->nodes);
900 while( (node = osrfHashIteratorNext(node_itr)) ) {
901 count += node->count;
903 osrfHashIteratorFree(node_itr);
905 jsonObjectSetKey( jresponse, classname, jsonNewNumberObject( (double) count ) );
908 osrfHashIteratorFree(class_itr);
912 return osrfRouterHandleMethodNFound( router, msg, omsg );
916 osrfRouterHandleAppResponse( router, msg, omsg, jresponse );
917 jsonObjectFree(jresponse);
924 static int osrfRouterHandleMethodNFound(
925 osrfRouter* router, transport_message* msg, osrfMessage* omsg ) {
927 osrfMessage* err = osrf_message_init( STATUS, omsg->thread_trace, 1);
928 osrf_message_set_status_info( err,
929 "osrfMethodException", "Router method not found", OSRF_STATUS_NOTFOUND );
931 char* data = osrf_message_serialize(err);
933 transport_message* tresponse = message_init(
934 data, "", msg->thread, msg->sender, msg->recipient );
936 client_send_message(router->connection, tresponse );
939 osrfMessageFree( err );
940 message_free(tresponse);
945 static int osrfRouterHandleAppResponse( osrfRouter* router,
946 transport_message* msg, osrfMessage* omsg, const jsonObject* response ) {
948 if( response ) { /* send the response message */
950 osrfMessage* oresponse = osrf_message_init(
951 RESULT, omsg->thread_trace, omsg->protocol );
953 char* json = jsonObjectToJSON(response);
954 osrf_message_set_result_content( oresponse, json);
956 char* data = osrf_message_serialize(oresponse);
957 osrfLogDebug( OSRF_LOG_MARK, "Responding to client app request with data: \n%s\n", data );
959 transport_message* tresponse = message_init(
960 data, "", msg->thread, msg->sender, msg->recipient );
962 client_send_message(router->connection, tresponse );
964 osrfMessageFree(oresponse);
965 message_free(tresponse);
970 /* now send the 'request complete' message */
971 osrfMessage* status = osrf_message_init( STATUS, omsg->thread_trace, 1);
972 osrf_message_set_status_info( status, "osrfConnectStatus", "Request Complete",
973 OSRF_STATUS_COMPLETE );
975 char* statusdata = osrf_message_serialize(status);
977 transport_message* sresponse = message_init(
978 statusdata, "", msg->thread, msg->sender, msg->recipient );
979 client_send_message(router->connection, sresponse );
982 osrfMessageFree(status);
983 message_free(sresponse);