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 int 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 int 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 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 */
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 sender 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 incoming requests to a router class.
306 @param router Pointer to the osrfRouter.
307 @param classname Class name.
308 @param class Pointer to an osrfRouterClass.
310 Make sure sender is a trusted client.
312 static int osrfRouterClassHandleIncoming( osrfRouter* router, const char* classname,
313 osrfRouterClass* class ) {
314 if(!(router && class)) return -1;
316 transport_message* msg;
317 osrfLogDebug( OSRF_LOG_MARK, "osrfRouterClassHandleIncoming()");
319 while( (msg = client_recv( class->connection, 0 )) ) {
321 osrfLogSetXid(msg->osrf_xid);
325 osrfLogDebug(OSRF_LOG_MARK,
326 "osrfRouterClassHandleIncoming(): investigating message from %s", msg->sender);
328 /* if the client is not from a trusted domain, drop the message */
329 int len = strlen(msg->sender) + 1;
331 memset(domain, 0, sizeof(domain));
332 jid_get_domain( msg->sender, domain, len - 1 );
334 if(osrfStringArrayContains( router->trustedClients, domain)) {
336 transport_message* bouncedMessage = NULL;
337 if( msg->is_error ) {
339 /* handle bounced message */
340 if( !(bouncedMessage = osrfRouterClassHandleBounce( router, classname,
342 return -1; /* we have no one to send the requested message to */
345 msg = bouncedMessage;
347 osrfRouterClassHandleMessage( router, class, msg );
350 osrfLogWarning( OSRF_LOG_MARK,
351 "Received client message from untrusted client domain %s", domain );
363 @brief Handle a top level router command.
364 @param router Pointer to the osrfRouter.
365 @param msg Pointer to the transport_message to be handled.
367 Currently supported commands:
368 - "register" -- Add a server class and/or a server node to our lists.
369 - "unregister" -- Remove a server class (and any associated nodes) from our list.
371 static void osrfRouterHandleCommand( osrfRouter* router, transport_message* msg ) {
372 if(!(router && msg && msg->router_class)) return;
374 if( !strcmp( msg->router_command, ROUTER_REGISTER ) ) {
376 osrfLogInfo( OSRF_LOG_MARK, "Registering class %s", msg->router_class );
378 // Add the server class to the list, if it isn't already there
379 osrfRouterClass* class = osrfRouterFindClass( router, msg->router_class );
381 class = osrfRouterAddClass( router, msg->router_class );
383 // Add the node to the osrfRouterClass's list, if it isn't already there
384 if(class && ! osrfRouterClassFindNode( class, msg->sender ) )
385 osrfRouterClassAddNode( class, msg->sender );
387 } else if( !strcmp( msg->router_command, ROUTER_UNREGISTER ) ) {
389 if( msg->router_class && *msg->router_class ) {
390 osrfLogInfo( OSRF_LOG_MARK, "Unregistering router class %s", msg->router_class );
391 osrfRouterClassRemoveNode( router, msg->router_class, msg->sender );
398 @brief Adds an osrfRouterClass to a router, and open a connection for it.
399 @param router Pointer to the osrfRouter.
400 @param classname The name of the class this node handles.
401 @return A pointer to the new osrfRouterClass, or NULL upon error.
403 Open a Jabber session to be used for this server class. The Jabber ID incorporates the
404 class name as the resource name.
406 static osrfRouterClass* osrfRouterAddClass( osrfRouter* router, const char* classname ) {
407 if(!(router && router->classes && classname)) return NULL;
409 osrfRouterClass* class = safe_malloc(sizeof(osrfRouterClass));
410 class->nodes = osrfNewHash();
411 class->itr = osrfNewHashIterator(class->nodes);
412 osrfHashSetCallback(class->nodes, &osrfRouterNodeFree);
413 class->router = router;
415 class->connection = client_init( router->domain, router->port, NULL, 0 );
417 if(!client_connect( class->connection, router->name,
418 router->password, classname, 10, AUTH_DIGEST ) ) {
419 // Cast away the constness of classname. Though ugly, this
420 // cast is benign because osrfRouterClassFree doesn't actually
421 // write through the pointer. We can't readily change its
422 // signature because it is used for a function pointer, and
423 // we would have to change other signatures the same way.
424 osrfRouterClassFree( (char *) classname, class );
428 osrfHashSet( router->classes, class, classname );
434 @brief Add a new server node to an osrfRouterClass.
435 @param rclass Pointer to the osrfRouterClass to add the node to.
436 @param remoteId The remote login of the osrfRouterNode.
438 static void osrfRouterClassAddNode( osrfRouterClass* rclass, const char* remoteId ) {
439 if(!(rclass && rclass->nodes && remoteId)) return;
441 osrfLogInfo( OSRF_LOG_MARK, "Adding router node for remote id %s", remoteId );
443 osrfRouterNode* node = safe_malloc(sizeof(osrfRouterNode));
445 node->lastMessage = NULL;
446 node->remoteId = strdup(remoteId);
448 osrfHashSet( rclass->nodes, node, remoteId );
451 /* copy off the lastMessage, remove the offending node, send error if it's tht last node
452 ? return NULL if it's the last node ?
455 /* handles case where router node is not longer reachable. copies over the
456 data from the last sent message and returns a newly crafted suitable for treating
457 as a newly inconing message. Removes the dead node and If there are no more
458 nodes to send the new message to, returns NULL.
460 static transport_message* osrfRouterClassHandleBounce( osrfRouter* router,
461 const char* classname, osrfRouterClass* rclass, transport_message* msg ) {
463 osrfLogDebug( OSRF_LOG_MARK, "osrfRouterClassHandleBounce()");
465 osrfLogInfo( OSRF_LOG_MARK, "Received network layer error message from %s", msg->sender );
466 osrfRouterNode* node = osrfRouterClassFindNode( rclass, msg->sender );
467 transport_message* lastSent = NULL;
469 if( node && osrfHashGetCount(rclass->nodes) == 1 ) { /* the last node is dead */
471 if( node->lastMessage ) {
472 osrfLogWarning( OSRF_LOG_MARK,
473 "We lost the last node in the class, responding with error and removing...");
475 transport_message* error = message_init(
476 node->lastMessage->body, node->lastMessage->subject,
477 node->lastMessage->thread, node->lastMessage->router_from,
478 node->lastMessage->recipient );
479 message_set_osrf_xid(error, node->lastMessage->osrf_xid);
480 set_msg_error( error, "cancel", 501 );
482 /* send the error message back to the original sender */
483 client_send_message( rclass->connection, error );
484 message_free( error );
492 if( node->lastMessage ) {
493 osrfLogDebug( OSRF_LOG_MARK, "Cloning lastMessage so next node can send it");
494 lastSent = message_init( node->lastMessage->body,
495 node->lastMessage->subject, node->lastMessage->thread, "", node->lastMessage->router_from );
496 message_set_router_info( lastSent, node->lastMessage->router_from, NULL, NULL, NULL, 0 );
497 message_set_osrf_xid( lastSent, node->lastMessage->osrf_xid );
501 osrfLogInfo(OSRF_LOG_MARK, "network error occurred after we removed the class.. ignoring");
506 /* remove the dead node */
507 osrfRouterClassRemoveNode( router, classname, msg->sender);
513 Handles class level requests
514 If we get a regular message, we send it to the next node in the list of nodes
515 if we get an error, it's a bounce back from a previous attempt. We take the
516 body and thread from the last sent on the node that had the bounced message
517 and propogate them on to the new message being sent
520 static int osrfRouterClassHandleMessage(
521 osrfRouter* router, osrfRouterClass* rclass, transport_message* msg ) {
522 if(!(router && rclass && msg)) return -1;
524 osrfLogDebug( OSRF_LOG_MARK, "osrfRouterClassHandleMessage()");
526 osrfRouterNode* node = osrfHashIteratorNext( rclass->itr );
528 osrfHashIteratorReset(rclass->itr);
529 node = osrfHashIteratorNext( rclass->itr );
534 transport_message* new_msg= message_init( msg->body,
535 msg->subject, msg->thread, node->remoteId, msg->sender );
536 message_set_router_info( new_msg, msg->sender, NULL, NULL, NULL, 0 );
537 message_set_osrf_xid( new_msg, msg->osrf_xid );
539 osrfLogInfo( OSRF_LOG_MARK, "Routing message:\nfrom: [%s]\nto: [%s]",
540 new_msg->router_from, new_msg->recipient );
542 message_free( node->lastMessage );
543 node->lastMessage = new_msg;
545 if ( client_send_message( rclass->connection, new_msg ) == 0 )
549 message_prepare_xml(new_msg);
550 osrfLogWarning( OSRF_LOG_MARK, "Error sending message from %s to %s\n%s",
551 new_msg->sender, new_msg->recipient, new_msg->msg_xml );
561 @brief Remove a given osrfRouterClass from an osrfRouter
562 @param router Pointer to the osrfRouter.
563 @param classname The name of the class to be removed.
565 A callback function, installed in the osrfHash, frees the osrfRouterClass and any
568 static void osrfRouterRemoveClass( osrfRouter* router, const char* classname ) {
569 if( router && router->classes && classname ) {
570 osrfLogInfo( OSRF_LOG_MARK, "Removing router class %s", classname );
571 osrfHashRemove( router->classes, classname );
577 Removes the given node from the class. Also, if this is that last node in the set,
578 removes the class from the router
579 @return 0 on successful removal with no class removal
580 @return 1 on successful remove with class removal
581 @return -1 error on removal
583 static int osrfRouterClassRemoveNode(
584 osrfRouter* router, const char* classname, const char* remoteId ) {
586 if(!(router && router->classes && classname && remoteId)) return 0;
588 osrfLogInfo( OSRF_LOG_MARK, "Removing router node %s", remoteId );
590 osrfRouterClass* class = osrfRouterFindClass( router, classname );
594 osrfHashRemove( class->nodes, remoteId );
595 if( osrfHashGetCount(class->nodes) == 0 ) {
596 osrfRouterRemoveClass( router, classname );
608 @brief Free a router class object.
609 @param classname Class name.
610 @param c Pointer to the osrfRouterClass, cast to a void pointer.
612 This function is designated to the osrfHash as a callback.
614 static void osrfRouterClassFree( char* classname, void* c ) {
615 if(!(classname && c)) return;
616 osrfRouterClass* rclass = (osrfRouterClass*) c;
617 client_disconnect( rclass->connection );
618 client_free( rclass->connection );
620 osrfHashIteratorReset( rclass->itr );
621 osrfRouterNode* node;
623 while( (node = osrfHashIteratorNext(rclass->itr)) )
624 osrfHashRemove( rclass->nodes, node->remoteId );
626 osrfHashIteratorFree(rclass->itr);
627 osrfHashFree(rclass->nodes);
633 @brief Free an osrfRouterNode.
634 @param remoteId Name of router (not used).
635 @param n Pointer to the osrfRouterNode to be freed, cast to a void pointer.
637 This is a callback installed in an osrfHash (the nodes member of an osrfRouterClass).
639 static void osrfRouterNodeFree( char* remoteId, void* n ) {
641 osrfRouterNode* node = (osrfRouterNode*) n;
642 free(node->remoteId);
643 message_free(node->lastMessage);
648 void osrfRouterFree( osrfRouter* router ) {
651 osrfHashIteratorFree( router->class_itr);
652 osrfHashFree(router->classes);
653 free(router->domain);
655 free(router->resource);
656 free(router->password);
658 osrfStringArrayFree( router->trustedClients );
659 osrfStringArrayFree( router->trustedServers );
661 client_free( router->connection );
668 Finds the class associated with the given class name in the list of classes
670 static osrfRouterClass* osrfRouterFindClass( osrfRouter* router, const char* classname ) {
671 if(!( router && router->classes && classname )) return NULL;
672 return (osrfRouterClass*) osrfHashGet( router->classes, classname );
677 Finds the router node within this class with the given remote id
679 static osrfRouterNode* osrfRouterClassFindNode( osrfRouterClass* rclass,
680 const char* remoteId ) {
681 if(!(rclass && remoteId)) return NULL;
682 return (osrfRouterNode*) osrfHashGet( rclass->nodes, remoteId );
687 Clears and populates the provided fd_set* with file descriptors
688 from the router's top level connection as well as each of the
689 router class connections
690 @return The largest file descriptor found in the filling process
693 @brief Fill an fd_set with all the sockets owned by the osrfRouter.
694 @param router Pointer to the osrfRouter whose sockets are to be used.
695 @param set Pointer to the fd_set that is to be filled.
696 @return The largest file descriptor loaded into the fd_set; or -1 upon error.
698 There's one socket for the osrfRouter as a whole, and one for each osrfRouterClass
699 that belongs to it. We load them all.
701 static int _osrfRouterFillFDSet( osrfRouter* router, fd_set* set ) {
702 if(!(router && router->classes && set)) return -1;
705 int maxfd = client_sock_fd( router->connection );
710 osrfRouterClass* class = NULL;
711 osrfHashIterator* itr = osrfNewHashIterator(router->classes);
713 while( (class = osrfHashIteratorNext(itr)) ) {
714 const char* classname = osrfHashIteratorKey(itr);
716 if( classname && (class = osrfRouterFindClass( router, classname )) ) {
717 sockid = client_sock_fd( class->connection );
719 if( osrfUtilsCheckFileDescriptor( sockid ) ) {
721 osrfLogWarning(OSRF_LOG_MARK,
722 "Removing router class '%s' because of a bad top-level file descriptor [%d]",
724 osrfRouterRemoveClass( router, classname );
727 if( sockid > maxfd ) maxfd = sockid;
733 osrfHashIteratorFree(itr);
738 handles messages that don't have a 'router_command' set. They are assumed to
739 be app request messages
741 static void osrfRouterHandleAppRequest( osrfRouter* router, transport_message* msg ) {
745 memset(arr, 0, sizeof(arr));
747 int num_msgs = osrf_message_deserialize( msg->body, arr, T );
748 osrfMessage* omsg = NULL;
751 for( i = 0; i != num_msgs; i++ ) {
753 if( !(omsg = arr[i]) ) continue;
755 switch( omsg->m_type ) {
758 osrfRouterRespondConnect( router, msg, omsg );
762 osrfRouterProcessAppRequest( router, msg, omsg );
768 osrfMessageFree( omsg );
774 static int osrfRouterRespondConnect( osrfRouter* router, transport_message* msg,
775 osrfMessage* omsg ) {
776 if(!(router && msg && omsg)) return -1;
778 osrfMessage* success = osrf_message_init( STATUS, omsg->thread_trace, omsg->protocol );
780 osrfLogDebug( OSRF_LOG_MARK, "router received a CONNECT message from %s", msg->sender );
782 osrf_message_set_status_info(
783 success, "osrfConnectStatus", "Connection Successful", OSRF_STATUS_OK );
785 char* data = osrf_message_serialize(success);
787 transport_message* return_m = message_init(
788 data, "", msg->thread, msg->sender, "" );
790 client_send_message(router->connection, return_m);
793 osrfMessageFree(success);
794 message_free(return_m);
801 static int osrfRouterProcessAppRequest( osrfRouter* router, transport_message* msg,
802 osrfMessage* omsg ) {
804 if(!(router && msg && omsg && omsg->method_name)) return -1;
806 osrfLogInfo( OSRF_LOG_MARK, "Router received app request: %s", omsg->method_name );
808 jsonObject* jresponse = NULL;
809 if(!strcmp( omsg->method_name, ROUTER_REQUEST_CLASS_LIST )) {
812 jresponse = jsonNewObjectType(JSON_ARRAY);
814 osrfStringArray* keys = osrfHashKeys( router->classes );
815 for( i = 0; i != keys->size; i++ )
816 jsonObjectPush( jresponse, jsonNewObject(osrfStringArrayGetString( keys, i )) );
817 osrfStringArrayFree(keys);
820 } else if(!strcmp( omsg->method_name, ROUTER_REQUEST_STATS_CLASS_SUMMARY )) {
822 osrfRouterClass* class;
823 osrfRouterNode* node;
826 char* classname = jsonObjectToSimpleString( jsonObjectGetIndex( omsg->_params, 0 ) );
831 class = osrfHashGet(router->classes, classname);
834 osrfHashIterator* node_itr = osrfNewHashIterator(class->nodes);
835 while( (node = osrfHashIteratorNext(node_itr)) ) {
836 count += node->count;
837 //jsonObjectSetKey( class_res, node->remoteId, jsonNewNumberObject( (double) node->count ) );
839 osrfHashIteratorFree(node_itr);
841 jresponse = jsonNewNumberObject( (double) count );
843 } else if(!strcmp( omsg->method_name, ROUTER_REQUEST_STATS_CLASS )) {
845 osrfRouterClass* class;
846 osrfRouterNode* node;
848 char* classname = jsonObjectToSimpleString( jsonObjectGetIndex( omsg->_params, 0 ) );
853 jresponse = jsonNewObjectType(JSON_HASH);
854 class = osrfHashGet(router->classes, classname);
857 osrfHashIterator* node_itr = osrfNewHashIterator(class->nodes);
858 while( (node = osrfHashIteratorNext(node_itr)) ) {
859 jsonObjectSetKey( jresponse, node->remoteId,
860 jsonNewNumberObject( (double) node->count ) );
862 osrfHashIteratorFree(node_itr);
864 } else if(!strcmp( omsg->method_name, ROUTER_REQUEST_STATS_CLASS_FULL )) {
866 osrfRouterClass* class;
867 osrfRouterNode* node;
868 jresponse = jsonNewObjectType(JSON_HASH);
870 osrfHashIterator* class_itr = osrfNewHashIterator(router->classes);
871 while( (class = osrfHashIteratorNext(class_itr)) ) {
873 jsonObject* class_res = jsonNewObjectType(JSON_HASH);
874 const char* classname = osrfHashIteratorKey(class_itr);
876 osrfHashIterator* node_itr = osrfNewHashIterator(class->nodes);
877 while( (node = osrfHashIteratorNext(node_itr)) ) {
878 jsonObjectSetKey( class_res, node->remoteId,
879 jsonNewNumberObject( (double) node->count ) );
881 osrfHashIteratorFree(node_itr);
883 jsonObjectSetKey( jresponse, classname, class_res );
886 osrfHashIteratorFree(class_itr);
888 } else if(!strcmp( omsg->method_name, ROUTER_REQUEST_STATS_NODE_FULL )) {
890 osrfRouterClass* class;
891 osrfRouterNode* node;
893 jresponse = jsonNewObjectType(JSON_HASH);
895 osrfHashIterator* class_itr = osrfNewHashIterator(router->classes);
896 while( (class = osrfHashIteratorNext(class_itr)) ) {
899 const char* classname = osrfHashIteratorKey(class_itr);
901 osrfHashIterator* node_itr = osrfNewHashIterator(class->nodes);
902 while( (node = osrfHashIteratorNext(node_itr)) ) {
903 count += node->count;
905 osrfHashIteratorFree(node_itr);
907 jsonObjectSetKey( jresponse, classname, jsonNewNumberObject( (double) count ) );
910 osrfHashIteratorFree(class_itr);
914 return osrfRouterHandleMethodNFound( router, msg, omsg );
918 osrfRouterHandleAppResponse( router, msg, omsg, jresponse );
919 jsonObjectFree(jresponse);
926 static int osrfRouterHandleMethodNFound(
927 osrfRouter* router, transport_message* msg, osrfMessage* omsg ) {
929 osrfMessage* err = osrf_message_init( STATUS, omsg->thread_trace, 1);
930 osrf_message_set_status_info( err,
931 "osrfMethodException", "Router method not found", OSRF_STATUS_NOTFOUND );
933 char* data = osrf_message_serialize(err);
935 transport_message* tresponse = message_init(
936 data, "", msg->thread, msg->sender, msg->recipient );
938 client_send_message(router->connection, tresponse );
941 osrfMessageFree( err );
942 message_free(tresponse);
947 static int osrfRouterHandleAppResponse( osrfRouter* router,
948 transport_message* msg, osrfMessage* omsg, const jsonObject* response ) {
950 if( response ) { /* send the response message */
952 osrfMessage* oresponse = osrf_message_init(
953 RESULT, omsg->thread_trace, omsg->protocol );
955 char* json = jsonObjectToJSON(response);
956 osrf_message_set_result_content( oresponse, json);
958 char* data = osrf_message_serialize(oresponse);
959 osrfLogDebug( OSRF_LOG_MARK, "Responding to client app request with data: \n%s\n", data );
961 transport_message* tresponse = message_init(
962 data, "", msg->thread, msg->sender, msg->recipient );
964 client_send_message(router->connection, tresponse );
966 osrfMessageFree(oresponse);
967 message_free(tresponse);
972 /* now send the 'request complete' message */
973 osrfMessage* status = osrf_message_init( STATUS, omsg->thread_trace, 1);
974 osrf_message_set_status_info( status, "osrfConnectStatus", "Request Complete",
975 OSRF_STATUS_COMPLETE );
977 char* statusdata = osrf_message_serialize(status);
979 transport_message* sresponse = message_init(
980 statusdata, "", msg->thread, msg->sender, msg->recipient );
981 client_send_message(router->connection, sresponse );
984 osrfMessageFree(status);
985 message_free(sresponse);