From: scottmk Date: Thu, 22 Oct 2009 03:21:31 +0000 (+0000) Subject: Various cleanups in transport_session.c: X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=b4527520685ea92320f14938dd6cc193cf8edbc2;p=opensrf%2Fbjwebb.git Various cleanups in transport_session.c: 1. In init_transport(): guard against a NULL server parameter. 2. In session_free(): if the session is still open, disconnect it. 3. In session_connect(): if we open a socket but are unable to connect to Jabber, close the socket and set the sock_id member to zero. If the socket is already open, return an error, instead of reusing the existing socket (and trying to overlay any open Jabber session). 4. In session_connect(): guard against an invalid auth_type. 5. In session_connect(): corrected some errors in the way we calculate buffer sizes, 6. In session_disconnect(): send a disconnect message only if the socket is still open. 7. Tidied up white space and comments in various places. 8. Added doxygen-style comments to document some of the functions. M src/libopensrf/transport_session.c git-svn-id: svn://svn.open-ils.org/OpenSRF/trunk@1822 9efc2488-bf62-4759-914b-345cdb29e865 --- diff --git a/src/libopensrf/transport_session.c b/src/libopensrf/transport_session.c index f8eab3a..e34bd5c 100644 --- a/src/libopensrf/transport_session.c +++ b/src/libopensrf/transport_session.c @@ -1,11 +1,18 @@ #include +/** + @file transport_session.c + @brief Routines to manage a connection to a Jabber server. + + In all cases, a transport_session acts as a client with regard to Jabber. +*/ + // --------------------------------------------------------------------------------- // Callback for handling the startElement event. Much of the jabber logic occurs // in this and the characterHandler callbacks. // Here we check for the various top level jabber elements: body, iq, etc. // --------------------------------------------------------------------------------- -static void startElementHandler( +static void startElementHandler( void *session, const xmlChar *name, const xmlChar **atts); // --------------------------------------------------------------------------------- @@ -75,15 +82,32 @@ static void grab_incoming(void* blob, socket_manager* mgr, int sockid, char* dat static int reset_session_buffers( transport_session* session ); static char* get_xml_attr( const xmlChar** atts, const char* attr_name ); -// --------------------------------------------------------------------------------- -// returns a built and allocated transport_session object. -// This codes does no network activity, only memory initilization -// --------------------------------------------------------------------------------- -transport_session* init_transport( const char* server, +/** + @brief Allocate and initialize a transport_session. + @param server Hostname or IP address where the Jabber server resides. + @param port Port used for connecting to Jabber (0 if using UNIX domain socket). + @param unix_path Name of Jabber's socket in file system (if using UNIX domain socket). + @param user_data An opaque pointer stored on behalf of the calling code. + @param component Boolean; true if we're a component. + @return Pointer to a newly allocated transport_session. + + This function initializes memory but does not open any sockets or otherwise access + the network. + + If @a port is greater than zero, we will use TCP to connect to Jabber, and ignore + @a unix_path. Otherwise we will open a UNIX domain socket using @a unix_path. + + The calling code is responsible for freeing the transport_session by calling + session_free(). +*/ +transport_session* init_transport( const char* server, int port, const char* unix_path, void* user_data, int component ) { + if( ! server ) + server = ""; + /* create the session struct */ - transport_session* session = + transport_session* session = (transport_session*) safe_malloc( sizeof(transport_session) ); session->user_data = user_data; @@ -91,10 +115,10 @@ transport_session* init_transport( const char* server, session->component = component; /* initialize the data buffers */ - session->body_buffer = buffer_init( JABBER_BODY_BUFSIZE ); + session->body_buffer = buffer_init( JABBER_BODY_BUFSIZE ); session->subject_buffer = buffer_init( JABBER_SUBJECT_BUFSIZE ); session->thread_buffer = buffer_init( JABBER_THREAD_BUFSIZE ); - session->from_buffer = buffer_init( JABBER_JID_BUFSIZE ); + session->from_buffer = buffer_init( JABBER_JID_BUFSIZE ); session->status_buffer = buffer_init( JABBER_STATUS_BUFSIZE ); session->recipient_buffer = buffer_init( JABBER_JID_BUFSIZE ); session->message_error_type = buffer_init( JABBER_JID_BUFSIZE ); @@ -103,7 +127,7 @@ transport_session* init_transport( const char* server, session->message_error_code = 0; /* for OpenSRF extensions */ - session->router_to_buffer = buffer_init( JABBER_JID_BUFSIZE ); + session->router_to_buffer = buffer_init( JABBER_JID_BUFSIZE ); session->router_from_buffer = buffer_init( JABBER_JID_BUFSIZE ); session->osrf_xid_buffer = buffer_init( JABBER_JID_BUFSIZE ); session->router_class_buffer = buffer_init( JABBER_JID_BUFSIZE ); @@ -128,17 +152,17 @@ transport_session* init_transport( const char* server, /* initialize the sax push parser */ session->parser_ctxt = xmlCreatePushParserCtxt(SAXHandler, session, "", 0, NULL); - /* initialize the transport_socket structure */ + /* initialize the socket_manager structure */ session->sock_mgr = (socket_manager*) safe_malloc( sizeof(socket_manager) ); session->sock_mgr->data_received = &grab_incoming; session->sock_mgr->on_socket_closed = NULL; session->sock_mgr->socket = NULL; session->sock_mgr->blob = session; - + session->port = port; session->server = strdup(server); - if(unix_path) + if(unix_path) session->unix_path = strdup(unix_path); else session->unix_path = NULL; @@ -149,11 +173,19 @@ transport_session* init_transport( const char* server, } +/** + @brief Destroy a transport_session, and close its socket. + @param session Pointer to the transport_session to be destroyed. + @return 1 if successful, or 0 if not. -/* XXX FREE THE BUFFERS */ + The only error condition is a NULL pointer argument. +*/ int session_free( transport_session* session ) { if( ! session ) { return 0; } + if( session->sock_id ) + session_disconnect( session ); + if(session->sock_mgr) socket_manager_free(session->sock_mgr); @@ -189,6 +221,22 @@ int session_free( transport_session* session ) { } +/** + @brief Wait on the client socket connected to Jabber, and process any resulting input. + @param session Pointer to the transport_session. + @param timeout How seconds to wait before timing out (see notes). + @return 0 if successful, or -1 if a timeout or other error occurs, or if the server + closes the connection at the other end. + + If @a timeout is -1, wait indefinitely for input activity to appear. If @a timeout is + zero, don't wait at all. If @a timeout is positive, wait that number of seconds + before timing out. If @a timeout has a negative value other than -1, the results are not + well defined. + + Read all available input from the socket and pass it through grab_incoming() (a previously + designated callback function). There is no guarantee that we will get a complete message + from a single call. +*/ int session_wait( transport_session* session, int timeout ) { if( ! session || ! session->sock_mgr ) { return 0; @@ -203,7 +251,13 @@ int session_wait( transport_session* session, int timeout ) { return ret; } -int session_send_msg( +/** + @brief Wrap a message in XML and send it to Jabber. + @param session Pointer to the transport_session. + @param msg Pointer to a transport_message enclosing the message. + @return 0 if successful, or -1 upon error. +*/ +int session_send_msg( transport_session* session, transport_message* msg ) { if( ! session ) { return -1; } @@ -219,39 +273,66 @@ int session_send_msg( } -/* connects to server and connects to jabber */ -int session_connect( transport_session* session, - const char* username, const char* password, +/** + @brief Connect to the Jabber server as a client and open a Jabber session. + @param session Pointer to a transport_session. + @param username Jabber user name. + @param password Jabber password. + @param resource name of Jabber resource. + @param connect_timeout Timeout interval, in seconds, for receiving data (see notes). + @param auth_type An enum: either AUTH_PLAIN or AUTH_DIGEST (see notes). + @return 1 if successful, or 0 upon error. + + If @a connect_timeout is -1, wait indefinitely for input activity to appear. If + @a connect_timeout is zero, don't wait at all. If @a timeout is positive, wait that + number of seconds before timing out. If @a connect_timeout has a negative value other + than -1, the results are not well defined. + + If we connect as a Jabber component, we send the password as an SHA1 hash. Otherwise + we look at the @a auth_type. If it's AUTH_PLAIN, we send the password as plaintext; if + it's AUTH_DIGEST, we send it as a hash. + + At this writing, we only use AUTH_DIGEST. +*/ +int session_connect( transport_session* session, + const char* username, const char* password, const char* resource, int connect_timeout, enum TRANSPORT_AUTH_TYPE auth_type ) { int size1 = 0; int size2 = 0; - if( ! session ) { - osrfLogWarning(OSRF_LOG_MARK, "session is null in connect" ); - return 0; + if( ! session ) { + osrfLogWarning(OSRF_LOG_MARK, "session is null in session_connect()" ); + return 0; } + if( session->sock_id != 0 ) { + osrfLogWarning(OSRF_LOG_MARK, "transport session is already open, on socket %d", + session->sock_id ); + return 0; + } - char* server = session->server; - - if( ! session->sock_id ) { - - if(session->port > 0) { - if( (session->sock_id = socket_open_tcp_client( - session->sock_mgr, session->port, session->server)) <= 0 ) - return 0; - - } else if(session->unix_path != NULL) { - if( (session->sock_id = socket_open_unix_client( - session->sock_mgr, session->unix_path)) <= 0 ) + // Open a client socket connecting to the Jabber server + if(session->port > 0) { // use TCP + session->sock_id = socket_open_tcp_client( + session->sock_mgr, session->port, session->server ); + if( session->sock_id <= 0 ) { + session->sock_id = 0; return 0; } - else { - osrfLogWarning( OSRF_LOG_MARK, "Can't open session: no port or unix path" ); + } else if(session->unix_path != NULL) { // use UNIX domain + session->sock_id = socket_open_unix_client( session->sock_mgr, session->unix_path ); + if( session->sock_id <= 0 ) { + session->sock_id = 0; return 0; } } + else { + osrfLogWarning( OSRF_LOG_MARK, "Can't open session: no port or unix path" ); + return 0; + } + + const char* server = session->server; if( session->component ) { @@ -259,8 +340,8 @@ int session_connect( transport_session* session, char our_hostname[HOST_NAME_MAX + 1] = ""; gethostname(our_hostname, sizeof(our_hostname) ); our_hostname[HOST_NAME_MAX] = '\0'; - size1 = 150 + strlen( server ); - char stanza1[ size1 ]; + size1 = 150 + strlen( username ) + strlen( our_hostname ); + char stanza1[ size1 ]; snprintf( stanza1, sizeof(stanza1), "", @@ -271,15 +352,17 @@ int session_connect( transport_session* session, if( socket_send( session->sock_id, stanza1 ) ) { osrfLogWarning(OSRF_LOG_MARK, "error sending"); + socket_disconnect( session->sock_mgr, session->sock_id ); + session->sock_id = 0; return 0; } - + /* wait for reply */ socket_wait(session->sock_mgr, connect_timeout, session->sock_id); - + /* server acknowledges our existence, now see if we can login */ if( session->state_machine->connecting == CONNECTING_2 ) { - + int ss = session->session_id->n_used + strlen(password) + 5; char hashstuff[ss]; snprintf( hashstuff, sizeof(hashstuff), "%s%s", session->session_id->buf, password ); @@ -288,9 +371,11 @@ int session_connect( transport_session* session, size2 = 100 + strlen( hash ); char stanza2[ size2 ]; snprintf( stanza2, sizeof(stanza2), "%s", hash ); - + if( socket_send( session->sock_id, stanza2 ) ) { osrfLogWarning(OSRF_LOG_MARK, "error sending"); + socket_disconnect( session->sock_mgr, session->sock_id ); + session->sock_id = 0; return 0; } } @@ -299,17 +384,18 @@ int session_connect( transport_session* session, /* the first Jabber connect stanza */ size1 = 100 + strlen( server ); - char stanza1[ size1 ]; - snprintf( stanza1, sizeof(stanza1), + char stanza1[ size1 ]; + snprintf( stanza1, sizeof(stanza1), "", server ); - /* send the first stanze */ session->state_machine->connecting = CONNECTING_1; if( socket_send( session->sock_id, stanza1 ) ) { osrfLogWarning(OSRF_LOG_MARK, "error sending"); + socket_disconnect( session->sock_mgr, session->sock_id ); + session->sock_id = 0; return 0; } @@ -320,17 +406,19 @@ int session_connect( transport_session* session, if( auth_type == AUTH_PLAIN ) { /* the second jabber connect stanza including login info*/ - size2 = 150 + strlen( username ) + strlen(password) + strlen(resource); + size2 = 150 + strlen( username ) + strlen( password ) + strlen( resource ); char stanza2[ size2 ]; - snprintf( stanza2, sizeof(stanza2), + snprintf( stanza2, sizeof(stanza2), "" "%s%s%s", username, password, resource ); - + /* server acknowledges our existence, now see if we can login */ if( session->state_machine->connecting == CONNECTING_2 ) { if( socket_send( session->sock_id, stanza2 ) ) { osrfLogWarning(OSRF_LOG_MARK, "error sending"); + socket_disconnect( session->sock_mgr, session->sock_id ); + session->sock_id = 0; return 0; } } @@ -344,35 +432,45 @@ int session_connect( transport_session* session, char* hash = shahash( hashstuff ); /* the second jabber connect stanza including login info*/ - size2 = 150 + strlen( hash ) + strlen(password) + strlen(resource); + size2 = 150 + strlen( username ) + strlen( hash ) + strlen(resource); char stanza2[ size2 ]; - snprintf( stanza2, sizeof(stanza2), + snprintf( stanza2, sizeof(stanza2), "" "%s%s%s", username, hash, resource ); - + /* server acknowledges our existence, now see if we can login */ if( session->state_machine->connecting == CONNECTING_2 ) { if( socket_send( session->sock_id, stanza2 ) ) { osrfLogWarning(OSRF_LOG_MARK, "error sending"); + socket_disconnect( session->sock_mgr, session->sock_id ); + session->sock_id = 0; return 0; } } + } else { + osrfLogWarning(OSRF_LOG_MARK, "Invalid auth_type parameter: %d", + (int) auth_type ); + socket_disconnect( session->sock_mgr, session->sock_id ); + session->sock_id = 0; + return 0; } } // not component - /* wait for reply */ + /* wait for reply to login request */ socket_wait( session->sock_mgr, connect_timeout, session->sock_id ); if( session->state_machine->connected ) { /* yar! */ return 1; + } else { + socket_disconnect( session->sock_mgr, session->sock_id ); + session->sock_id = 0; + return 0; } - - return 0; } // --------------------------------------------------------------------------------- @@ -392,7 +490,7 @@ static void startElementHandler( transport_session* ses = (transport_session*) session; if( ! ses ) { return; } - + if( strcmp( (char*) name, "message" ) == 0 ) { ses->state_machine->in_message = 1; buffer_add( ses->from_buffer, get_xml_attr( atts, "from" ) ); @@ -415,12 +513,12 @@ static void startElementHandler( ses->state_machine->in_message_body = 1; return; } - + if( strcmp( (char*) name, "subject" ) == 0 ) { ses->state_machine->in_subject = 1; return; } - + if( strcmp( (char*) name, "thread" ) == 0 ) { ses->state_machine->in_thread = 1; return; @@ -468,7 +566,7 @@ static void startElementHandler( ses->state_machine->in_message_error = 1; buffer_add( ses->message_error_type, get_xml_attr( atts, "type" ) ); ses->message_error_code = atoi( get_xml_attr( atts, "code" ) ); - osrfLogInfo( OSRF_LOG_MARK, "Received message with type %s and code %s", + osrfLogInfo( OSRF_LOG_MARK, "Received message with type %s and code %s", get_xml_attr( atts, "type"), get_xml_attr( atts, "code") ); return; } @@ -476,7 +574,7 @@ static void startElementHandler( if( strcmp( (char*) name, "iq" ) == 0 ) { ses->state_machine->in_iq = 1; - if( strcmp( get_xml_attr(atts, "type"), "result") == 0 + if( strcmp( get_xml_attr(atts, "type"), "result") == 0 && ses->state_machine->connecting == CONNECTING_2 ) { ses->state_machine->connected = 1; ses->state_machine->connecting = 0; @@ -525,18 +623,18 @@ static void endElementHandler( void *session, const xmlChar *name) { if( ses->message_callback ) { /* here it's ok to pass in the raw buffers because - message_init allocates new space for the chars + message_init allocates new space for the chars passed in */ - transport_message* msg = message_init( - ses->body_buffer->buf, + transport_message* msg = message_init( + ses->body_buffer->buf, ses->subject_buffer->buf, - ses->thread_buffer->buf, - ses->recipient_buffer->buf, + ses->thread_buffer->buf, + ses->recipient_buffer->buf, ses->from_buffer->buf ); - message_set_router_info( msg, - ses->router_from_buffer->buf, - ses->router_to_buffer->buf, + message_set_router_info( msg, + ses->router_from_buffer->buf, + ses->router_to_buffer->buf, ses->router_class_buffer->buf, ses->router_command_buffer->buf, ses->router_broadcast ); @@ -555,7 +653,7 @@ static void endElementHandler( void *session, const xmlChar *name) { reset_session_buffers( session ); return; } - + if( strcmp( (const char*) name, "body" ) == 0 ) { ses->state_machine->in_message_body = 0; return; @@ -570,7 +668,7 @@ static void endElementHandler( void *session, const xmlChar *name) { ses->state_machine->in_thread = 0; return; } - + if( strcmp( (const char*) name, "iq" ) == 0 ) { ses->state_machine->in_iq = 0; if( ses->message_error_code > 0 ) { @@ -673,7 +771,7 @@ static void parseWarningHandler( void *session, const char* msg, ... ) { fprintf(stdout, "transport_session XML WARNING"); vfprintf(stdout, msg, args); va_end(args); - fprintf(stderr, "XML WARNING: %s\n", msg ); + fprintf(stderr, "XML WARNING: %s\n", msg ); } static void parseErrorHandler( void *session, const char* msg, ... ){ @@ -683,14 +781,21 @@ static void parseErrorHandler( void *session, const char* msg, ... ){ fprintf(stdout, "transport_session XML ERROR"); vfprintf(stdout, msg, args); va_end(args); - fprintf(stderr, "XML ERROR: %s\n", msg ); + fprintf(stderr, "XML ERROR: %s\n", msg ); } +/** + @brief Disconnect from Jabber, and close the socket. + @param session Pointer to the transport_session to be disconnected. + @return 0 in all cases. +*/ int session_disconnect( transport_session* session ) { - if( session == NULL ) { return 0; } - socket_send(session->sock_id, ""); - socket_disconnect(session->sock_mgr, session->sock_id); + if( session && session->sock_id != 0 ) { + socket_send(session->sock_id, ""); + socket_disconnect(session->sock_mgr, session->sock_id); + session->sock_id = 0; + } return 0; }