PageRenderTime 49ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 1ms

/src/router/osrf_router.c

https://gitlab.com/evergreen-bjwebb/opensrf-debian
C | 1093 lines | 571 code | 201 blank | 321 comment | 116 complexity | 46df8a0d05a18cbd4d0b6b4a49984107 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause
  1. #include <sys/select.h>
  2. #include <signal.h>
  3. #include "opensrf/utils.h"
  4. #include "opensrf/log.h"
  5. #include "opensrf/osrf_list.h"
  6. #include "opensrf/string_array.h"
  7. #include "opensrf/osrf_hash.h"
  8. #include "osrf_router.h"
  9. #include "opensrf/transport_client.h"
  10. #include "opensrf/transport_message.h"
  11. #include "opensrf/osrf_message.h"
  12. /**
  13. @file osrf_router.c
  14. @brief Implementation of osrfRouter.
  15. The router opens multiple Jabber sessions for the same username and domain, one for
  16. each server class. The Jabber IDs for these sessions are distinguished by the use of
  17. the class names as Jabber resource names.
  18. For each server class there may be multiple server nodes. Each node corresponds to a
  19. listener process for a service.
  20. */
  21. /**
  22. @brief Collection of server classes, with connection parameters for Jabber.
  23. */
  24. struct osrfRouterStruct {
  25. /**
  26. @brief Hash store of server classes.
  27. For each entry, the key is the class name, and the corresponding datum is an
  28. osrfRouterClass.
  29. */
  30. osrfHash* classes;
  31. osrfHashIterator* class_itr; /**< For traversing the list of classes. */
  32. char* domain; /**< Domain name of Jabber server. */
  33. char* name; /**< Router's username for the Jabber logon. */
  34. char* resource; /**< Router's resource name for the Jabber logon. */
  35. char* password; /**< Router's password for the Jabber logon. */
  36. int port; /**< Jabber's port number. */
  37. volatile sig_atomic_t stop; /**< To be set by signal handler to interrupt main loop. */
  38. /** Array of client domains that we allow to send requests through us. */
  39. osrfStringArray* trustedClients;
  40. /** Array of server domains that we allow to register, etc. with us. */
  41. osrfStringArray* trustedServers;
  42. /** List of osrfMessages to be returned from osrfMessageDeserialize() */
  43. osrfList* message_list;
  44. transport_client* connection;
  45. };
  46. /**
  47. @brief Maintains a set of server nodes belonging to the same class.
  48. */
  49. struct _osrfRouterClassStruct {
  50. osrfRouter* router; /**< The osrfRouter that owns this osrfRouterClass. */
  51. osrfHashIterator* itr; /**< Iterator for set of osrfRouterNodes. */
  52. /**
  53. @brief Hash store of server nodes.
  54. The key of each entry is a node name, and the associated data is an osrfRouterNode.
  55. We install a callback for freeing the entries.
  56. */
  57. osrfHash* nodes;
  58. /** The transport_client used for communicating with this server. */
  59. transport_client* connection;
  60. };
  61. typedef struct _osrfRouterClassStruct osrfRouterClass;
  62. /**
  63. @brief Represents a link to a single server's inbound connection.
  64. */
  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;
  69. };
  70. 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, const transport_message* msg );
  74. static void osrfRouterClassHandleMessage( osrfRouter* router,
  75. osrfRouterClass* rclass, const transport_message* msg );
  76. static void osrfRouterRemoveClass( osrfRouter* router, const char* classname );
  77. static void 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 void osrfRouterClassHandleIncoming( osrfRouter* router,
  87. const char* classname, osrfRouterClass* class );
  88. static transport_message* osrfRouterClassHandleBounce( osrfRouter* router,
  89. const char* classname, osrfRouterClass* rclass, const transport_message* msg );
  90. static void osrfRouterHandleAppRequest( osrfRouter* router, const transport_message* msg );
  91. static void osrfRouterRespondConnect( osrfRouter* router, const transport_message* msg,
  92. const osrfMessage* omsg );
  93. static void osrfRouterProcessAppRequest( osrfRouter* router, const transport_message* msg,
  94. const osrfMessage* omsg );
  95. static void osrfRouterSendAppResponse( osrfRouter* router, const transport_message* msg,
  96. const osrfMessage* omsg, const jsonObject* response );
  97. static void osrfRouterHandleMethodNFound( osrfRouter* router,
  98. const transport_message* msg, const osrfMessage* omsg );
  99. #define ROUTER_REGISTER "register"
  100. #define ROUTER_UNREGISTER "unregister"
  101. #define ROUTER_REQUEST_CLASS_LIST "opensrf.router.info.class.list"
  102. #define ROUTER_REQUEST_STATS_NODE_FULL "opensrf.router.info.stats.class.node.all"
  103. #define ROUTER_REQUEST_STATS_CLASS_FULL "opensrf.router.info.stats.class.all"
  104. #define ROUTER_REQUEST_STATS_CLASS "opensrf.router.info.stats.class"
  105. #define ROUTER_REQUEST_STATS_CLASS_SUMMARY "opensrf.router.info.stats.class.summary"
  106. /**
  107. @brief Stop the otherwise endless main loop of the router.
  108. @param router Pointer to the osrfRouter to be stopped.
  109. To be called by a signal handler. We don't stop the loop immediately; we just set
  110. a switch that the main loop checks on each iteration.
  111. */
  112. void router_stop( osrfRouter* router )
  113. {
  114. if( router )
  115. router->stop = 1;
  116. }
  117. /**
  118. @brief Allocate and initialize a new osrfRouter.
  119. @param domain Domain name of Jabber server.
  120. @param name Router's username for the Jabber logon.
  121. @param resource Router's resource name for the Jabber logon.
  122. @param password Router's password for the Jabber logon.
  123. @param port Jabber's port number.
  124. @param trustedClients Array of client domains that we allow to send requests through us.
  125. @param trustedServers Array of server domains that we allow to register, etc. with us.
  126. @return Pointer to the newly allocated osrfRouter, or NULL upon error.
  127. Don't connect to Jabber yet. We'll do that later, upon a call to osrfRouterConnect().
  128. The calling code is responsible for freeing the osrfRouter by calling osrfRouterFree().
  129. */
  130. osrfRouter* osrfNewRouter(
  131. const char* domain, const char* name,
  132. const char* resource, const char* password, int port,
  133. osrfStringArray* trustedClients, osrfStringArray* trustedServers ) {
  134. if(!( domain && name && resource && password && port && trustedClients && trustedServers ))
  135. return NULL;
  136. osrfRouter* router = safe_malloc(sizeof(osrfRouter));
  137. router->domain = strdup(domain);
  138. router->name = strdup(name);
  139. router->password = strdup(password);
  140. router->resource = strdup(resource);
  141. router->port = port;
  142. router->stop = 0;
  143. router->trustedClients = trustedClients;
  144. router->trustedServers = trustedServers;
  145. router->classes = osrfNewHash();
  146. osrfHashSetCallback(router->classes, &osrfRouterClassFree);
  147. router->class_itr = osrfNewHashIterator( router->classes );
  148. router->message_list = NULL; // We'll allocate one later
  149. // Prepare to connect to Jabber, as a non-component, over TCP (not UNIX domain).
  150. router->connection = client_init( domain, port, NULL, 0 );
  151. return router;
  152. }
  153. /**
  154. @brief Connect to Jabber.
  155. @param router Pointer to the osrfRouter to connect to Jabber.
  156. @return 0 if successful, or -1 on error.
  157. Allow up to 10 seconds for the logon to succeed.
  158. We connect over TCP (not over a UNIX domain), as a non-component.
  159. */
  160. int osrfRouterConnect( osrfRouter* router ) {
  161. if(!router) return -1;
  162. int ret = client_connect( router->connection, router->name,
  163. router->password, router->resource, 10, AUTH_DIGEST );
  164. if( ret == 0 ) return -1;
  165. return 0;
  166. }
  167. /**
  168. @brief Enter endless loop to receive and respond to input.
  169. @param router Pointer to the osrfRouter that's looping.
  170. On each iteration: wait for incoming messages to arrive on any of our sockets -- i.e.
  171. either the top level socket belonging to the router or any of the lower level sockets
  172. belonging to the classes. React to the incoming activity as needed.
  173. We don't exit the loop until we receive a signal to stop, or until we encounter an error.
  174. */
  175. void osrfRouterRun( osrfRouter* router ) {
  176. if(!(router && router->classes)) return;
  177. int routerfd = client_sock_fd( router->connection );
  178. int selectret = 0;
  179. // Loop until a signal handler sets router->stop
  180. while( ! router->stop ) {
  181. fd_set set;
  182. int maxfd = _osrfRouterFillFDSet( router, &set );
  183. // Wait indefinitely for an incoming message
  184. if( (selectret = select(maxfd + 1, &set, NULL, NULL, NULL)) < 0 ) {
  185. if( EINTR == errno ) {
  186. if( router->stop ) {
  187. osrfLogWarning( OSRF_LOG_MARK, "Top level select call interrupted by signal" );
  188. break;
  189. }
  190. else
  191. continue; // Irrelevant signal; ignore it
  192. } else {
  193. osrfLogWarning( OSRF_LOG_MARK, "Top level select call failed with errno %d: %s",
  194. errno, strerror( errno ) );
  195. break;
  196. }
  197. }
  198. /* see if there is a top level router message */
  199. if( FD_ISSET(routerfd, &set) ) {
  200. osrfLogDebug( OSRF_LOG_MARK, "Top router socket is active: %d", routerfd );
  201. osrfRouterHandleIncoming( router );
  202. }
  203. /* Check each of the connected classes and see if they have data to route */
  204. osrfRouterClass* class;
  205. osrfHashIterator* itr = router->class_itr; // remove a layer of indirection
  206. osrfHashIteratorReset( itr );
  207. while( (class = osrfHashIteratorNext(itr)) ) { // for each class
  208. const char* classname = osrfHashIteratorKey(itr);
  209. if( classname ) {
  210. osrfLogDebug( OSRF_LOG_MARK, "Checking %s for activity...", classname );
  211. int sockfd = client_sock_fd( class->connection );
  212. if(FD_ISSET( sockfd, &set )) {
  213. osrfLogDebug( OSRF_LOG_MARK, "Socket is active: %d", sockfd );
  214. osrfRouterClassHandleIncoming( router, classname, class );
  215. }
  216. }
  217. } // end while
  218. } // end while
  219. }
  220. /**
  221. @brief Handle incoming requests to the router.
  222. @param router Pointer to the osrfRouter.
  223. Read all available input messages from the top-level transport_client. For each one:
  224. if the domain of the sender's Jabber id is on the list of approved domains, pass the
  225. message to osrfRouterHandleCommand() (if there's a message) or osrfRouterHandleAppRequest()
  226. (if there isn't). If the domain is @em not on the approved list, log a warning and
  227. discard the message.
  228. */
  229. static void osrfRouterHandleIncoming( osrfRouter* router ) {
  230. if(!router) return;
  231. transport_message* msg = NULL;
  232. while( (msg = client_recv( router->connection, 0 )) ) { // for each message
  233. if( msg->sender ) {
  234. osrfLogDebug(OSRF_LOG_MARK,
  235. "osrfRouterHandleIncoming(): investigating message from %s", msg->sender);
  236. /* if the server is not on a trusted domain, drop the message */
  237. int len = strlen(msg->sender) + 1;
  238. char domain[len];
  239. jid_get_domain( msg->sender, domain, len - 1 );
  240. if(osrfStringArrayContains( router->trustedServers, domain)) {
  241. // If there's a command, obey it. Otherwise, treat
  242. // the message as an app session level request.
  243. if( msg->router_command && *msg->router_command )
  244. osrfRouterHandleCommand( router, msg );
  245. else
  246. osrfRouterHandleAppRequest( router, msg );
  247. }
  248. else
  249. osrfLogWarning( OSRF_LOG_MARK,
  250. "Received message from un-trusted server domain %s", msg->sender);
  251. }
  252. message_free(msg);
  253. }
  254. }
  255. /**
  256. @brief Handle all available incoming messages for a router class.
  257. @param router Pointer to the osrfRouter.
  258. @param classname Class name.
  259. @param class Pointer to the osrfRouterClass.
  260. For each message: if the sender is on a trusted domain, process the message.
  261. */
  262. static void osrfRouterClassHandleIncoming( osrfRouter* router, const char* classname,
  263. osrfRouterClass* class ) {
  264. if(!(router && class)) return;
  265. transport_message* msg;
  266. osrfLogDebug( OSRF_LOG_MARK, "osrfRouterClassHandleIncoming()");
  267. // For each incoming message for this class:
  268. while( (msg = client_recv( class->connection, 0 )) ) {
  269. // Save the transaction id so that we can incorporate it
  270. // into any relevant messages
  271. osrfLogSetXid(msg->osrf_xid);
  272. if( msg->sender ) {
  273. osrfLogDebug(OSRF_LOG_MARK,
  274. "osrfRouterClassHandleIncoming(): investigating message from %s", msg->sender);
  275. /* if the client is not from a trusted domain, drop the message */
  276. int len = strlen(msg->sender) + 1;
  277. char domain[len];
  278. jid_get_domain( msg->sender, domain, len - 1 );
  279. if(osrfStringArrayContains( router->trustedClients, domain )) {
  280. if( msg->is_error ) {
  281. // A previous message bounced. Try to send a clone of it to a
  282. // different node of the same class.
  283. // First make a local copy of the class name. If the class gets
  284. // deleted, the classname parameter becomes invalid.
  285. char classname_copy[ strlen( classname ) + 1 ];
  286. strcpy( classname_copy, classname );
  287. transport_message* bouncedMessage = osrfRouterClassHandleBounce(
  288. router, classname, class, msg );
  289. /* handle bounced message */
  290. if( !bouncedMessage ) {
  291. /* we have no one to send the requested message to on our domain */
  292. /* XXX */
  293. /* XXX Here's where we plug in peer domains, inserting this brick into a wall */
  294. /* XXX */
  295. message_free( msg );
  296. osrfLogClearXid();
  297. // See if the class still exists
  298. if( osrfHashGet( router->classes, classname_copy ) )
  299. continue; // It does; keep going
  300. else
  301. break; // It doesn't; don't try to read from it any more
  302. }
  303. osrfRouterClassHandleMessage( router, class, bouncedMessage );
  304. message_free( bouncedMessage );
  305. } else
  306. osrfRouterClassHandleMessage( router, class, msg );
  307. } else {
  308. osrfLogWarning( OSRF_LOG_MARK,
  309. "Received client message from untrusted client domain %s", domain );
  310. }
  311. }
  312. message_free( msg );
  313. osrfLogClearXid(); // We're done with this transaction id
  314. }
  315. }
  316. /**
  317. @brief Handle a top level router command.
  318. @param router Pointer to the osrfRouter.
  319. @param msg Pointer to the transport_message to be handled.
  320. Currently supported commands:
  321. - "register" -- Add a server class and/or a server node to our lists.
  322. - "unregister" -- Remove a node from a class, and the class as well if no nodes are
  323. left for it.
  324. */
  325. static void osrfRouterHandleCommand( osrfRouter* router, const transport_message* msg ) {
  326. if(!(router && msg && msg->router_class)) return;
  327. if( !strcmp( msg->router_command, ROUTER_REGISTER ) ) {
  328. osrfLogInfo( OSRF_LOG_MARK, "Registering class %s", msg->router_class );
  329. // Add the server class to the list, if it isn't already there
  330. osrfRouterClass* class = osrfRouterFindClass( router, msg->router_class );
  331. if(!class)
  332. class = osrfRouterAddClass( router, msg->router_class );
  333. // Add the node to the osrfRouterClass's list, if it isn't already there
  334. if(class && ! osrfRouterClassFindNode( class, msg->sender ) )
  335. osrfRouterClassAddNode( class, msg->sender );
  336. } else if( !strcmp( msg->router_command, ROUTER_UNREGISTER ) ) {
  337. if( msg->router_class && *msg->router_class ) {
  338. osrfLogInfo( OSRF_LOG_MARK, "Unregistering router class %s", msg->router_class );
  339. osrfRouterClassRemoveNode( router, msg->router_class, msg->sender );
  340. }
  341. }
  342. }
  343. /**
  344. @brief Add an osrfRouterClass to a router, and open a connection for it.
  345. @param router Pointer to the osrfRouter.
  346. @param classname The name of the class this node handles.
  347. @return A pointer to the new osrfRouterClass, or NULL upon error.
  348. Open a Jabber session to be used for this server class. The Jabber ID incorporates the
  349. class name as the resource name.
  350. */
  351. static osrfRouterClass* osrfRouterAddClass( osrfRouter* router, const char* classname ) {
  352. if(!(router && router->classes && classname)) return NULL;
  353. osrfRouterClass* class = safe_malloc(sizeof(osrfRouterClass));
  354. class->nodes = osrfNewHash();
  355. class->itr = osrfNewHashIterator(class->nodes);
  356. osrfHashSetCallback(class->nodes, &osrfRouterNodeFree);
  357. class->router = router;
  358. class->connection = client_init( router->domain, router->port, NULL, 0 );
  359. if(!client_connect( class->connection, router->name,
  360. router->password, classname, 10, AUTH_DIGEST ) ) {
  361. // Cast away the constness of classname. Though ugly, this
  362. // cast is benign because osrfRouterClassFree doesn't actually
  363. // write through the pointer. We can't readily change its
  364. // signature because it is used for a function pointer, and
  365. // we would have to change other signatures the same way.
  366. osrfRouterClassFree( (char *) classname, class );
  367. return NULL;
  368. }
  369. osrfHashSet( router->classes, class, classname );
  370. return class;
  371. }
  372. /**
  373. @brief Add a new server node to an osrfRouterClass.
  374. @param rclass Pointer to the osrfRouterClass to which we are to add the node.
  375. @param remoteId The remote login of the osrfRouterNode.
  376. */
  377. static void osrfRouterClassAddNode( osrfRouterClass* rclass, const char* remoteId ) {
  378. if(!(rclass && rclass->nodes && remoteId)) return;
  379. osrfLogInfo( OSRF_LOG_MARK, "Adding router node for remote id %s", remoteId );
  380. osrfRouterNode* node = safe_malloc(sizeof(osrfRouterNode));
  381. node->count = 0;
  382. node->lastMessage = NULL;
  383. node->remoteId = strdup(remoteId);
  384. osrfHashSet( rclass->nodes, node, remoteId );
  385. }
  386. /**
  387. @brief Handle an input message representing a Jabber error stanza.
  388. @param router Pointer to the current osrfRouter.
  389. @param classname Name of the class to which the error stanza was sent.
  390. @param rclass Pointer to the osrfRouterClass to which the error stanza was sent.
  391. @param msg Pointer to the transport_message representing the error stanza.
  392. @return Pointer to a newly allocated transport_message; or NULL (see remarks).
  393. The presumption is that the relevant node is dead. If another node is available for
  394. the same class, then remove the dead one, create a clone of the message to be sent
  395. elsewhere, and return a pointer to it. If there is no other node for the same class,
  396. send a cancel message back to the sender, remove both the node and the class it belongs
  397. to, and return NULL. If we can't even do that because the entire class is dead, log
  398. a message to that effect and return NULL.
  399. */
  400. static transport_message* osrfRouterClassHandleBounce( osrfRouter* router,
  401. const char* classname, osrfRouterClass* rclass, const transport_message* msg ) {
  402. osrfLogDebug( OSRF_LOG_MARK, "osrfRouterClassHandleBounce()");
  403. osrfLogInfo( OSRF_LOG_MARK, "Received network layer error message from %s", msg->sender );
  404. osrfRouterNode* node = osrfRouterClassFindNode( rclass, msg->sender );
  405. if( ! node ) {
  406. osrfLogInfo( OSRF_LOG_MARK,
  407. "network error occurred after we removed the class.. ignoring");
  408. return NULL;
  409. }
  410. if( osrfHashGetCount(rclass->nodes) == 1 ) { /* the last node is dead */
  411. if( node->lastMessage ) {
  412. osrfLogWarning( OSRF_LOG_MARK,
  413. "We lost the last node in the class, responding with error and removing...");
  414. transport_message* error = message_init(
  415. node->lastMessage->body, node->lastMessage->subject,
  416. node->lastMessage->thread, node->lastMessage->router_from,
  417. node->lastMessage->recipient );
  418. message_set_osrf_xid(error, node->lastMessage->osrf_xid);
  419. set_msg_error( error, "cancel", 501 );
  420. /* send the error message back to the original sender */
  421. client_send_message( rclass->connection, error );
  422. message_free( error );
  423. }
  424. /* remove the dead node */
  425. osrfRouterClassRemoveNode( router, classname, msg->sender);
  426. return NULL;
  427. } else {
  428. transport_message* lastSent = NULL;
  429. if( node->lastMessage ) {
  430. osrfLogDebug( OSRF_LOG_MARK, "Cloning lastMessage so next node can send it");
  431. lastSent = message_init( node->lastMessage->body,
  432. node->lastMessage->subject, node->lastMessage->thread, "",
  433. node->lastMessage->router_from );
  434. message_set_router_info( lastSent, node->lastMessage->router_from,
  435. NULL, NULL, NULL, 0 );
  436. message_set_osrf_xid( lastSent, node->lastMessage->osrf_xid );
  437. }
  438. /* remove the dead node */
  439. osrfRouterClassRemoveNode( router, classname, msg->sender);
  440. return lastSent;
  441. }
  442. }
  443. /**
  444. @brief Forward a class-level message to a listener for the corresponding service.
  445. @param router Pointer to the current osrfRouter.
  446. @param rclass Pointer to the class to which the message is directed.
  447. @param msg Pointer to the message to be forwarded.
  448. Pick a node for the specified class, and forward the message to it.
  449. We use an iterator, stored with the class, to maintain a position in the class's list
  450. of nodes. Advance the iterator to pick the next node, and if we reach the end, go
  451. back to the beginning of the list.
  452. */
  453. static void osrfRouterClassHandleMessage(
  454. osrfRouter* router, osrfRouterClass* rclass, const transport_message* msg ) {
  455. if(!(router && rclass && msg)) return;
  456. osrfLogDebug( OSRF_LOG_MARK, "osrfRouterClassHandleMessage()");
  457. // Pick a node, in a round-robin.
  458. osrfRouterNode* node = osrfHashIteratorNext( rclass->itr );
  459. if(!node) { // wrap around to the beginning of the list
  460. osrfHashIteratorReset(rclass->itr);
  461. node = osrfHashIteratorNext( rclass->itr );
  462. }
  463. if(node) { // should always be true -- no class without a node
  464. // Build a transport message
  465. transport_message* new_msg = message_init( msg->body,
  466. msg->subject, msg->thread, node->remoteId, msg->sender );
  467. message_set_router_info( new_msg, msg->sender, NULL, NULL, NULL, 0 );
  468. message_set_osrf_xid( new_msg, msg->osrf_xid );
  469. osrfLogInfo( OSRF_LOG_MARK, "Routing message:\nfrom: [%s]\nto: [%s]",
  470. new_msg->router_from, new_msg->recipient );
  471. // Save it for possible future reference
  472. message_free( node->lastMessage );
  473. node->lastMessage = new_msg;
  474. // Send it
  475. if ( client_send_message( rclass->connection, new_msg ) == 0 )
  476. node->count++;
  477. else {
  478. message_prepare_xml(new_msg);
  479. osrfLogWarning( OSRF_LOG_MARK, "Error sending message from %s to %s\n%s",
  480. new_msg->sender, new_msg->recipient, new_msg->msg_xml );
  481. }
  482. // We don't free new_msg here because we saved it as node->lastMessage.
  483. }
  484. }
  485. /**
  486. @brief Remove a given osrfRouterClass from an osrfRouter
  487. @param router Pointer to the osrfRouter.
  488. @param classname The name of the class to be removed.
  489. Delete an osrfRouterClass from the router's list of classes. Indirectly (via a callback
  490. function installed in the osrfHash), free the osrfRouterClass and any associated nodes.
  491. */
  492. static void osrfRouterRemoveClass( osrfRouter* router, const char* classname ) {
  493. if( router && router->classes && classname ) {
  494. osrfLogInfo( OSRF_LOG_MARK, "Removing router class %s", classname );
  495. osrfHashRemove( router->classes, classname );
  496. }
  497. }
  498. /**
  499. @brief Remove a node from a class. If the class thereby becomes empty, remove it as well.
  500. @param router Pointer to the current osrfRouter.
  501. @param classname Class name.
  502. @param remoteId Identifier for the node to be removed.
  503. */
  504. static void osrfRouterClassRemoveNode(
  505. osrfRouter* router, const char* classname, const char* remoteId ) {
  506. if(!(router && router->classes && classname && remoteId)) // sanity check
  507. return;
  508. osrfLogInfo( OSRF_LOG_MARK, "Removing router node %s", remoteId );
  509. osrfRouterClass* class = osrfRouterFindClass( router, classname );
  510. if( class ) {
  511. osrfHashRemove( class->nodes, remoteId );
  512. if( osrfHashGetCount(class->nodes) == 0 ) {
  513. osrfRouterRemoveClass( router, classname );
  514. }
  515. }
  516. }
  517. /**
  518. @brief Free a router class object.
  519. @param classname Class name (not used).
  520. @param c Pointer to the osrfRouterClass, cast to a void pointer.
  521. This function is invoked as a callback when we remove an osrfRouterClass from the
  522. router's list of classes.
  523. */
  524. static void osrfRouterClassFree( char* classname, void* c ) {
  525. if( !c )
  526. return;
  527. osrfRouterClass* rclass = (osrfRouterClass*) c;
  528. client_disconnect( rclass->connection );
  529. client_free( rclass->connection );
  530. osrfHashIteratorReset( rclass->itr );
  531. osrfRouterNode* node;
  532. while( (node = osrfHashIteratorNext(rclass->itr)) )
  533. osrfHashRemove( rclass->nodes, node->remoteId );
  534. osrfHashIteratorFree(rclass->itr);
  535. osrfHashFree(rclass->nodes);
  536. free(rclass);
  537. }
  538. /**
  539. @brief Free an osrfRouterNode.
  540. @param remoteId Jabber ID of node (not used).
  541. @param n Pointer to the osrfRouterNode to be freed, cast to a void pointer.
  542. This is a callback installed in an osrfHash (the nodes member of an osrfRouterClass).
  543. */
  544. static void osrfRouterNodeFree( char* remoteId, void* n ) {
  545. if(!n) return;
  546. osrfRouterNode* node = (osrfRouterNode*) n;
  547. free(node->remoteId);
  548. message_free(node->lastMessage);
  549. free(node);
  550. }
  551. /**
  552. @brief Free an osrfRouter and everything it owns.
  553. @param router Pointer to the osrfRouter to be freed.
  554. The osrfRouterClasses and osrfRouterNodes are freed by callback functions installed in
  555. the osrfHashes.
  556. */
  557. void osrfRouterFree( osrfRouter* router ) {
  558. if(!router) return;
  559. osrfHashIteratorFree( router->class_itr);
  560. osrfHashFree(router->classes);
  561. free(router->domain);
  562. free(router->name);
  563. free(router->resource);
  564. free(router->password);
  565. osrfStringArrayFree( router->trustedClients );
  566. osrfStringArrayFree( router->trustedServers );
  567. osrfListFree( router->message_list );
  568. client_free( router->connection );
  569. free(router);
  570. }
  571. /**
  572. @brief Given a class name, find the corresponding osrfRouterClass.
  573. @param router Pointer to the osrfRouter that owns the osrfRouterClass.
  574. @param classname Name of the class.
  575. @return Pointer to a matching osrfRouterClass if found, or NULL if not.
  576. */
  577. static osrfRouterClass* osrfRouterFindClass( osrfRouter* router, const char* classname ) {
  578. if(!( router && router->classes && classname )) return NULL;
  579. return (osrfRouterClass*) osrfHashGet( router->classes, classname );
  580. }
  581. /**
  582. @brief Find a given node for a given class.
  583. @param rclass Pointer to the osrfRouterClass in which to search.
  584. @param remoteId Jabber ID of the node for which to search.
  585. @return Pointer to the matching osrfRouterNode, if found; otherwise NULL.
  586. */
  587. static osrfRouterNode* osrfRouterClassFindNode( osrfRouterClass* rclass,
  588. const char* remoteId ) {
  589. if(!(rclass && remoteId)) return NULL;
  590. return (osrfRouterNode*) osrfHashGet( rclass->nodes, remoteId );
  591. }
  592. /**
  593. @brief Fill an fd_set with all the sockets owned by the osrfRouter.
  594. @param router Pointer to the osrfRouter whose sockets are to be used.
  595. @param set Pointer to the fd_set that is to be filled.
  596. @return The largest file descriptor loaded into the fd_set; or -1 upon error.
  597. There's one socket for the osrfRouter as a whole, and one for each osrfRouterClass
  598. that belongs to it. We load them all.
  599. */
  600. static int _osrfRouterFillFDSet( osrfRouter* router, fd_set* set ) {
  601. if(!(router && router->classes && set)) return -1;
  602. FD_ZERO(set);
  603. int maxfd = client_sock_fd( router->connection );
  604. FD_SET(maxfd, set);
  605. int sockid;
  606. osrfRouterClass* class = NULL;
  607. osrfHashIterator* itr = router->class_itr;
  608. osrfHashIteratorReset( itr );
  609. while( (class = osrfHashIteratorNext(itr)) ) {
  610. const char* classname = osrfHashIteratorKey(itr);
  611. if( classname && (class = osrfRouterFindClass( router, classname )) ) {
  612. sockid = client_sock_fd( class->connection );
  613. if( osrfUtilsCheckFileDescriptor( sockid ) ) {
  614. osrfLogWarning(OSRF_LOG_MARK,
  615. "Removing router class '%s' because of a bad top-level file descriptor [%d]",
  616. classname, sockid );
  617. osrfRouterRemoveClass( router, classname );
  618. } else {
  619. if( sockid > maxfd ) maxfd = sockid;
  620. FD_SET(sockid, set);
  621. }
  622. }
  623. }
  624. return maxfd;
  625. }
  626. /**
  627. @brief Handler a router-level message that isn't a command; presumed to be an app request.
  628. @param router Pointer to the current osrfRouter.
  629. @param msg Pointer to the incoming message.
  630. The body of the transport_message is a JSON string, specifically an JSON array.
  631. Translate the JSON into a series of osrfMessages, one for each element of the JSON
  632. array. Process each osrfMessage in turn. Each message is either a CONNECT or a
  633. REQUEST.
  634. */
  635. static void osrfRouterHandleAppRequest( osrfRouter* router, const transport_message* msg ) {
  636. // Translate the JSON into a list of osrfMessages
  637. router->message_list = osrfMessageDeserialize( msg->body, router->message_list );
  638. const osrfMessage* omsg = NULL;
  639. // Process each osrfMessage
  640. int i;
  641. for( i = 0; i < router->message_list->size; ++i ) {
  642. omsg = osrfListGetIndex( router->message_list, i );
  643. if( omsg ) {
  644. switch( omsg->m_type ) {
  645. case CONNECT:
  646. osrfRouterRespondConnect( router, msg, omsg );
  647. break;
  648. case REQUEST:
  649. osrfRouterProcessAppRequest( router, msg, omsg );
  650. break;
  651. default:
  652. break;
  653. }
  654. }
  655. }
  656. osrfListClear( router->message_list );
  657. return;
  658. }
  659. /**
  660. @brief Respond to a CONNECT message.
  661. @param router Pointer to the current osrfRouter.
  662. @param msg Pointer to the transport_message that the osrfMessage came from.
  663. @param omsg Pointer to the osrfMessage to be processed.
  664. An application is trying to connect to the router. Reply with a STATUS message
  665. signifying success.
  666. "CONNECT" is a bit of a misnomer. We don't establish a stateful session; i.e. we
  667. don't retain any memory of this message. We just confirm that the router is alive,
  668. and that the client has a good address for it.
  669. */
  670. static void osrfRouterRespondConnect( osrfRouter* router, const transport_message* msg,
  671. const osrfMessage* omsg ) {
  672. if(!(router && msg && omsg))
  673. return;
  674. osrfLogDebug( OSRF_LOG_MARK, "router received a CONNECT message from %s", msg->sender );
  675. // Build a success message
  676. osrfMessage* success = osrf_message_init( STATUS, omsg->thread_trace, omsg->protocol );
  677. osrf_message_set_status_info(
  678. success, "osrfConnectStatus", "Connection Successful", OSRF_STATUS_OK );
  679. // Translate the success message into JSON,
  680. // and then package the JSON in a transport message
  681. char* data = osrf_message_serialize(success);
  682. osrfMessageFree( success );
  683. transport_message* return_msg = message_init(
  684. data, // message payload, translated from osrfMessage
  685. "", // no subject
  686. msg->thread, // same thread
  687. msg->sender, // destination (client's Jabber ID)
  688. "" // don't send our address; client already has it
  689. );
  690. free( data );
  691. client_send_message( router->connection, return_msg );
  692. message_free( return_msg );
  693. }
  694. /**
  695. @brief Respond to a REQUEST message.
  696. @param router Pointer to the current osrfRouter.
  697. @param msg Pointer to the transport_message that the osrfMessage came from.
  698. @param omsg Pointer to the osrfMessage to be processed.
  699. Respond to an information request from an application. Most types of request involve
  700. one or more counts of messages successfully routed.
  701. Request types currently supported:
  702. - "opensrf.router.info.class.list" -- list of class names.
  703. - "opensrf.router.info.stats.class.summary" -- total count for a specified class.
  704. - "opensrf.router.info.stats.class" -- count for every node of a specified class.
  705. - "opensrf.router.info.stats.class.all" -- count for every node of every class.
  706. - "opensrf.router.info.stats.class.node.all" -- total count for every class.
  707. */
  708. static void osrfRouterProcessAppRequest( osrfRouter* router, const transport_message* msg,
  709. const osrfMessage* omsg ) {
  710. if(!(router && msg && omsg && omsg->method_name))
  711. return;
  712. osrfLogInfo( OSRF_LOG_MARK, "Router received app request: %s", omsg->method_name );
  713. // Branch on the request type. Build a jsonObject as an answer to the request.
  714. jsonObject* jresponse = NULL;
  715. if(!strcmp( omsg->method_name, ROUTER_REQUEST_CLASS_LIST )) {
  716. // Prepare an array of class names.
  717. int i;
  718. jresponse = jsonNewObjectType(JSON_ARRAY);
  719. osrfStringArray* keys = osrfHashKeys( router->classes );
  720. for( i = 0; i != keys->size; i++ )
  721. jsonObjectPush( jresponse, jsonNewObject(osrfStringArrayGetString( keys, i )) );
  722. osrfStringArrayFree(keys);
  723. } else if(!strcmp( omsg->method_name, ROUTER_REQUEST_STATS_CLASS_SUMMARY )) {
  724. // Prepare a count of all the messages successfully routed for a given class.
  725. int count = 0;
  726. // class name is the first parameter
  727. const char* classname = jsonObjectGetString( jsonObjectGetIndex( omsg->_params, 0 ) );
  728. if (!classname)
  729. return;
  730. osrfRouterClass* class = osrfHashGet(router->classes, classname);
  731. // For each node: add the count to the total.
  732. osrfRouterNode* node;
  733. osrfHashIterator* node_itr = osrfNewHashIterator(class->nodes);
  734. while( (node = osrfHashIteratorNext(node_itr)) ) {
  735. count += node->count;
  736. // jsonObjectSetKey( class_res, node->remoteId,
  737. // jsonNewNumberObject( (double) node->count ) );
  738. }
  739. osrfHashIteratorFree(node_itr);
  740. jresponse = jsonNewNumberObject( (double) count );
  741. } else if(!strcmp( omsg->method_name, ROUTER_REQUEST_STATS_CLASS )) {
  742. // Prepare a hash for a given class. Key: the remoteId of a node. Datum: the
  743. // number of messages successfully routed for that node.
  744. // class name is the first parameter
  745. const char* classname = jsonObjectGetString( jsonObjectGetIndex( omsg->_params, 0 ) );
  746. if (!classname)
  747. return;
  748. jresponse = jsonNewObjectType(JSON_HASH);
  749. osrfRouterClass* class = osrfHashGet(router->classes, classname);
  750. // For each node: get the count and store it in the hash.
  751. osrfRouterNode* node;
  752. osrfHashIterator* node_itr = osrfNewHashIterator(class->nodes);
  753. while( (node = osrfHashIteratorNext(node_itr)) ) {
  754. jsonObjectSetKey( jresponse, node->remoteId,
  755. jsonNewNumberObject( (double) node->count ) );
  756. }
  757. osrfHashIteratorFree(node_itr);
  758. } else if(!strcmp( omsg->method_name, ROUTER_REQUEST_STATS_CLASS_FULL )) {
  759. // Prepare a hash of hashes, giving the message counts for each node for each class.
  760. osrfRouterClass* class;
  761. osrfRouterNode* node;
  762. jresponse = jsonNewObjectType(JSON_HASH); // Key: class name.
  763. // Traverse the list of classes.
  764. osrfHashIterator* class_itr = osrfNewHashIterator(router->classes);
  765. while( (class = osrfHashIteratorNext(class_itr)) ) {
  766. jsonObject* class_res = jsonNewObjectType(JSON_HASH); // Key: remoteId of node.
  767. const char* classname = osrfHashIteratorKey(class_itr);
  768. // Traverse the list of nodes for the current class.
  769. osrfHashIterator* node_itr = osrfNewHashIterator(class->nodes);
  770. while( (node = osrfHashIteratorNext(node_itr)) ) {
  771. jsonObjectSetKey( class_res, node->remoteId,
  772. jsonNewNumberObject( (double) node->count ) );
  773. }
  774. osrfHashIteratorFree(node_itr);
  775. jsonObjectSetKey( jresponse, classname, class_res );
  776. }
  777. osrfHashIteratorFree(class_itr);
  778. } else if(!strcmp( omsg->method_name, ROUTER_REQUEST_STATS_NODE_FULL )) {
  779. // Prepare a hash. Key: class name. Datum: total number of successfully routed
  780. // messages routed for nodes of that class.
  781. osrfRouterClass* class;
  782. osrfRouterNode* node;
  783. jresponse = jsonNewObjectType(JSON_HASH);
  784. osrfHashIterator* class_itr = osrfNewHashIterator(router->classes);
  785. while( (class = osrfHashIteratorNext(class_itr)) ) { // For each class
  786. int count = 0;
  787. const char* classname = osrfHashIteratorKey(class_itr);
  788. osrfHashIterator* node_itr = osrfNewHashIterator(class->nodes);
  789. while( (node = osrfHashIteratorNext(node_itr)) ) { // For each node
  790. count += node->count;
  791. }
  792. osrfHashIteratorFree(node_itr);
  793. jsonObjectSetKey( jresponse, classname, jsonNewNumberObject( (double) count ) );
  794. }
  795. osrfHashIteratorFree(class_itr);
  796. } else { // None of the above
  797. osrfRouterHandleMethodNFound( router, msg, omsg );
  798. return;
  799. }
  800. // Send the result back to the requester.
  801. osrfRouterSendAppResponse( router, msg, omsg, jresponse );
  802. jsonObjectFree(jresponse);
  803. }
  804. /**
  805. @brief Respond to an invalid REQUEST message.
  806. @param router Pointer to the current osrfRouter.
  807. @param msg Pointer to the transport_message that contained the REQUEST message.
  808. @param omsg Pointer to the osrfMessage that contained the REQUEST.
  809. */
  810. static void osrfRouterHandleMethodNFound( osrfRouter* router,
  811. const transport_message* msg, const osrfMessage* omsg ) {
  812. // Create an exception message
  813. osrfMessage* err = osrf_message_init( STATUS, omsg->thread_trace, 1 );
  814. osrf_message_set_status_info( err,
  815. "osrfMethodException", "Router method not found", OSRF_STATUS_NOTFOUND );
  816. // Translate it into JSON
  817. char* data = osrf_message_serialize(err);
  818. osrfMessageFree( err );
  819. // Wrap the JSON up in a transport_message
  820. transport_message* tresponse = message_init(
  821. data, "", msg->thread, msg->sender, msg->recipient );
  822. free(data);
  823. // Send it
  824. client_send_message( router->connection, tresponse );
  825. message_free( tresponse );
  826. }
  827. /**
  828. @brief Send a response to a router REQUEST message.
  829. @param router Pointer to the current osrfRouter.
  830. @param msg Pointer to the transport_message that contained the REQUEST message.
  831. @param omsg Pointer to the osrfMessage that contained the REQUEST.
  832. @param response Pointer to the jsonObject that constitutes the response.
  833. */
  834. static void osrfRouterSendAppResponse( osrfRouter* router, const transport_message* msg,
  835. const osrfMessage* omsg, const jsonObject* response ) {
  836. if( response ) { /* send the response message */
  837. // Turn the jsonObject into JSON, and load it into an osrfMessage
  838. osrfMessage* oresponse = osrf_message_init(
  839. RESULT, omsg->thread_trace, omsg->protocol );
  840. char* json = jsonObjectToJSON(response);
  841. osrf_message_set_result_content( oresponse, json );
  842. free(json);
  843. // Package the osrfMessage into a transport_message, and send it
  844. char* data = osrf_message_serialize(oresponse);
  845. osrfMessageFree(oresponse);
  846. osrfLogDebug( OSRF_LOG_MARK, "Responding to client app request with data: \n%s\n", data );
  847. transport_message* tresponse = message_init(
  848. data, "", msg->thread, msg->sender, msg->recipient );
  849. free(data);
  850. client_send_message(router->connection, tresponse );
  851. message_free(tresponse);
  852. }
  853. /* now send the 'request complete' message */
  854. osrfMessage* status = osrf_message_init( STATUS, omsg->thread_trace, 1);
  855. osrf_message_set_status_info( status, "osrfConnectStatus", "Request Complete",
  856. OSRF_STATUS_COMPLETE );
  857. char* statusdata = osrf_message_serialize(status);
  858. osrfMessageFree(status);
  859. transport_message* sresponse = message_init(
  860. statusdata, "", msg->thread, msg->sender, msg->recipient );
  861. free(statusdata);
  862. client_send_message(router->connection, sresponse );
  863. message_free(sresponse);
  864. }