[Opensrf-commits] r1822 - trunk/src/libopensrf (scottmk)

svn at svn.open-ils.org svn at svn.open-ils.org
Wed Oct 21 23:21:34 EDT 2009


Author: scottmk
Date: 2009-10-21 23:21:31 -0400 (Wed, 21 Oct 2009)
New Revision: 1822

Modified:
   trunk/src/libopensrf/transport_session.c
Log:
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


Modified: trunk/src/libopensrf/transport_session.c
===================================================================
--- trunk/src/libopensrf/transport_session.c	2009-10-18 02:00:18 UTC (rev 1821)
+++ trunk/src/libopensrf/transport_session.c	2009-10-22 03:21:31 UTC (rev 1822)
@@ -1,11 +1,18 @@
 #include <opensrf/transport_session.h>
 
+/**
+	@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 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 @@
 	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 @@
 	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 @@
 	/* 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 @@
 }
 
 
+/**
+	@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 @@
 }
 
 
+/**
+	@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 @@
 	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,48 +273,75 @@
 }
 
 
-/* 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 ) 
+	// 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 if(session->unix_path != NULL) {
-			if( (session->sock_id = socket_open_unix_client(
-				session->sock_mgr, session->unix_path)) <= 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 ) {
 
 		/* the first Jabber connect stanza */
 		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),
 				"<stream:stream version='1.0' xmlns:stream='http://etherx.jabber.org/streams' "
 				"xmlns='jabber:component:accept' to='%s' from='%s' xml:lang='en'>",
@@ -271,15 +352,17 @@
 
 		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 @@
 			size2 = 100 + strlen( hash );
 			char stanza2[ size2 ];
 			snprintf( stanza2, sizeof(stanza2), "<handshake>%s</handshake>", 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 @@
 
 		/* the first Jabber connect stanza */
 		size1 = 100 + strlen( server );
-		char stanza1[ size1 ]; 
-		snprintf( stanza1, sizeof(stanza1), 
+		char stanza1[ size1 ];
+		snprintf( stanza1, sizeof(stanza1),
 				"<stream:stream to='%s' xmlns='jabber:client' "
 				"xmlns:stream='http://etherx.jabber.org/streams'>",
 			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 @@
 		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),
 					"<iq id='123456789' type='set'><query xmlns='jabber:iq:auth'>"
 					"<username>%s</username><password>%s</password><resource>%s</resource></query></iq>",
 					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 @@
 			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),
 					"<iq id='123456789' type='set'><query xmlns='jabber:iq:auth'>"
 					"<username>%s</username><digest>%s</digest><resource>%s</resource></query></iq>",
 					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 @@
 	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 @@
 			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 @@
 		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 <error> message with type %s and code %s", 
+		osrfLogInfo( OSRF_LOG_MARK, "Received <error> message with type %s and code %s",
 			get_xml_attr( atts, "type"), get_xml_attr( atts, "code") );
 		return;
 	}
@@ -476,7 +574,7 @@
 	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 @@
 		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 @@
 		reset_session_buffers( session );
 		return;
 	}
-	
+
 	if( strcmp( (const char*) name, "body" ) == 0 ) {
 		ses->state_machine->in_message_body = 0;
 		return;
@@ -570,7 +668,7 @@
 		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 @@
 	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 @@
 	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, "</stream:stream>");
-	socket_disconnect(session->sock_mgr, session->sock_id);
+	if( session && session->sock_id != 0 ) {
+		socket_send(session->sock_id, "</stream:stream>");
+		socket_disconnect(session->sock_mgr, session->sock_id);
+		session->sock_id = 0;
+	}
 	return 0;
 }
 



More information about the opensrf-commits mailing list