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 );
207 // Wait indefinitely for an incoming message
208 if( (selectret = select(maxfd + 1, &set, NULL, NULL, NULL)) < 0 ) {
209 if( EINTR == errno ) {
211 osrfLogWarning( OSRF_LOG_MARK, "Top level select call interrupted by signal" );
215 continue; // Irrelevant signal; ignore it
217 osrfLogWarning( OSRF_LOG_MARK, "Top level select call failed with errno %d: %s",
218 errno, strerror( errno ) );
223 /* see if there is a top level router message */
224 if( FD_ISSET(routerfd, &set) ) {
225 osrfLogDebug( OSRF_LOG_MARK, "Top router socket is active: %d", routerfd );
226 osrfRouterHandleIncoming( router );
229 /* Check each of the connected classes and see if they have data to route */
230 osrfRouterClass* class;
231 osrfHashIterator* itr = router->class_itr; // remove a layer of indirection
232 osrfHashIteratorReset( itr );
234 while( (class = osrfHashIteratorNext(itr)) ) { // for each class
236 const char* classname = osrfHashIteratorKey(itr);
240 osrfLogDebug( OSRF_LOG_MARK, "Checking %s for activity...", classname );
242 int sockfd = client_sock_fd( class->connection );
243 if(FD_ISSET( sockfd, &set )) {
244 osrfLogDebug( OSRF_LOG_MARK, "Socket is active: %d", sockfd );
245 osrfRouterClassHandleIncoming( router, classname, class );
254 @brief Handle incoming requests to the router.
255 @param router Pointer to the osrfRouter.
257 Read all available input messages from the top-level transport_client. For each one:
258 if the domain of the sender's Jabber id is on the list of approved domains, pass the
259 message to osrfRouterHandleCommand() (if there's a message) or osrfRouterHandleAppRequest()
260 (if there isn't). If the domain is @em not on the approved list, log a warning and
263 static void osrfRouterHandleIncoming( osrfRouter* router ) {
266 transport_message* msg = NULL;
268 while( (msg = client_recv( router->connection, 0 )) ) { // for each message
272 osrfLogDebug(OSRF_LOG_MARK,
273 "osrfRouterHandleIncoming(): investigating message from %s", msg->sender);
275 /* if the server is not on a trusted domain, drop the message */
276 int len = strlen(msg->sender) + 1;
278 jid_get_domain( msg->sender, domain, len - 1 );
280 if(osrfStringArrayContains( router->trustedServers, domain)) {
282 // If there's a command, obey it. Otherwise, treat
283 // the message as an app session level request.
284 if( msg->router_command && *msg->router_command )
285 osrfRouterHandleCommand( router, msg );
287 osrfRouterHandleAppRequest( router, msg );
290 osrfLogWarning( OSRF_LOG_MARK,
291 "Received message from un-trusted server domain %s", msg->sender);
299 @brief Handle all available incoming messages for a router class.
300 @param router Pointer to the osrfRouter.
301 @param classname Class name.
302 @param class Pointer to the osrfRouterClass.
304 For each message: if the sender is on a trusted domain, process the message.
306 static void osrfRouterClassHandleIncoming( osrfRouter* router, const char* classname,
307 osrfRouterClass* class ) {
308 if(!(router && class)) return;
310 transport_message* msg;
311 osrfLogDebug( OSRF_LOG_MARK, "osrfRouterClassHandleIncoming()");
313 // For each incoming message for this class:
314 while( (msg = client_recv( class->connection, 0 )) ) {
316 // Save the transaction id so that we can incorporate it
317 // into any relevant messages
318 osrfLogSetXid(msg->osrf_xid);
322 osrfLogDebug(OSRF_LOG_MARK,
323 "osrfRouterClassHandleIncoming(): investigating message from %s", msg->sender);
325 /* if the client is not from a trusted domain, drop the message */
326 int len = strlen(msg->sender) + 1;
328 jid_get_domain( msg->sender, domain, len - 1 );
330 if(osrfStringArrayContains( router->trustedClients, domain )) {
332 if( msg->is_error ) {
334 transport_message* bouncedMessage = osrfRouterClassHandleBounce(
335 router, classname, class, msg );
336 /* handle bounced message */
337 if( !bouncedMessage ) {
338 /* we have no one to send the requested message to */
343 osrfRouterClassHandleMessage( router, class, bouncedMessage );
344 message_free( bouncedMessage );
346 osrfRouterClassHandleMessage( router, class, msg );
349 osrfLogWarning( OSRF_LOG_MARK,
350 "Received client message from untrusted client domain %s", domain );
355 osrfLogClearXid(); // We're done with this transaction id
360 @brief Handle a top level router command.
361 @param router Pointer to the osrfRouter.
362 @param msg Pointer to the transport_message to be handled.
364 Currently supported commands:
365 - "register" -- Add a server class and/or a server node to our lists.
366 - "unregister" -- Remove a node from a class, and the class as well if no nodes are
369 static void osrfRouterHandleCommand( osrfRouter* router, transport_message* msg ) {
370 if(!(router && msg && msg->router_class)) return;
372 if( !strcmp( msg->router_command, ROUTER_REGISTER ) ) {
374 osrfLogInfo( OSRF_LOG_MARK, "Registering class %s", msg->router_class );
376 // Add the server class to the list, if it isn't already there
377 osrfRouterClass* class = osrfRouterFindClass( router, msg->router_class );
379 class = osrfRouterAddClass( router, msg->router_class );
381 // Add the node to the osrfRouterClass's list, if it isn't already there
382 if(class && ! osrfRouterClassFindNode( class, msg->sender ) )
383 osrfRouterClassAddNode( class, msg->sender );
385 } else if( !strcmp( msg->router_command, ROUTER_UNREGISTER ) ) {
387 if( msg->router_class && *msg->router_class ) {
388 osrfLogInfo( OSRF_LOG_MARK, "Unregistering router class %s", msg->router_class );
389 osrfRouterClassRemoveNode( router, msg->router_class, msg->sender );
396 @brief Adds an osrfRouterClass to a router, and open a connection for it.
397 @param router Pointer to the osrfRouter.
398 @param classname The name of the class this node handles.
399 @return A pointer to the new osrfRouterClass, or NULL upon error.
401 Open a Jabber session to be used for this server class. The Jabber ID incorporates the
402 class name as the resource name.
404 static osrfRouterClass* osrfRouterAddClass( osrfRouter* router, const char* classname ) {
405 if(!(router && router->classes && classname)) return NULL;
407 osrfRouterClass* class = safe_malloc(sizeof(osrfRouterClass));
408 class->nodes = osrfNewHash();
409 class->itr = osrfNewHashIterator(class->nodes);
410 osrfHashSetCallback(class->nodes, &osrfRouterNodeFree);
411 class->router = router;
413 class->connection = client_init( router->domain, router->port, NULL, 0 );
415 if(!client_connect( class->connection, router->name,
416 router->password, classname, 10, AUTH_DIGEST ) ) {
417 // Cast away the constness of classname. Though ugly, this
418 // cast is benign because osrfRouterClassFree doesn't actually
419 // write through the pointer. We can't readily change its
420 // signature because it is used for a function pointer, and
421 // we would have to change other signatures the same way.
422 osrfRouterClassFree( (char *) classname, class );
426 osrfHashSet( router->classes, class, classname );
432 @brief Add a new server node to an osrfRouterClass.
433 @param rclass Pointer to the osrfRouterClass to add the node to.
434 @param remoteId The remote login of the osrfRouterNode.
436 static void osrfRouterClassAddNode( osrfRouterClass* rclass, const char* remoteId ) {
437 if(!(rclass && rclass->nodes && remoteId)) return;
439 osrfLogInfo( OSRF_LOG_MARK, "Adding router node for remote id %s", remoteId );
441 osrfRouterNode* node = safe_malloc(sizeof(osrfRouterNode));
443 node->lastMessage = NULL;
444 node->remoteId = strdup(remoteId);
446 osrfHashSet( rclass->nodes, node, remoteId );
449 /* copy off the lastMessage, remove the offending node, send error if it's the last node
450 ? return NULL if it's the last node ?
453 /* handles case where router node is not longer reachable. copies over the
454 data from the last sent message and returns a newly crafted suitable for treating
455 as a newly inconing message. Removes the dead node and If there are no more
456 nodes to send the new message to, returns NULL.
459 @brief Handle an input message representing a Jabber error stanza.
460 @param router Pointer to the current osrfRouter.
461 @param classname Name of the class to which the error stanza was sent.
462 @param rclass Pointer to the osrfRouterClass to which the error stanza was sent.
463 @param msg Pointer to the transport_message representing the error stanza.
464 @return Pointer to a newly allocated transport_message; or NULL (see remarks).
466 The presumption is that the relevant node is dead. If another node is available for
467 the same class, then remove the dead one, create a clone of the message to be sent
468 elsewhere, and return a pointer to it. If there is no other node for the same class,
469 send a cancel message back to Jabber, and return NULL. If we can't even do that because
470 the entire class is dead, log a message to that effect and return NULL.
472 static transport_message* osrfRouterClassHandleBounce( osrfRouter* router,
473 const char* classname, osrfRouterClass* rclass, transport_message* msg ) {
475 osrfLogDebug( OSRF_LOG_MARK, "osrfRouterClassHandleBounce()");
477 osrfLogInfo( OSRF_LOG_MARK, "Received network layer error message from %s", msg->sender );
478 osrfRouterNode* node = osrfRouterClassFindNode( rclass, msg->sender );
480 osrfLogInfo( OSRF_LOG_MARK,
481 "network error occurred after we removed the class.. ignoring");
485 if( osrfHashGetCount(rclass->nodes) == 1 ) { /* the last node is dead */
487 if( node->lastMessage ) {
488 osrfLogWarning( OSRF_LOG_MARK,
489 "We lost the last node in the class, responding with error and removing...");
491 transport_message* error = message_init(
492 node->lastMessage->body, node->lastMessage->subject,
493 node->lastMessage->thread, node->lastMessage->router_from,
494 node->lastMessage->recipient );
495 message_set_osrf_xid(error, node->lastMessage->osrf_xid);
496 set_msg_error( error, "cancel", 501 );
498 /* send the error message back to the original sender */
499 client_send_message( rclass->connection, error );
500 message_free( error );
503 /* remove the dead node */
504 osrfRouterClassRemoveNode( router, classname, msg->sender);
509 transport_message* lastSent = NULL;
511 if( node->lastMessage ) {
512 osrfLogDebug( OSRF_LOG_MARK, "Cloning lastMessage so next node can send it");
513 lastSent = message_init( node->lastMessage->body,
514 node->lastMessage->subject, node->lastMessage->thread, "",
515 node->lastMessage->router_from );
516 message_set_router_info( lastSent, node->lastMessage->router_from,
517 NULL, NULL, NULL, 0 );
518 message_set_osrf_xid( lastSent, node->lastMessage->osrf_xid );
521 /* remove the dead node */
522 osrfRouterClassRemoveNode( router, classname, msg->sender);
529 Handles class level requests
530 If we get a regular message, we send it to the next node in the list of nodes
531 if we get an error, it's a bounce back from a previous attempt. We take the
532 body and thread from the last sent on the node that had the bounced message
533 and propogate them on to the new message being sent
536 static void osrfRouterClassHandleMessage(
537 osrfRouter* router, osrfRouterClass* rclass, transport_message* msg ) {
538 if(!(router && rclass && msg)) return;
540 osrfLogDebug( OSRF_LOG_MARK, "osrfRouterClassHandleMessage()");
542 osrfRouterNode* node = osrfHashIteratorNext( rclass->itr );
544 osrfHashIteratorReset(rclass->itr);
545 node = osrfHashIteratorNext( rclass->itr );
550 transport_message* new_msg= message_init( msg->body,
551 msg->subject, msg->thread, node->remoteId, msg->sender );
552 message_set_router_info( new_msg, msg->sender, NULL, NULL, NULL, 0 );
553 message_set_osrf_xid( new_msg, msg->osrf_xid );
555 osrfLogInfo( OSRF_LOG_MARK, "Routing message:\nfrom: [%s]\nto: [%s]",
556 new_msg->router_from, new_msg->recipient );
558 message_free( node->lastMessage );
559 node->lastMessage = new_msg;
561 if ( client_send_message( rclass->connection, new_msg ) == 0 )
565 message_prepare_xml(new_msg);
566 osrfLogWarning( OSRF_LOG_MARK, "Error sending message from %s to %s\n%s",
567 new_msg->sender, new_msg->recipient, new_msg->msg_xml );
575 @brief Remove a given osrfRouterClass from an osrfRouter
576 @param router Pointer to the osrfRouter.
577 @param classname The name of the class to be removed.
579 A callback function, installed in the osrfHash, frees the osrfRouterClass and any
582 static void osrfRouterRemoveClass( osrfRouter* router, const char* classname ) {
583 if( router && router->classes && classname ) {
584 osrfLogInfo( OSRF_LOG_MARK, "Removing router class %s", classname );
585 osrfHashRemove( router->classes, classname );
591 Removes the given node from the class. Also, if this is that last node in the set,
592 removes the class from the router
593 @return 0 on successful removal with no class removal
594 @return 1 on successful remove with class removal
595 @return -1 error on removal
597 static int osrfRouterClassRemoveNode(
598 osrfRouter* router, const char* classname, const char* remoteId ) {
600 if(!(router && router->classes && classname && remoteId)) return 0;
602 osrfLogInfo( OSRF_LOG_MARK, "Removing router node %s", remoteId );
604 osrfRouterClass* class = osrfRouterFindClass( router, classname );
608 osrfHashRemove( class->nodes, remoteId );
609 if( osrfHashGetCount(class->nodes) == 0 ) {
610 osrfRouterRemoveClass( router, classname );
622 @brief Free a router class object.
623 @param classname Class name.
624 @param c Pointer to the osrfRouterClass, cast to a void pointer.
626 This function is designated to the osrfHash as a callback.
628 static void osrfRouterClassFree( char* classname, void* c ) {
629 if(!(classname && c)) return;
630 osrfRouterClass* rclass = (osrfRouterClass*) c;
631 client_disconnect( rclass->connection );
632 client_free( rclass->connection );
634 osrfHashIteratorReset( rclass->itr );
635 osrfRouterNode* node;
637 while( (node = osrfHashIteratorNext(rclass->itr)) )
638 osrfHashRemove( rclass->nodes, node->remoteId );
640 osrfHashIteratorFree(rclass->itr);
641 osrfHashFree(rclass->nodes);
647 @brief Free an osrfRouterNode.
648 @param remoteId Name of router (not used).
649 @param n Pointer to the osrfRouterNode to be freed, cast to a void pointer.
651 This is a callback installed in an osrfHash (the nodes member of an osrfRouterClass).
653 static void osrfRouterNodeFree( char* remoteId, void* n ) {
655 osrfRouterNode* node = (osrfRouterNode*) n;
656 free(node->remoteId);
657 message_free(node->lastMessage);
662 void osrfRouterFree( osrfRouter* router ) {
665 osrfHashIteratorFree( router->class_itr);
666 osrfHashFree(router->classes);
667 free(router->domain);
669 free(router->resource);
670 free(router->password);
672 osrfStringArrayFree( router->trustedClients );
673 osrfStringArrayFree( router->trustedServers );
675 client_free( router->connection );
682 Finds the class associated with the given class name in the list of classes
684 static osrfRouterClass* osrfRouterFindClass( osrfRouter* router, const char* classname ) {
685 if(!( router && router->classes && classname )) return NULL;
686 return (osrfRouterClass*) osrfHashGet( router->classes, classname );
691 Finds the router node within this class with the given remote id
693 static osrfRouterNode* osrfRouterClassFindNode( osrfRouterClass* rclass,
694 const char* remoteId ) {
695 if(!(rclass && remoteId)) return NULL;
696 return (osrfRouterNode*) osrfHashGet( rclass->nodes, remoteId );
701 Clears and populates the provided fd_set* with file descriptors
702 from the router's top level connection as well as each of the
703 router class connections
704 @return The largest file descriptor found in the filling process
707 @brief Fill an fd_set with all the sockets owned by the osrfRouter.
708 @param router Pointer to the osrfRouter whose sockets are to be used.
709 @param set Pointer to the fd_set that is to be filled.
710 @return The largest file descriptor loaded into the fd_set; or -1 upon error.
712 There's one socket for the osrfRouter as a whole, and one for each osrfRouterClass
713 that belongs to it. We load them all.
715 static int _osrfRouterFillFDSet( osrfRouter* router, fd_set* set ) {
716 if(!(router && router->classes && set)) return -1;
719 int maxfd = client_sock_fd( router->connection );
724 osrfRouterClass* class = NULL;
725 osrfHashIterator* itr = router->class_itr;
726 osrfHashIteratorReset( itr );
728 while( (class = osrfHashIteratorNext(itr)) ) {
729 const char* classname = osrfHashIteratorKey(itr);
731 if( classname && (class = osrfRouterFindClass( router, classname )) ) {
732 sockid = client_sock_fd( class->connection );
734 if( osrfUtilsCheckFileDescriptor( sockid ) ) {
736 osrfLogWarning(OSRF_LOG_MARK,
737 "Removing router class '%s' because of a bad top-level file descriptor [%d]",
739 osrfRouterRemoveClass( router, classname );
742 if( sockid > maxfd ) maxfd = sockid;
752 handles messages that don't have a 'router_command' set. They are assumed to
753 be app request messages
755 static void osrfRouterHandleAppRequest( osrfRouter* router, transport_message* msg ) {
759 memset(arr, 0, sizeof(arr));
761 int num_msgs = osrf_message_deserialize( msg->body, arr, T );
762 osrfMessage* omsg = NULL;
765 for( i = 0; i != num_msgs; i++ ) {
767 if( !(omsg = arr[i]) ) continue;
769 switch( omsg->m_type ) {
772 osrfRouterRespondConnect( router, msg, omsg );
776 osrfRouterProcessAppRequest( router, msg, omsg );
782 osrfMessageFree( omsg );
788 static int osrfRouterRespondConnect( osrfRouter* router, transport_message* msg,
789 osrfMessage* omsg ) {
790 if(!(router && msg && omsg)) return -1;
792 osrfMessage* success = osrf_message_init( STATUS, omsg->thread_trace, omsg->protocol );
794 osrfLogDebug( OSRF_LOG_MARK, "router received a CONNECT message from %s", msg->sender );
796 osrf_message_set_status_info(
797 success, "osrfConnectStatus", "Connection Successful", OSRF_STATUS_OK );
799 char* data = osrf_message_serialize(success);
801 transport_message* return_m = message_init(
802 data, "", msg->thread, msg->sender, "" );
804 client_send_message(router->connection, return_m);
807 osrfMessageFree(success);
808 message_free(return_m);
815 static int osrfRouterProcessAppRequest( osrfRouter* router, transport_message* msg,
816 osrfMessage* omsg ) {
818 if(!(router && msg && omsg && omsg->method_name)) return -1;
820 osrfLogInfo( OSRF_LOG_MARK, "Router received app request: %s", omsg->method_name );
822 jsonObject* jresponse = NULL;
823 if(!strcmp( omsg->method_name, ROUTER_REQUEST_CLASS_LIST )) {
826 jresponse = jsonNewObjectType(JSON_ARRAY);
828 osrfStringArray* keys = osrfHashKeys( router->classes );
829 for( i = 0; i != keys->size; i++ )
830 jsonObjectPush( jresponse, jsonNewObject(osrfStringArrayGetString( keys, i )) );
831 osrfStringArrayFree(keys);
834 } else if(!strcmp( omsg->method_name, ROUTER_REQUEST_STATS_CLASS_SUMMARY )) {
836 osrfRouterClass* class;
837 osrfRouterNode* node;
840 char* classname = jsonObjectToSimpleString( jsonObjectGetIndex( omsg->_params, 0 ) );
845 class = osrfHashGet(router->classes, classname);
848 osrfHashIterator* node_itr = osrfNewHashIterator(class->nodes);
849 while( (node = osrfHashIteratorNext(node_itr)) ) {
850 count += node->count;
851 //jsonObjectSetKey( class_res, node->remoteId, jsonNewNumberObject( (double) node->count ) );
853 osrfHashIteratorFree(node_itr);
855 jresponse = jsonNewNumberObject( (double) count );
857 } else if(!strcmp( omsg->method_name, ROUTER_REQUEST_STATS_CLASS )) {
859 osrfRouterClass* class;
860 osrfRouterNode* node;
862 char* classname = jsonObjectToSimpleString( jsonObjectGetIndex( omsg->_params, 0 ) );
867 jresponse = jsonNewObjectType(JSON_HASH);
868 class = osrfHashGet(router->classes, classname);
871 osrfHashIterator* node_itr = osrfNewHashIterator(class->nodes);
872 while( (node = osrfHashIteratorNext(node_itr)) ) {
873 jsonObjectSetKey( jresponse, node->remoteId,
874 jsonNewNumberObject( (double) node->count ) );
876 osrfHashIteratorFree(node_itr);
878 } else if(!strcmp( omsg->method_name, ROUTER_REQUEST_STATS_CLASS_FULL )) {
880 osrfRouterClass* class;
881 osrfRouterNode* node;
882 jresponse = jsonNewObjectType(JSON_HASH);
884 osrfHashIterator* class_itr = osrfNewHashIterator(router->classes);
885 while( (class = osrfHashIteratorNext(class_itr)) ) {
887 jsonObject* class_res = jsonNewObjectType(JSON_HASH);
888 const char* classname = osrfHashIteratorKey(class_itr);
890 osrfHashIterator* node_itr = osrfNewHashIterator(class->nodes);
891 while( (node = osrfHashIteratorNext(node_itr)) ) {
892 jsonObjectSetKey( class_res, node->remoteId,
893 jsonNewNumberObject( (double) node->count ) );
895 osrfHashIteratorFree(node_itr);
897 jsonObjectSetKey( jresponse, classname, class_res );
900 osrfHashIteratorFree(class_itr);
902 } else if(!strcmp( omsg->method_name, ROUTER_REQUEST_STATS_NODE_FULL )) {
904 osrfRouterClass* class;
905 osrfRouterNode* node;
907 jresponse = jsonNewObjectType(JSON_HASH);
909 osrfHashIterator* class_itr = osrfNewHashIterator(router->classes);
910 while( (class = osrfHashIteratorNext(class_itr)) ) {
913 const char* classname = osrfHashIteratorKey(class_itr);
915 osrfHashIterator* node_itr = osrfNewHashIterator(class->nodes);
916 while( (node = osrfHashIteratorNext(node_itr)) ) {
917 count += node->count;
919 osrfHashIteratorFree(node_itr);
921 jsonObjectSetKey( jresponse, classname, jsonNewNumberObject( (double) count ) );
924 osrfHashIteratorFree(class_itr);
928 return osrfRouterHandleMethodNFound( router, msg, omsg );
932 osrfRouterHandleAppResponse( router, msg, omsg, jresponse );
933 jsonObjectFree(jresponse);
940 static int osrfRouterHandleMethodNFound(
941 osrfRouter* router, transport_message* msg, osrfMessage* omsg ) {
943 osrfMessage* err = osrf_message_init( STATUS, omsg->thread_trace, 1);
944 osrf_message_set_status_info( err,
945 "osrfMethodException", "Router method not found", OSRF_STATUS_NOTFOUND );
947 char* data = osrf_message_serialize(err);
949 transport_message* tresponse = message_init(
950 data, "", msg->thread, msg->sender, msg->recipient );
952 client_send_message(router->connection, tresponse );
955 osrfMessageFree( err );
956 message_free(tresponse);
961 static int osrfRouterHandleAppResponse( osrfRouter* router,
962 transport_message* msg, osrfMessage* omsg, const jsonObject* response ) {
964 if( response ) { /* send the response message */
966 osrfMessage* oresponse = osrf_message_init(
967 RESULT, omsg->thread_trace, omsg->protocol );
969 char* json = jsonObjectToJSON(response);
970 osrf_message_set_result_content( oresponse, json);
972 char* data = osrf_message_serialize(oresponse);
973 osrfLogDebug( OSRF_LOG_MARK, "Responding to client app request with data: \n%s\n", data );
975 transport_message* tresponse = message_init(
976 data, "", msg->thread, msg->sender, msg->recipient );
978 client_send_message(router->connection, tresponse );
980 osrfMessageFree(oresponse);
981 message_free(tresponse);
986 /* now send the 'request complete' message */
987 osrfMessage* status = osrf_message_init( STATUS, omsg->thread_trace, 1);
988 osrf_message_set_status_info( status, "osrfConnectStatus", "Request Complete",
989 OSRF_STATUS_COMPLETE );
991 char* statusdata = osrf_message_serialize(status);
993 transport_message* sresponse = message_init(
994 statusdata, "", msg->thread, msg->sender, msg->recipient );
995 client_send_message(router->connection, sresponse );
998 osrfMessageFree(status);
999 message_free(sresponse);