PageRenderTime 50ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/src/libopensrf/osrf_stack.c

https://gitlab.com/evergreen-bjwebb/opensrf-debian
C | 308 lines | 175 code | 56 blank | 77 comment | 33 complexity | c2c0eb3685549ddf396a660f7e8b7b70 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause
  1. #include <opensrf/osrf_stack.h>
  2. #include <opensrf/osrf_application.h>
  3. /**
  4. @file osrf_stack.c
  5. @brief Routines to receive and process input osrfMessages.
  6. */
  7. /* the max number of oilsMessage blobs present in any one root packet */
  8. #define OSRF_MAX_MSGS_PER_PACKET 256
  9. // -----------------------------------------------------------------------------
  10. static void _do_client( osrfAppSession*, osrfMessage* );
  11. static void _do_server( osrfAppSession*, osrfMessage* );
  12. /**
  13. @brief Read and process available transport_messages for a transport_client.
  14. @param client Pointer to the transport_client whose socket is to be read.
  15. @param timeout How many seconds to wait for the first message.
  16. @param msg_received A pointer through which to report whether a message was received.
  17. @return 0 upon success (even if a timeout occurs), or -1 upon failure.
  18. Read and process all available transport_messages from the socket of the specified
  19. transport_client. Pass each one through osrf_stack_transport().
  20. The timeout applies only to the first message. Any subsequent messages must be
  21. available immediately. Don't wait for them, even if the timeout has not expired. In
  22. theory, a sufficiently large backlog of input messages could keep you working past the
  23. nominal expiration of the timeout.
  24. The @a msg_received parameter points to an int owned by the calling code and used as
  25. a boolean. Set it to true if you receive at least one transport_message, or to false
  26. if you don't. A timeout is not treated as an error; it just means you must set that
  27. boolean to false.
  28. */
  29. int osrf_stack_process( transport_client* client, int timeout, int* msg_received ) {
  30. if( !client ) return -1;
  31. transport_message* msg = NULL;
  32. if(msg_received) *msg_received = 0;
  33. // Loop through the available input messages
  34. while( (msg = client_recv( client, timeout )) ) {
  35. if(msg_received) *msg_received = 1;
  36. osrfLogDebug( OSRF_LOG_MARK, "Received message from transport code from %s", msg->sender );
  37. osrf_stack_transport_handler( msg, NULL );
  38. timeout = 0;
  39. }
  40. if( client->error ) {
  41. osrfLogWarning(OSRF_LOG_MARK, "transport_client had trouble reading from the socket..");
  42. return -1;
  43. }
  44. if( ! client_connected( client ) ) return -1;
  45. return 0;
  46. }
  47. // -----------------------------------------------------------------------------
  48. // Entry point into the stack
  49. // -----------------------------------------------------------------------------
  50. /**
  51. @brief Unpack a transport_message into one or more osrfMessages, and process each one.
  52. @param msg Pointer to the transport_message to be unpacked and processed.
  53. @param my_service Application name (optional).
  54. @return Pointer to an osrfAppSession -- either a pre-existing one or a new one.
  55. Look for an existing osrfAppSession with which the message is associated. Such a session
  56. may already exist if, for example, you're a client waiting for a response from some other
  57. application, or if you're a server that has opened a stateful session with a client.
  58. If you can't find an existing session for the current message, and the @a my_service
  59. parameter has provided an application name, then you're presumably a server receiving
  60. something from a new client. Create an application server session to own the new message.
  61. Barring various errors and malformations, extract one or more osrfMessages from the
  62. transport_message. Pass each one to the appropriate routine for processing, depending
  63. on whether you're acting as a client or as a server.
  64. */
  65. struct osrf_app_session_struct* osrf_stack_transport_handler( transport_message* msg,
  66. const char* my_service ) {
  67. if(!msg) return NULL;
  68. osrfLogSetXid(msg->osrf_xid);
  69. osrfLogDebug( OSRF_LOG_MARK, "Transport handler received new message \nfrom %s "
  70. "to %s with body \n\n%s\n", msg->sender, msg->recipient, msg->body );
  71. if( msg->is_error && ! msg->thread ) {
  72. osrfLogWarning( OSRF_LOG_MARK,
  73. "!! Received jabber layer error for %s ... exiting\n", msg->sender );
  74. message_free( msg );
  75. return NULL;
  76. }
  77. if(! msg->thread && ! msg->is_error ) {
  78. osrfLogWarning( OSRF_LOG_MARK,
  79. "Received a non-error message with no thread trace... dropping");
  80. message_free( msg );
  81. return NULL;
  82. }
  83. osrfAppSession* session = osrf_app_session_find_session( msg->thread );
  84. if( !session && my_service )
  85. session = osrf_app_server_session_init( msg->thread, my_service, msg->sender);
  86. if( !session ) {
  87. message_free( msg );
  88. return NULL;
  89. }
  90. if(!msg->is_error)
  91. osrfLogDebug( OSRF_LOG_MARK, "Session [%s] found or built", session->session_id );
  92. osrf_app_session_set_remote( session, msg->sender );
  93. osrfMessage* arr[OSRF_MAX_MSGS_PER_PACKET];
  94. /* Convert the message body into one or more osrfMessages */
  95. int num_msgs = osrf_message_deserialize(msg->body, arr, OSRF_MAX_MSGS_PER_PACKET);
  96. osrfLogDebug( OSRF_LOG_MARK, "We received %d messages from %s", num_msgs, msg->sender );
  97. double starttime = get_timestamp_millis();
  98. int i;
  99. for( i = 0; i < num_msgs; i++ ) {
  100. /* if we've received a jabber layer error message (probably talking to
  101. someone who no longer exists) and we're not talking to the original
  102. remote id for this server, consider it a redirect and pass it up */
  103. if(msg->is_error) {
  104. osrfLogWarning( OSRF_LOG_MARK, " !!! Received Jabber layer error message" );
  105. if( strcmp( session->remote_id, session->orig_remote_id ) ) {
  106. osrfLogWarning( OSRF_LOG_MARK, "Treating jabber error as redirect for tt [%d] "
  107. "and session [%s]", arr[i]->thread_trace, session->session_id );
  108. arr[i]->m_type = STATUS;
  109. arr[i]->status_code = OSRF_STATUS_REDIRECTED;
  110. } else {
  111. osrfLogWarning( OSRF_LOG_MARK, " * Jabber Error is for top level remote "
  112. " id [%s], no one to send my message to! Cutting request short...",
  113. session->remote_id );
  114. session->transport_error = 1;
  115. break;
  116. }
  117. }
  118. if( session->type == OSRF_SESSION_CLIENT )
  119. _do_client( session, arr[i] );
  120. else
  121. _do_server( session, arr[i] );
  122. }
  123. double duration = get_timestamp_millis() - starttime;
  124. osrfLogInfo(OSRF_LOG_MARK, "Message processing duration %f", duration);
  125. message_free( msg );
  126. osrfLogDebug( OSRF_LOG_MARK, "after msg delete");
  127. return session;
  128. }
  129. /**
  130. @brief Acting as a client, process an incoming osrfMessage.
  131. @param session Pointer to the osrfAppSession to which the message pertains.
  132. @param msg Pointer to the osrfMessage.
  133. What we do with the message depends on the combination of message type and status code:
  134. - If it's a RESULT message, add it to the message queue of the appropriate app session,
  135. to be handled later.
  136. - If it's a STATUS message, handle it according to its status code and return NULL --
  137. unless it has an unexpected status code, in which case add it to the message queue of
  138. the appropriate app session, to be handled later.
  139. */
  140. static void _do_client( osrfAppSession* session, osrfMessage* msg ) {
  141. if(session == NULL || msg == NULL)
  142. return;
  143. if( msg->m_type == STATUS ) {
  144. switch( msg->status_code ) {
  145. case OSRF_STATUS_OK:
  146. // This combination of message type and status code comes
  147. // only from the router, in response to a CONNECT message.
  148. osrfLogDebug( OSRF_LOG_MARK, "We connected successfully");
  149. session->state = OSRF_SESSION_CONNECTED;
  150. osrfLogDebug( OSRF_LOG_MARK, "State: %x => %s => %d", session,
  151. session->session_id, session->state );
  152. osrfMessageFree(msg);
  153. break;
  154. case OSRF_STATUS_COMPLETE:
  155. osrf_app_session_set_complete( session, msg->thread_trace );
  156. osrfMessageFree(msg);
  157. break;
  158. case OSRF_STATUS_CONTINUE:
  159. osrf_app_session_request_reset_timeout( session, msg->thread_trace );
  160. osrfMessageFree(msg);
  161. break;
  162. case OSRF_STATUS_REDIRECTED:
  163. osrf_app_session_reset_remote( session );
  164. session->state = OSRF_SESSION_DISCONNECTED;
  165. osrf_app_session_request_resend( session, msg->thread_trace );
  166. osrfMessageFree(msg);
  167. break;
  168. case OSRF_STATUS_EXPFAILED:
  169. osrf_app_session_reset_remote( session );
  170. session->state = OSRF_SESSION_DISCONNECTED;
  171. osrfMessageFree(msg);
  172. break;
  173. case OSRF_STATUS_TIMEOUT:
  174. osrf_app_session_reset_remote( session );
  175. session->state = OSRF_SESSION_DISCONNECTED;
  176. osrf_app_session_request_resend( session, msg->thread_trace );
  177. osrfMessageFree(msg);
  178. break;
  179. default:
  180. {
  181. /* Replace the old message with a new one */
  182. osrfMessage* new_msg = osrf_message_init(
  183. RESULT, msg->thread_trace, msg->protocol );
  184. osrf_message_set_status_info( new_msg,
  185. msg->status_name, msg->status_text, msg->status_code );
  186. osrfLogWarning( OSRF_LOG_MARK, "The stack doesn't know what to do with "
  187. "the provided message code: %d, name %s. Passing UP.",
  188. msg->status_code, msg->status_name );
  189. new_msg->is_exception = 1;
  190. osrf_app_session_set_complete( session, msg->thread_trace );
  191. osrfLogDebug( OSRF_LOG_MARK,
  192. "passing client message %d / session %s to app handler",
  193. msg->thread_trace, session->session_id );
  194. osrfMessageFree(msg);
  195. // Enqueue the new message to be processed later
  196. osrf_app_session_push_queue( session, new_msg );
  197. break;
  198. } // end default
  199. } // end switch
  200. } else if( msg->m_type == RESULT ) {
  201. osrfLogDebug( OSRF_LOG_MARK, "passing client message %d / session %s to app handler",
  202. msg->thread_trace, session->session_id );
  203. // Enqueue the RESULT message to be processed later
  204. osrf_app_session_push_queue( session, msg );
  205. }
  206. return;
  207. }
  208. /**
  209. @brief Acting as a server, process an incoming osrfMessage.
  210. @param session Pointer to the osrfAppSession to which the message pertains.
  211. @param msg Pointer to the osrfMessage.
  212. Branch on the message type. In particular, if it's a REQUEST, call the requested method.
  213. */
  214. static void _do_server( osrfAppSession* session, osrfMessage* msg ) {
  215. if(session == NULL || msg == NULL) return;
  216. osrfLogDebug( OSRF_LOG_MARK, "Server received message of type %d", msg->m_type );
  217. switch( msg->m_type ) {
  218. case STATUS:
  219. break;
  220. case DISCONNECT:
  221. /* session will be freed by the forker */
  222. osrfLogDebug(OSRF_LOG_MARK, "Client sent explicit disconnect");
  223. session->state = OSRF_SESSION_DISCONNECTED;
  224. break;
  225. case CONNECT:
  226. osrfAppSessionStatus( session, OSRF_STATUS_OK,
  227. "osrfConnectStatus", msg->thread_trace, "Connection Successful" );
  228. session->state = OSRF_SESSION_CONNECTED;
  229. break;
  230. case REQUEST:
  231. osrfLogDebug( OSRF_LOG_MARK, "server passing message %d to application handler "
  232. "for session %s", msg->thread_trace, session->session_id );
  233. osrfAppRunMethod( session->remote_service, msg->method_name,
  234. session, msg->thread_trace, msg->_params );
  235. break;
  236. default:
  237. osrfLogWarning( OSRF_LOG_MARK,
  238. "Server cannot handle message of type %d", msg->m_type );
  239. session->state = OSRF_SESSION_DISCONNECTED;
  240. break;
  241. }
  242. osrfMessageFree(msg);
  243. return;
  244. }