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

svn at svn.open-ils.org svn at svn.open-ils.org
Sat Oct 17 13:15:58 EDT 2009


Author: scottmk
Date: 2009-10-17 13:15:54 -0400 (Sat, 17 Oct 2009)
New Revision: 1820

Modified:
   trunk/src/libopensrf/socket_bundle.c
Log:
1. In socket_connected(): if the select() fails because it is interrupted
by a signal, it doesn't mean that the socket is invalid, so try again.

2. In _socket_handle_client_data(): remove two unnecessary calls to the
osrf_clearbuf macro.

3. Add more doxygen-style comments to document the functions; edit a few
existing comments in various ways.

M    src/libopensrf/socket_bundle.c


Modified: trunk/src/libopensrf/socket_bundle.c
===================================================================
--- trunk/src/libopensrf/socket_bundle.c	2009-10-13 23:07:01 UTC (rev 1819)
+++ trunk/src/libopensrf/socket_bundle.c	2009-10-17 17:15:54 UTC (rev 1820)
@@ -1,3 +1,8 @@
+/**
+	@file socket_bundle.c
+	@brief Collection of socket-handling routines.
+*/
+
 #include <opensrf/socket_bundle.h>
 
 struct socket_node_struct {
@@ -99,7 +104,7 @@
 	@param listen_ip The IP address to bind to; or, NULL for INADDR_ANY.
 	@return The socket fd if successful; otherwise -1.
 
-	Calls: socket(), bind(), and listen().
+	Calls: socket(), bind(), and listen().  Creates a SERVER_SOCKET.
 */
 int socket_open_tcp_server(socket_manager* mgr, int port, const char* listen_ip) {
 
@@ -161,8 +166,10 @@
 	@param path Name of the socket within the file system.
 	@return The socket fd if successful; otherwise -1.
 
-	Calls: socket(), bind(), listen().
-*/
+	Calls: socket(), bind(), listen().  Creates a SERVER_SOCKET.
+
+	Applies socket option TCP_NODELAY in order to reduce latency.
+ */
 int socket_open_unix_server(socket_manager* mgr, const char* path) {
 	if(mgr == NULL || path == NULL) return -1;
 
@@ -229,7 +236,7 @@
 	@param listen_ip The IP address to bind to, or NULL for INADDR_ANY.
 	@return The socket fd if successful; otherwise -1.
 
-	Calls: socket(), bind().
+	Calls: socket(), bind().  Creates a SERVER_SOCKET.
 */
 int socket_open_udp_server( 
 		socket_manager* mgr, int port, const char* listen_ip ) {
@@ -276,8 +283,10 @@
 	@param dest_addr Host name or IP address of the server to which we are connecting.
 	@return The socket fd if successful; otherwise -1.
 
-	Calls: getaddrinfo(), socket(), connect().
-*/
+	Calls: getaddrinfo(), socket(), connect().  Creates a CLIENT_SOCKET.
+
+	Applies socket option TCP_NODELAY in order to reduce latency.
+ */
 int socket_open_tcp_client(socket_manager* mgr, int port, const char* dest_addr) {
 
 	struct sockaddr_in remoteAddr;
@@ -355,7 +364,7 @@
 	@param mgr Pointer to the socket_manager that will own the socket.
 	@return The socket fd if successful; otherwise -1.
 
-	Calls: socket().
+	Calls: socket().  Creates a CLIENT_SOCKET.
 */
 int socket_open_udp_client( socket_manager* mgr ) {
 
@@ -380,7 +389,7 @@
 	@param sock_path Name of the socket within the file system.
 	@return The socket fd if successful; otherwise -1.
 
-	Calls: socket(), connect().
+	Calls: socket(), connect().  Creates a CLIENT_SOCKET.
 */
 int socket_open_unix_client(socket_manager* mgr, const char* sock_path) {
 
@@ -445,7 +454,7 @@
 	@param sock_fd The file descriptor whose socket_node is to be removed.
 
 	This function does @em not close the socket.  It just removes a node from the list, and
-	frees it.  It is the responsibility of the calling code to close the socket.
+	frees it.  The disposition of the socket is the responsibility of the calling code.
 */
 static void socket_remove_node(socket_manager* mgr, int sock_fd) {
 
@@ -499,12 +508,27 @@
 	osrfLogDebug( OSRF_LOG_MARK, "]");
 }
 
-/* sends the given data to the given socket */
+/**
+	@brief Send a nul-terminated string over a socket.
+	@param sock_fd The file descriptor for the socket.
+	@param data Pointer to the string to be sent.
+	@return 0 if successful, -1 if not.
+
+	This function is a thin wrapper for _socket_send().
+*/
 int socket_send(int sock_fd, const char* data) {
 	return _socket_send( sock_fd, data, 0);
 }
 
-/* utility method */
+/**
+	@brief Send a nul-terminated string over a socket.
+	@param sock_fd The file descriptor for the socket.
+	@param data Pointer to the string to be sent.
+	@param flags A set of bitflags to be passed to send().
+	@return 0 if successful, -1 if not.
+
+	This function is the final common pathway for all outgoing socket traffic.
+*/
 static int _socket_send(int sock_fd, const char* data, int flags) {
 
 	signal(SIGPIPE, SIG_IGN); /* in case a unix socket was closed */
@@ -512,7 +536,7 @@
 	errno = 0;
 	size_t r = send( sock_fd, data, strlen(data), flags );
 	int local_errno = errno;
-	
+
 	if( r == -1 ) {
 		osrfLogWarning( OSRF_LOG_MARK, "_socket_send(): Error sending data with return %d", r );
 		osrfLogWarning( OSRF_LOG_MARK, "Last Sys Error: %s", strerror(local_errno));
@@ -532,18 +556,22 @@
 //}
 
 
-/*
- * Waits at most usecs microseconds for the send buffer of the given
- * socket to accept new data.  This does not guarantee that the 
- * socket will accept all the data we want to give it.
- */
+/**
+	@brief Wait for a socket to be ready to send, and then send a string over it.
+	@param sock_fd File descriptor of the socket.
+	@param data Pointer to a nul-terminated string to be sent.
+	@param usecs How long to wait, in microseconds, before timing out.
+	@return 0 if successful, -1 if not.
+
+	The socket may not accept all the data we want to give it.
+*/
 int socket_send_timeout( int sock_fd, const char* data, int usecs ) {
 
 	fd_set write_set;
 	FD_ZERO( &write_set );
 	FD_SET( sock_fd, &write_set );
 
-	int mil = 1000000;
+	const int mil = 1000000;
 	int secs = (int) usecs / mil;
 	usecs = usecs - (secs * mil);
 
@@ -565,6 +593,13 @@
 
 /* disconnects the node with the given sock_fd and removes
 	it from the socket set */
+/**
+	@brief Close a socket, and remove it from the socket_manager's list.
+	@param mgr Pointer to the socket_manager.
+	@param sock_fd File descriptor for the socket to be closed.
+
+	We close the socket before determining whether it belongs to the socket_manager in question.
+*/
 void socket_disconnect(socket_manager* mgr, int sock_fd) {
 	osrfLogInternal( OSRF_LOG_MARK, "Closing socket %d", sock_fd);
 	close( sock_fd );
@@ -572,15 +607,34 @@
 }
 
 
-/* we assume that if select() fails, the socket is no longer valid */
+/**
+	@brief Determine whether a socket is valid.
+	@param sock_fd File descriptor for the socket.
+	@return 1 if the socket is valid, or 0 if it isn't.
+
+	The test is based on a call to select().  If the socket is valid but is not ready to be
+	written to, we wait until it is ready, then return 1.
+
+	If the select() fails, it may be because it was interrupted by a signal.  In that case
+	we try again.  Otherwise we assume that the socket is no longer valid.  This can happen
+	if, for example, the other end of a connection has closed the connection.
+
+	The select() can also fail if it is unable to allocate enough memory for its own internal
+	use.  If that happens, we may erroneously report a valid socket as invalid, but we
+	probably wouldn't be able to use it anyway if we're that close to exhausting memory.
+*/
 int socket_connected(int sock_fd) {
 	fd_set read_set;
 	FD_ZERO( &read_set );
 	FD_SET( sock_fd, &read_set );
-	if( select( sock_fd + 1, &read_set, NULL, NULL, NULL) == -1 ) 
-		return 0;
-	return 1;
-
+	while( 1 ) {
+		if( select( sock_fd + 1, &read_set, NULL, NULL, NULL) == -1 )
+			return 0;
+		else if( EINTR == errno )
+			continue;
+		else
+			return 1;
+	}
 }
 
 /* this only waits on the server socket and does not handle the actual
@@ -601,7 +655,8 @@
 
 		// If timeout is -1, we block indefinitely
 		if( (retval = select( sock_fd + 1, &read_set, NULL, NULL, NULL)) == -1 ) {
-			osrfLogDebug( OSRF_LOG_MARK, "Call to select() interrupted: Sys Error: %s", strerror(errno));
+			osrfLogDebug( OSRF_LOG_MARK, "Call to select() interrupted: Sys Error: %s",
+						  strerror(errno));
 			return -1;
 		}
 
@@ -756,7 +811,7 @@
 	return -1;
 }
 
-
+/* Creates a CLIENT_SOCKET. */
 static int _socket_handle_new_client(socket_manager* mgr, socket_node* node) {
 	if(mgr == NULL || node == NULL) return -1;
 
@@ -782,6 +837,25 @@
 }
 
 
+/**
+	@brief Receive data on a streaming socket.
+	@param mgr Pointer to the socket_manager that owns the socket_node.
+	@param node Pointer to the socket_node that owns the socket.
+	@return 0 if successful, or -1 upon failure.
+
+	Receive one or more buffers until no more bytes are available for receipt.  Add a
+	terminal nul to each buffer and pass it to a callback function previously defined by the
+	application to the socket_manager.
+
+	If the sender closes the connection, call another callback function, if one has been
+	defined.
+
+	Even when the function returns successfully, the received message may not be complete --
+	there may be more data that hasn't arrived yet.  It is the responsibility of the
+	calling code to recognize message boundaries.
+
+	Called only for a CLIENT_SOCKET.
+*/
 static int _socket_handle_client_data(socket_manager* mgr, socket_node* node) {
 	if(mgr == NULL || node == NULL) return -1;
 
@@ -789,26 +863,27 @@
 	int read_bytes;
 	int sock_fd = node->sock_fd;
 
-	osrf_clearbuf(buf, sizeof(buf));
 	set_fl(sock_fd, O_NONBLOCK);
 
-	osrfLogInternal( OSRF_LOG_MARK, "%ld : Received data at %f\n", (long) getpid(), get_timestamp_millis());
+	osrfLogInternal( OSRF_LOG_MARK, "%ld : Received data at %f\n", 
+			(long) getpid(), get_timestamp_millis());
 
 	while( (read_bytes = recv(sock_fd, buf, RBUFSIZE-1, 0) ) > 0 ) {
 		buf[read_bytes] = '\0';
-		osrfLogInternal( OSRF_LOG_MARK, "Socket %d Read %d bytes and data: %s", sock_fd, read_bytes, buf);
+		osrfLogInternal( OSRF_LOG_MARK, "Socket %d Read %d bytes and data: %s",
+				sock_fd, read_bytes, buf);
 		if(mgr->data_received)
 			mgr->data_received(mgr->blob, mgr, sock_fd, buf, node->parent_id);
-
-		osrf_clearbuf(buf, sizeof(buf));
 	}
-    int local_errno = errno; /* capture errno as set by recv() */
+	int local_errno = errno; /* capture errno as set by recv() */
 
 	if(socket_find_node(mgr, sock_fd)) {  /* someone may have closed this socket */
 		clr_fl(sock_fd, O_NONBLOCK); 
 		if(read_bytes < 0) { 
-			if(local_errno != EAGAIN) 
-				osrfLogWarning(OSRF_LOG_MARK,  " * Error reading socket with error %s", strerror(local_errno));
+			// EAGAIN would have meant that no more data was available
+			if(local_errno != EAGAIN)   // but if that's not the case...
+				osrfLogWarning( OSRF_LOG_MARK, " * Error reading socket with error %s",
+					strerror(local_errno) );
 		}
 
 	} else { return -1; } /* inform the caller that this node has been tampered with */
@@ -825,6 +900,10 @@
 }
 
 
+/**
+	@brief Destroy a socket_manager, and close all of its sockets.
+	@param mgr Pointer to the socket_manager to be destroyed.
+*/
 void socket_manager_free(socket_manager* mgr) {
 	if(mgr == NULL) return;
 	socket_node* tmp;



More information about the opensrf-commits mailing list