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 osrfHashIterator* class_itr; /**< For traversing the list of classes */
29 char* domain; /**< Domain name of Jabber server. */
30 char* name; /**< Router's username for the Jabber logon. */
31 char* resource; /**< Router's resource name for the Jabber logon. */
32 char* password; /**< Router's password for the Jabber logon. */
33 int port; /**< Jabber's port number. */
34 sig_atomic_t stop; /**< To be set by signal handler to interrupt main loop */
36 /** Array of client domains that we allow to send requests through us. */
37 osrfStringArray* trustedClients;
38 /** Array of server domains that we allow to register, etc. with us. */
39 osrfStringArray* trustedServers;
41 transport_client* connection;
45 @brief Maintains a set of server nodes belonging to the same class.
47 struct _osrfRouterClassStruct {
48 osrfRouter* router; /**< The osrfRouter that owns this osrfRouterClass. */
49 osrfHashIterator* itr; /**< Iterator for set of osrfRouterNodes. */
51 @brief Hash store of server nodes.
53 The key of each entry is a node name, and the associated data is an osrfRouterNode.
54 We install a callback for freeing the entries.
57 /** The transport_client used for communicating with this server. */
58 transport_client* connection;
60 typedef struct _osrfRouterClassStruct osrfRouterClass;
63 @brief Represents a link to a single server's inbound connection.
65 struct _osrfRouterNodeStruct {
66 char* remoteId; /**< Send message to me via this login. */
67 int count; /**< How many message have been sent to this node. */
68 transport_message* lastMessage;
70 typedef struct _osrfRouterNodeStruct osrfRouterNode;
72 static osrfRouterClass* osrfRouterAddClass( osrfRouter* router, const char* classname );
73 static void osrfRouterClassAddNode( osrfRouterClass* rclass, const char* remoteId );
74 static void osrfRouterHandleCommand( osrfRouter* router, transport_message* msg );
75 static void osrfRouterClassHandleMessage( osrfRouter* router,
76 osrfRouterClass* rclass, transport_message* msg );
77 static void osrfRouterRemoveClass( osrfRouter* router, const char* classname );
78 static int osrfRouterClassRemoveNode( osrfRouter* router, const char* classname,
79 const char* remoteId );
80 static void osrfRouterClassFree( char* classname, void* rclass );
81 static void osrfRouterNodeFree( char* remoteId, void* node );
82 static osrfRouterClass* osrfRouterFindClass( osrfRouter* router, const char* classname );
83 static osrfRouterNode* osrfRouterClassFindNode( osrfRouterClass* rclass,
84 const char* remoteId );
85 static int _osrfRouterFillFDSet( osrfRouter* router, fd_set* set );
86 static void osrfRouterHandleIncoming( osrfRouter* router );
87 static void osrfRouterClassHandleIncoming( osrfRouter* router,
88 const char* classname, osrfRouterClass* class );
89 static transport_message* osrfRouterClassHandleBounce( osrfRouter* router,
90 const char* classname, osrfRouterClass* rclass, transport_message* msg );
91 static void osrfRouterHandleAppRequest( osrfRouter* router, transport_message* msg );
92 static int osrfRouterRespondConnect( osrfRouter* router, transport_message* msg,
94 static int osrfRouterProcessAppRequest( osrfRouter* router, transport_message* msg,
96 static int osrfRouterHandleAppResponse( osrfRouter* router,
97 transport_message* msg, osrfMessage* omsg, const jsonObject* response );
98 static int osrfRouterHandleMethodNFound( osrfRouter* router, transport_message* msg,
101 #define ROUTER_REGISTER "register"
102 #define ROUTER_UNREGISTER "unregister"
104 #define ROUTER_REQUEST_CLASS_LIST "opensrf.router.info.class.list"
105 #define ROUTER_REQUEST_STATS_NODE_FULL "opensrf.router.info.stats.class.node.all"
106 #define ROUTER_REQUEST_STATS_CLASS_FULL "opensrf.router.info.stats.class.all"
107 #define ROUTER_REQUEST_STATS_CLASS "opensrf.router.info.stats.class"
108 #define ROUTER_REQUEST_STATS_CLASS_SUMMARY "opensrf.router.info.stats.class.summary"
111 @brief Stop the otherwise infinite main loop of the router.
112 @param router Pointer to the osrfRouter to be stopped.
114 To be called by a signal handler.
116 void router_stop( osrfRouter* router )
123 @brief Allocate and initialize a new osrfRouter.
124 @param domain Domain name of Jabber server
125 @param name Router's username for the Jabber logon.
126 @param resource Router's resource name for the Jabber logon.
127 @param password Router's password for the Jabber logon.
128 @param port Jabber's port number.
129 @param trustedClients Array of client domains that we allow to send requests through us.
130 @param trustedServers Array of server domains that we allow to register, etc. with us.
131 @return Pointer to the newly allocated osrfRouter.
133 Don't connect to Jabber yet. We'll do that later, upon a call to osrfRouterConnect().
135 The calling code is responsible for freeing the osrfRouter by calling osrfRouterFree().
137 osrfRouter* osrfNewRouter(
138 const char* domain, const char* name,
139 const char* resource, const char* password, int port,
140 osrfStringArray* trustedClients, osrfStringArray* trustedServers ) {
142 if(!( domain && name && resource && password && port && trustedClients && trustedServers ))
145 osrfRouter* router = safe_malloc(sizeof(osrfRouter));
146 router->domain = strdup(domain);
147 router->name = strdup(name);
148 router->password = strdup(password);
149 router->resource = strdup(resource);
153 router->trustedClients = trustedClients;
154 router->trustedServers = trustedServers;
157 router->classes = osrfNewHash();
158 osrfHashSetCallback(router->classes, &osrfRouterClassFree);
159 router->class_itr = osrfNewHashIterator( router->classes );
161 // Prepare to connect to Jabber, as a non-component, over TCP (not UNIX domain).
162 router->connection = client_init( domain, port, NULL, 0 );
168 @brief Connect to Jabber.
169 @param router Pointer to the osrfRouter to connect to Jabber
170 @return 0 if successful, or -1 on error.
172 Allow up to 10 seconds for the logon to succeed.
174 We connect over TCP (not over a UNIX domain), as a non-component.
176 int osrfRouterConnect( osrfRouter* router ) {
177 if(!router) return -1;
178 int ret = client_connect( router->connection, router->name,
179 router->password, router->resource, 10, AUTH_DIGEST );
180 if( ret == 0 ) return -1;
185 @brief Enter endless loop to receive and respond to input.
186 @param router Pointer to the osrfRouter that's looping.
189 On each iteration: wait for incoming messages to arrive on any of our sockets -- i.e.
190 either the top level socket belong to the router or any of the lower level sockets
191 belonging to the classes. React to the incoming activity as needed.
193 We don't exit the loop until we receive a signal to stop, or until we encounter an error.
195 void osrfRouterRun( osrfRouter* router ) {
196 if(!(router && router->classes)) return;
198 int routerfd = client_sock_fd( router->connection );
201 // Loop until a signal handler sets router->stop
202 while( ! router->stop ) {
205 int maxfd = _osrfRouterFillFDSet( router, &set );
208 // Wait indefinitely for an incoming message
209 if( (selectret = select(maxfd + 1, &set, NULL, NULL, NULL)) < 0 ) {
210 if( EINTR == errno ) {
212 osrfLogWarning( OSRF_LOG_MARK, "Top level select call interrupted by signal" );
216 continue; // Irrelevant signal; ignore it
218 osrfLogWarning( OSRF_LOG_MARK, "Top level select call failed with errno %d: %s",
219 errno, strerror( errno ) );
224 /* see if there is a top level router message */
225 if( FD_ISSET(routerfd, &set) ) {
226 osrfLogDebug( OSRF_LOG_MARK, "Top router socket is active: %d", routerfd );
228 osrfRouterHandleIncoming( router );
231 /* now check each of the connected classes and see if they have data to route */
232 while( numhandled < selectret ) {
234 osrfRouterClass* class;
235 osrfHashIterator* itr = router->class_itr; // remove a layer of indirection
236 osrfHashIteratorReset( itr );
238 while( (class = osrfHashIteratorNext(itr)) ) {
240 const char* classname = osrfHashIteratorKey(itr);
244 osrfLogDebug( OSRF_LOG_MARK, "Checking %s for activity...", classname );
246 int sockfd = client_sock_fd( class->connection );
247 if(FD_ISSET( sockfd, &set )) {
248 osrfLogDebug( OSRF_LOG_MARK, "Socket is active: %d", sockfd );
250 osrfRouterClassHandleIncoming( router, classname, class );
260 @brief Handle incoming requests to the router.
261 @param router Pointer to the osrfRouter.
263 Read all available input messages from the top-level transport_client. For each one:
264 if the domain of the sender's Jabber id is on the list of approved domains, pass the
265 message to osrfRouterHandleCommand() (if there's a message) or osrfRouterHandleAppRequest()
266 (if there isn't). If the domain is @em not on the approved list, log a warning and
269 static void osrfRouterHandleIncoming( osrfRouter* router ) {
272 transport_message* msg = NULL;
274 while( (msg = client_recv( router->connection, 0 )) ) { // for each message
278 osrfLogDebug(OSRF_LOG_MARK,
279 "osrfRouterHandleIncoming(): investigating message from %s", msg->sender);
281 /* if the server is not on a trusted domain, drop the message */
282 int len = strlen(msg->sender) + 1;
284 jid_get_domain( msg->sender, domain, len - 1 );
286 if(osrfStringArrayContains( router->trustedServers, domain)) {
288 // If there's a command, obey it. Otherwise, treat
289 // the message as an app session level request.
290 if( msg->router_command && *msg->router_command )
291 osrfRouterHandleCommand( router, msg );
293 osrfRouterHandleAppRequest( router, msg );
296 osrfLogWarning( OSRF_LOG_MARK,
297 "Received message from un-trusted server domain %s", msg->sender);
305 @brief Handle all available incoming messages for a router class.
306 @param router Pointer to the osrfRouter.
307 @param classname Class name.
308 @param class Pointer to the osrfRouterClass.
310 For each message: if the sender is on a trusted domain, process the message.
312 static void osrfRouterClassHandleIncoming( osrfRouter* router, const char* classname,
313 osrfRouterClass* class ) {
314 if(!(router && class)) return;
316 transport_message* msg;
317 osrfLogDebug( OSRF_LOG_MARK, "osrfRouterClassHandleIncoming()");
319 // For each incoming message for this class:
320 while( (msg = client_recv( class->connection, 0 )) ) {
322 // Save the transaction id so that we can incorporate it
323 // into any relevant messages
324 osrfLogSetXid(msg->osrf_xid);
328 osrfLogDebug(OSRF_LOG_MARK,
329 "osrfRouterClassHandleIncoming(): investigating message from %s", msg->sender);
331 /* if the client is not from a trusted domain, drop the message */
332 int len = strlen(msg->sender) + 1;
334 jid_get_domain( msg->sender, domain, len - 1 );
336 if(osrfStringArrayContains( router->trustedClients, domain )) {
338 if( msg->is_error ) {
340 transport_message* bouncedMessage = osrfRouterClassHandleBounce(
341 router, classname, class, msg );
342 /* handle bounced message */
343 if( !bouncedMessage ) {
344 /* we have no one to send the requested message to */
349 osrfRouterClassHandleMessage( router, class, bouncedMessage );
350 message_free( bouncedMessage );
352 osrfRouterClassHandleMessage( router, class, msg );
355 osrfLogWarning( OSRF_LOG_MARK,
356 "Received client message from untrusted client domain %s", domain );
361 osrfLogClearXid(); // We're done with this transaction id
366 @brief Handle a top level router command.
367 @param router Pointer to the osrfRouter.
368 @param msg Pointer to the transport_message to be handled.
370 Currently supported commands:
371 - "register" -- Add a server class and/or a server node to our lists.
372 - "unregister" -- Remove a node from a class, and the class as well if no nodes are
375 static void osrfRouterHandleCommand( osrfRouter* router, transport_message* msg ) {
376 if(!(router && msg && msg->router_class)) return;
378 if( !strcmp( msg->router_command, ROUTER_REGISTER ) ) {
380 osrfLogInfo( OSRF_LOG_MARK, "Registering class %s", msg->router_class );
382 // Add the server class to the list, if it isn't already there
383 osrfRouterClass* class = osrfRouterFindClass( router, msg->router_class );
385 class = osrfRouterAddClass( router, msg->router_class );
387 // Add the node to the osrfRouterClass's list, if it isn't already there
388 if(class && ! osrfRouterClassFindNode( class, msg->sender ) )
389 osrfRouterClassAddNode( class, msg->sender );
391 } else if( !strcmp( msg->router_command, ROUTER_UNREGISTER ) ) {
393 if( msg->router_class && *msg->router_class ) {
394 osrfLogInfo( OSRF_LOG_MARK, "Unregistering router class %s", msg->router_class );
395 osrfRouterClassRemoveNode( router, msg->router_class, msg->sender );
402 @brief Adds an osrfRouterClass to a router, and open a connection for it.
403 @param router Pointer to the osrfRouter.
404 @param classname The name of the class this node handles.
405 @return A pointer to the new osrfRouterClass, or NULL upon error.
407 Open a Jabber session to be used for this server class. The Jabber ID incorporates the
408 class name as the resource name.
410 static osrfRouterClass* osrfRouterAddClass( osrfRouter* router, const char* classname ) {
411 if(!(router && router->classes && classname)) return NULL;
413 osrfRouterClass* class = safe_malloc(sizeof(osrfRouterClass));
414 class->nodes = osrfNewHash();
415 class->itr = osrfNewHashIterator(class->nodes);
416 osrfHashSetCallback(class->nodes, &osrfRouterNodeFree);
417 class->router = router;
419 class->connection = client_init( router->domain, router->port, NULL, 0 );
421 if(!client_connect( class->connection, router->name,
422 router->password, classname, 10, AUTH_DIGEST ) ) {
423 // Cast away the constness of classname. Though ugly, this
424 // cast is benign because osrfRouterClassFree doesn't actually
425 // write through the pointer. We can't readily change its
426 // signature because it is used for a function pointer, and
427 // we would have to change other signatures the same way.
428 osrfRouterClassFree( (char *) classname, class );
432 osrfHashSet( router->classes, class, classname );
438 @brief Add a new server node to an osrfRouterClass.
439 @param rclass Pointer to the osrfRouterClass to add the node to.
440 @param remoteId The remote login of the osrfRouterNode.
442 static void osrfRouterClassAddNode( osrfRouterClass* rclass, const char* remoteId ) {
443 if(!(rclass && rclass->nodes && remoteId)) return;
445 osrfLogInfo( OSRF_LOG_MARK, "Adding router node for remote id %s", remoteId );
447 osrfRouterNode* node = safe_malloc(sizeof(osrfRouterNode));
449 node->lastMessage = NULL;
450 node->remoteId = strdup(remoteId);
452 osrfHashSet( rclass->nodes, node, remoteId );
455 /* copy off the lastMessage, remove the offending node, send error if it's the last node
456 ? return NULL if it's the last node ?
459 /* handles case where router node is not longer reachable. copies over the
460 data from the last sent message and returns a newly crafted suitable for treating
461 as a newly inconing message. Removes the dead node and If there are no more
462 nodes to send the new message to, returns NULL.
465 @brief Handle an input message representing a Jabber error stanza.
466 @param router Pointer to the current osrfRouter.
467 @param classname Name of the class to which the error stanza was sent.
468 @param rclass Pointer to the osrfRouterClass to which the error stanza was sent.
469 @param msg Pointer to the transport_message representing the error stanza.
470 @return Pointer to a newly allocated transport_message; or NULL (see remarks).
472 The presumption is that the relevant node is dead. If another node is available for
473 the same class, then remove the dead one, create a clone of the message to be sent
474 elsewhere, and return a pointer to it. If there is no other node for the same class,
475 send a cancel message back to Jabber, and return NULL. If we can't even do that because
476 the entire class is dead, log a message to that effect and return NULL.
478 static transport_message* osrfRouterClassHandleBounce( osrfRouter* router,
479 const char* classname, osrfRouterClass* rclass, transport_message* msg ) {
481 osrfLogDebug( OSRF_LOG_MARK, "osrfRouterClassHandleBounce()");
483 osrfLogInfo( OSRF_LOG_MARK, "Received network layer error message from %s", msg->sender );
484 osrfRouterNode* node = osrfRouterClassFindNode( rclass, msg->sender );
486 osrfLogInfo( OSRF_LOG_MARK,
487 "network error occurred after we removed the class.. ignoring");
491 if( osrfHashGetCount(rclass->nodes) == 1 ) { /* the last node is dead */
493 if( node->lastMessage ) {
494 osrfLogWarning( OSRF_LOG_MARK,
495 "We lost the last node in the class, responding with error and removing...");
497 transport_message* error = message_init(
498 node->lastMessage->body, node->lastMessage->subject,
499 node->lastMessage->thread, node->lastMessage->router_from,
500 node->lastMessage->recipient );
501 message_set_osrf_xid(error, node->lastMessage->osrf_xid);
502 set_msg_error( error, "cancel", 501 );
504 /* send the error message back to the original sender */
505 client_send_message( rclass->connection, error );
506 message_free( error );
513 transport_message* lastSent = NULL;
515 if( node->lastMessage ) {
516 osrfLogDebug( OSRF_LOG_MARK, "Cloning lastMessage so next node can send it");
517 lastSent = message_init( node->lastMessage->body,
518 node->lastMessage->subject, node->lastMessage->thread, "",
519 node->lastMessage->router_from );
520 message_set_router_info( lastSent, node->lastMessage->router_from,
521 NULL, NULL, NULL, 0 );
522 message_set_osrf_xid( lastSent, node->lastMessage->osrf_xid );
525 /* remove the dead node */
526 osrfRouterClassRemoveNode( router, classname, msg->sender);
533 Handles class level requests
534 If we get a regular message, we send it to the next node in the list of nodes
535 if we get an error, it's a bounce back from a previous attempt. We take the
536 body and thread from the last sent on the node that had the bounced message
537 and propogate them on to the new message being sent
540 static void osrfRouterClassHandleMessage(
541 osrfRouter* router, osrfRouterClass* rclass, transport_message* msg ) {
542 if(!(router && rclass && msg)) return;
544 osrfLogDebug( OSRF_LOG_MARK, "osrfRouterClassHandleMessage()");
546 osrfRouterNode* node = osrfHashIteratorNext( rclass->itr );
548 osrfHashIteratorReset(rclass->itr);
549 node = osrfHashIteratorNext( rclass->itr );
554 transport_message* new_msg= message_init( msg->body,
555 msg->subject, msg->thread, node->remoteId, msg->sender );
556 message_set_router_info( new_msg, msg->sender, NULL, NULL, NULL, 0 );
557 message_set_osrf_xid( new_msg, msg->osrf_xid );
559 osrfLogInfo( OSRF_LOG_MARK, "Routing message:\nfrom: [%s]\nto: [%s]",
560 new_msg->router_from, new_msg->recipient );
562 message_free( node->lastMessage );
563 node->lastMessage = new_msg;
565 if ( client_send_message( rclass->connection, new_msg ) == 0 )
569 message_prepare_xml(new_msg);
570 osrfLogWarning( OSRF_LOG_MARK, "Error sending message from %s to %s\n%s",
571 new_msg->sender, new_msg->recipient, new_msg->msg_xml );
579 @brief Remove a given osrfRouterClass from an osrfRouter
580 @param router Pointer to the osrfRouter.
581 @param classname The name of the class to be removed.
583 A callback function, installed in the osrfHash, frees the osrfRouterClass and any
586 static void osrfRouterRemoveClass( osrfRouter* router, const char* classname ) {
587 if( router && router->classes && classname ) {
588 osrfLogInfo( OSRF_LOG_MARK, "Removing router class %s", classname );
589 osrfHashRemove( router->classes, classname );
595 Removes the given node from the class. Also, if this is that last node in the set,
596 removes the class from the router
597 @return 0 on successful removal with no class removal
598 @return 1 on successful remove with class removal
599 @return -1 error on removal
601 static int osrfRouterClassRemoveNode(
602 osrfRouter* router, const char* classname, const char* remoteId ) {
604 if(!(router && router->classes && classname && remoteId)) return 0;
606 osrfLogInfo( OSRF_LOG_MARK, "Removing router node %s", remoteId );
608 osrfRouterClass* class = osrfRouterFindClass( router, classname );
612 osrfHashRemove( class->nodes, remoteId );
613 if( osrfHashGetCount(class->nodes) == 0 ) {
614 osrfRouterRemoveClass( router, classname );
626 @brief Free a router class object.
627 @param classname Class name.
628 @param c Pointer to the osrfRouterClass, cast to a void pointer.
630 This function is designated to the osrfHash as a callback.
632 static void osrfRouterClassFree( char* classname, void* c ) {
633 if(!(classname && c)) return;
634 osrfRouterClass* rclass = (osrfRouterClass*) c;
635 client_disconnect( rclass->connection );
636 client_free( rclass->connection );
638 osrfHashIteratorReset( rclass->itr );
639 osrfRouterNode* node;
641 while( (node = osrfHashIteratorNext(rclass->itr)) )
642 osrfHashRemove( rclass->nodes, node->remoteId );
644 osrfHashIteratorFree(rclass->itr);
645 osrfHashFree(rclass->nodes);
651 @brief Free an osrfRouterNode.
652 @param remoteId Name of router (not used).
653 @param n Pointer to the osrfRouterNode to be freed, cast to a void pointer.
655 This is a callback installed in an osrfHash (the nodes member of an osrfRouterClass).
657 static void osrfRouterNodeFree( char* remoteId, void* n ) {
659 osrfRouterNode* node = (osrfRouterNode*) n;
660 free(node->remoteId);
661 message_free(node->lastMessage);
666 void osrfRouterFree( osrfRouter* router ) {
669 osrfHashIteratorFree( router->class_itr);
670 osrfHashFree(router->classes);
671 free(router->domain);
673 free(router->resource);
674 free(router->password);
676 osrfStringArrayFree( router->trustedClients );
677 osrfStringArrayFree( router->trustedServers );
679 client_free( router->connection );
686 Finds the class associated with the given class name in the list of classes
688 static osrfRouterClass* osrfRouterFindClass( osrfRouter* router, const char* classname ) {
689 if(!( router && router->classes && classname )) return NULL;
690 return (osrfRouterClass*) osrfHashGet( router->classes, classname );
695 Finds the router node within this class with the given remote id
697 static osrfRouterNode* osrfRouterClassFindNode( osrfRouterClass* rclass,
698 const char* remoteId ) {
699 if(!(rclass && remoteId)) return NULL;
700 return (osrfRouterNode*) osrfHashGet( rclass->nodes, remoteId );
705 Clears and populates the provided fd_set* with file descriptors
706 from the router's top level connection as well as each of the
707 router class connections
708 @return The largest file descriptor found in the filling process
711 @brief Fill an fd_set with all the sockets owned by the osrfRouter.
712 @param router Pointer to the osrfRouter whose sockets are to be used.
713 @param set Pointer to the fd_set that is to be filled.
714 @return The largest file descriptor loaded into the fd_set; or -1 upon error.
716 There's one socket for the osrfRouter as a whole, and one for each osrfRouterClass
717 that belongs to it. We load them all.
719 static int _osrfRouterFillFDSet( osrfRouter* router, fd_set* set ) {
720 if(!(router && router->classes && set)) return -1;
723 int maxfd = client_sock_fd( router->connection );
728 osrfRouterClass* class = NULL;
729 osrfHashIterator* itr = router->class_itr;
730 osrfHashIteratorReset( itr );
732 while( (class = osrfHashIteratorNext(itr)) ) {
733 const char* classname = osrfHashIteratorKey(itr);
735 if( classname && (class = osrfRouterFindClass( router, classname )) ) {
736 sockid = client_sock_fd( class->connection );
738 if( osrfUtilsCheckFileDescriptor( sockid ) ) {
740 osrfLogWarning(OSRF_LOG_MARK,
741 "Removing router class '%s' because of a bad top-level file descriptor [%d]",
743 osrfRouterRemoveClass( router, classname );
746 if( sockid > maxfd ) maxfd = sockid;
756 handles messages that don't have a 'router_command' set. They are assumed to
757 be app request messages
759 static void osrfRouterHandleAppRequest( osrfRouter* router, transport_message* msg ) {
763 memset(arr, 0, sizeof(arr));
765 int num_msgs = osrf_message_deserialize( msg->body, arr, T );
766 osrfMessage* omsg = NULL;
769 for( i = 0; i != num_msgs; i++ ) {
771 if( !(omsg = arr[i]) ) continue;
773 switch( omsg->m_type ) {
776 osrfRouterRespondConnect( router, msg, omsg );
780 osrfRouterProcessAppRequest( router, msg, omsg );
786 osrfMessageFree( omsg );
792 static int osrfRouterRespondConnect( osrfRouter* router, transport_message* msg,
793 osrfMessage* omsg ) {
794 if(!(router && msg && omsg)) return -1;
796 osrfMessage* success = osrf_message_init( STATUS, omsg->thread_trace, omsg->protocol );
798 osrfLogDebug( OSRF_LOG_MARK, "router received a CONNECT message from %s", msg->sender );
800 osrf_message_set_status_info(
801 success, "osrfConnectStatus", "Connection Successful", OSRF_STATUS_OK );
803 char* data = osrf_message_serialize(success);
805 transport_message* return_m = message_init(
806 data, "", msg->thread, msg->sender, "" );
808 client_send_message(router->connection, return_m);
811 osrfMessageFree(success);
812 message_free(return_m);
819 static int osrfRouterProcessAppRequest( osrfRouter* router, transport_message* msg,
820 osrfMessage* omsg ) {
822 if(!(router && msg && omsg && omsg->method_name)) return -1;
824 osrfLogInfo( OSRF_LOG_MARK, "Router received app request: %s", omsg->method_name );
826 jsonObject* jresponse = NULL;
827 if(!strcmp( omsg->method_name, ROUTER_REQUEST_CLASS_LIST )) {
830 jresponse = jsonNewObjectType(JSON_ARRAY);
832 osrfStringArray* keys = osrfHashKeys( router->classes );
833 for( i = 0; i != keys->size; i++ )
834 jsonObjectPush( jresponse, jsonNewObject(osrfStringArrayGetString( keys, i )) );
835 osrfStringArrayFree(keys);
838 } else if(!strcmp( omsg->method_name, ROUTER_REQUEST_STATS_CLASS_SUMMARY )) {
840 osrfRouterClass* class;
841 osrfRouterNode* node;
844 char* classname = jsonObjectToSimpleString( jsonObjectGetIndex( omsg->_params, 0 ) );
849 class = osrfHashGet(router->classes, classname);
852 osrfHashIterator* node_itr = osrfNewHashIterator(class->nodes);
853 while( (node = osrfHashIteratorNext(node_itr)) ) {
854 count += node->count;
855 //jsonObjectSetKey( class_res, node->remoteId, jsonNewNumberObject( (double) node->count ) );
857 osrfHashIteratorFree(node_itr);
859 jresponse = jsonNewNumberObject( (double) count );
861 } else if(!strcmp( omsg->method_name, ROUTER_REQUEST_STATS_CLASS )) {
863 osrfRouterClass* class;
864 osrfRouterNode* node;
866 char* classname = jsonObjectToSimpleString( jsonObjectGetIndex( omsg->_params, 0 ) );
871 jresponse = jsonNewObjectType(JSON_HASH);
872 class = osrfHashGet(router->classes, classname);
875 osrfHashIterator* node_itr = osrfNewHashIterator(class->nodes);
876 while( (node = osrfHashIteratorNext(node_itr)) ) {
877 jsonObjectSetKey( jresponse, node->remoteId,
878 jsonNewNumberObject( (double) node->count ) );
880 osrfHashIteratorFree(node_itr);
882 } else if(!strcmp( omsg->method_name, ROUTER_REQUEST_STATS_CLASS_FULL )) {
884 osrfRouterClass* class;
885 osrfRouterNode* node;
886 jresponse = jsonNewObjectType(JSON_HASH);
888 osrfHashIterator* class_itr = osrfNewHashIterator(router->classes);
889 while( (class = osrfHashIteratorNext(class_itr)) ) {
891 jsonObject* class_res = jsonNewObjectType(JSON_HASH);
892 const char* classname = osrfHashIteratorKey(class_itr);
894 osrfHashIterator* node_itr = osrfNewHashIterator(class->nodes);
895 while( (node = osrfHashIteratorNext(node_itr)) ) {
896 jsonObjectSetKey( class_res, node->remoteId,
897 jsonNewNumberObject( (double) node->count ) );
899 osrfHashIteratorFree(node_itr);
901 jsonObjectSetKey( jresponse, classname, class_res );
904 osrfHashIteratorFree(class_itr);
906 } else if(!strcmp( omsg->method_name, ROUTER_REQUEST_STATS_NODE_FULL )) {
908 osrfRouterClass* class;
909 osrfRouterNode* node;
911 jresponse = jsonNewObjectType(JSON_HASH);
913 osrfHashIterator* class_itr = osrfNewHashIterator(router->classes);
914 while( (class = osrfHashIteratorNext(class_itr)) ) {
917 const char* classname = osrfHashIteratorKey(class_itr);
919 osrfHashIterator* node_itr = osrfNewHashIterator(class->nodes);
920 while( (node = osrfHashIteratorNext(node_itr)) ) {
921 count += node->count;
923 osrfHashIteratorFree(node_itr);
925 jsonObjectSetKey( jresponse, classname, jsonNewNumberObject( (double) count ) );
928 osrfHashIteratorFree(class_itr);
932 return osrfRouterHandleMethodNFound( router, msg, omsg );
936 osrfRouterHandleAppResponse( router, msg, omsg, jresponse );
937 jsonObjectFree(jresponse);
944 static int osrfRouterHandleMethodNFound(
945 osrfRouter* router, transport_message* msg, osrfMessage* omsg ) {
947 osrfMessage* err = osrf_message_init( STATUS, omsg->thread_trace, 1);
948 osrf_message_set_status_info( err,
949 "osrfMethodException", "Router method not found", OSRF_STATUS_NOTFOUND );
951 char* data = osrf_message_serialize(err);
953 transport_message* tresponse = message_init(
954 data, "", msg->thread, msg->sender, msg->recipient );
956 client_send_message(router->connection, tresponse );
959 osrfMessageFree( err );
960 message_free(tresponse);
965 static int osrfRouterHandleAppResponse( osrfRouter* router,
966 transport_message* msg, osrfMessage* omsg, const jsonObject* response ) {
968 if( response ) { /* send the response message */
970 osrfMessage* oresponse = osrf_message_init(
971 RESULT, omsg->thread_trace, omsg->protocol );
973 char* json = jsonObjectToJSON(response);
974 osrf_message_set_result_content( oresponse, json);
976 char* data = osrf_message_serialize(oresponse);
977 osrfLogDebug( OSRF_LOG_MARK, "Responding to client app request with data: \n%s\n", data );
979 transport_message* tresponse = message_init(
980 data, "", msg->thread, msg->sender, msg->recipient );
982 client_send_message(router->connection, tresponse );
984 osrfMessageFree(oresponse);
985 message_free(tresponse);
990 /* now send the 'request complete' message */
991 osrfMessage* status = osrf_message_init( STATUS, omsg->thread_trace, 1);
992 osrf_message_set_status_info( status, "osrfConnectStatus", "Request Complete",
993 OSRF_STATUS_COMPLETE );
995 char* statusdata = osrf_message_serialize(status);
997 transport_message* sresponse = message_init(
998 statusdata, "", msg->thread, msg->sender, msg->recipient );
999 client_send_message(router->connection, sresponse );
1002 osrfMessageFree(status);
1003 message_free(sresponse);