3 @brief Collection of socket-handling routines.
6 #include <opensrf/socket_bundle.h>
8 #define LISTENER_SOCKET 1
15 @brief Represents a socket owned by a socket_manager.
17 A socket_manager owns a linked list of socket_nodes representing the collection of
18 sockets that it manages. It may contain a single socket for passing data, or it may
19 contain a listener socket (conceivably more than one) together with any associated
20 sockets created by accept() for communicating with a client.
22 struct socket_node_struct {
23 int endpoint; /**< Role of socket: LISTENER_SOCKET or DATA_SOCKET. */
24 int addr_type; /**< INET or UNIX. */
25 int sock_fd; /**< File descriptor for socket. */
26 int parent_id; /**< For a socket created by accept() for a listener socket,
27 this is the listener socket we spawned from. */
28 struct socket_node_struct* next; /**< Linkage pointer for linked list. */
31 /** @brief Size of buffer used to read from the sockets */
34 static socket_node* _socket_add_node(socket_manager* mgr,
35 int endpoint, int addr_type, int sock_fd, int parent_id );
36 static socket_node* socket_find_node(socket_manager* mgr, int sock_fd);
37 static void socket_remove_node(socket_manager*, int sock_fd);
38 static int _socket_send(int sock_fd, const char* data, int flags);
39 static int _socket_handle_new_client(socket_manager* mgr, socket_node* node);
40 static int _socket_handle_client_data(socket_manager* mgr, socket_node* node);
43 /* --------------------------------------------------------------------
45 -------------------------------------------------------------------- */
48 void printme(void* blob, socket_manager* mgr,
49 int sock_fd, char* data, int parent_id) {
51 fprintf(stderr, "Got data from socket %d with parent %d => %s",
52 sock_fd, parent_id, data );
54 socket_send(sock_fd, data);
57 socket_disconnect(mgr, sock_fd);
58 _socket_print_list(mgr);
62 int main(int argc, char* argv[]) {
63 socket_manager manager;
64 memset(&manager, 0, sizeof(socket_manager));
69 manager.data_received = &printme;
70 socket_open_tcp_server(&manager, port);
73 socket_wait_all(&manager, -1);
78 /* -------------------------------------------------------------------- */
82 @brief Create a new socket_node and add it to a socket_manager's list.
83 @param mgr Pointer to the socket_manager.
84 @param endpoint LISTENER_SOCKET or DATA_SOCKET, denoting how the socket is to be used.
85 @param addr_type address type: INET or UNIX.
86 @param sock_fd sock_fd for the new socket_node.
87 @param parent_id parent_id for the new node.
88 @return Pointer to the new socket_node.
90 If @a parent_id is negative, the new socket_node receives a parent_id of 0.
92 static socket_node* _socket_add_node(socket_manager* mgr,
93 int endpoint, int addr_type, int sock_fd, int parent_id ) {
95 if(mgr == NULL) return NULL;
96 osrfLogInternal( OSRF_LOG_MARK, "Adding socket node with fd %d", sock_fd);
97 socket_node* new_node = safe_malloc(sizeof(socket_node));
99 new_node->endpoint = endpoint;
100 new_node->addr_type = addr_type;
101 new_node->sock_fd = sock_fd;
102 new_node->next = NULL;
103 new_node->parent_id = 0;
105 new_node->parent_id = parent_id;
107 new_node->next = mgr->socket;
108 mgr->socket = new_node;
113 @brief Create an TCP INET listener socket and add it to a socket_manager's list.
114 @param mgr Pointer to the socket manager that will own the socket.
115 @param port The port number to bind to.
116 @param listen_ip The IP address to bind to; or, NULL for INADDR_ANY.
117 @return The socket's file descriptor if successful; otherwise -1.
119 Calls: socket(), bind(), and listen(). Creates a LISTENER_SOCKET.
121 int socket_open_tcp_server(socket_manager* mgr, int port, const char* listen_ip) {
124 osrfLogWarning( OSRF_LOG_MARK, "socket_open_tcp_server(): NULL mgr");
129 struct sockaddr_in server_addr;
131 server_addr.sin_family = AF_INET;
133 if(listen_ip != NULL) {
135 if( inet_aton( listen_ip, &addr ) )
136 server_addr.sin_addr.s_addr = addr.s_addr;
138 osrfLogError( OSRF_LOG_MARK, "Listener address is invalid: %s", listen_ip );
142 server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
145 server_addr.sin_port = htons(port);
148 sock_fd = socket(AF_INET, SOCK_STREAM, 0);
150 osrfLogWarning( OSRF_LOG_MARK, "socket_open_tcp_server(): Unable to create TCP socket: %s",
156 if(bind( sock_fd, (struct sockaddr*) &server_addr, sizeof(server_addr)) < 0) {
157 osrfLogWarning( OSRF_LOG_MARK, "socket_open_tcp_server(): cannot bind to port %d: %s",
158 port, strerror( errno ) );
164 if(listen(sock_fd, 20) == -1) {
165 osrfLogWarning( OSRF_LOG_MARK, "socket_open_tcp_server(): listen() returned error: %s",
171 _socket_add_node(mgr, LISTENER_SOCKET, INET, sock_fd, 0);
176 @brief Create a UNIX domain listener socket and add it to the socket_manager's list.
177 @param mgr Pointer to the socket_manager that will own the socket.
178 @param path Name of the socket within the file system.
179 @return The socket's file descriptor if successful; otherwise -1.
181 Calls: socket(), bind(), listen(). Creates a LISTENER_SOCKET.
183 Apply socket option TCP_NODELAY in order to reduce latency.
185 int socket_open_unix_server(socket_manager* mgr, const char* path) {
186 if(mgr == NULL || path == NULL) return -1;
188 osrfLogDebug( OSRF_LOG_MARK, "opening unix socket at %s", path);
190 struct sockaddr_un server_addr;
192 if(strlen(path) > sizeof(server_addr.sun_path) - 1)
194 osrfLogWarning( OSRF_LOG_MARK, "socket_open_unix_server(): path too long: %s",
200 sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
202 osrfLogWarning( OSRF_LOG_MARK, "socket_open_unix_server(): socket() failed: %s",
207 server_addr.sun_family = AF_UNIX;
208 strcpy(server_addr.sun_path, path);
211 if( bind(sock_fd, (struct sockaddr*) &server_addr,
212 sizeof(struct sockaddr_un)) < 0) {
213 osrfLogWarning( OSRF_LOG_MARK,
214 "socket_open_unix_server(): cannot bind to unix port %s: %s",
215 path, strerror( errno ) );
221 if(listen(sock_fd, 20) == -1) {
222 osrfLogWarning( OSRF_LOG_MARK, "socket_open_unix_server(): listen() returned error: %s",
228 osrfLogDebug( OSRF_LOG_MARK, "unix socket successfully opened");
232 /* causing problems with router for some reason ... */
233 //osrfLogDebug( OSRF_LOG_MARK, "Setting SO_REUSEADDR");
234 //setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
236 //osrfLogDebug( OSRF_LOG_MARK, "Setting TCP_NODELAY");
237 setsockopt(sock_fd, IPPROTO_TCP, TCP_NODELAY, &i, sizeof(i));
239 _socket_add_node(mgr, LISTENER_SOCKET, UNIX, sock_fd, 0);
245 @brief Create a UDP socket for a server, and add it to a socket_manager's list.
246 @param mgr Pointer to the socket_manager that will own the socket.
247 @param port The port number to bind to.
248 @param listen_ip The IP address to bind to, or NULL for INADDR_ANY.
249 @return The socket's file descriptor if successful; otherwise -1.
251 Calls: socket(), bind(). Creates a DATA_SOCKET.
253 int socket_open_udp_server(
254 socket_manager* mgr, int port, const char* listen_ip ) {
257 struct sockaddr_in server_addr;
259 server_addr.sin_family = AF_INET;
260 server_addr.sin_port = htons(port);
263 if( inet_aton( listen_ip, &addr ) )
264 server_addr.sin_addr.s_addr = addr.s_addr;
266 osrfLogError( OSRF_LOG_MARK, "UDP listener address is invalid: %s", listen_ip );
270 server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
273 if( (sockfd = socket( AF_INET, SOCK_DGRAM, 0 )) < 0 ) {
274 osrfLogWarning( OSRF_LOG_MARK, "Unable to create UDP socket: %s", strerror( errno ) );
279 if( (bind (sockfd, (struct sockaddr *) &server_addr,sizeof(server_addr))) ) {
280 osrfLogWarning( OSRF_LOG_MARK, "Unable to bind to UDP port %d: %s",
281 port, strerror( errno ) );
286 _socket_add_node(mgr, DATA_SOCKET, INET, sockfd, 0);
292 @brief Create a client TCP socket, connect with it, and add it to a socket_manager's list.
293 @param mgr Pointer to the socket_manager that will own the socket.
294 @param port What port number to connect to.
295 @param dest_addr Host name or IP address of the server to which we are connecting.
296 @return The socket's file descriptor if successful; otherwise -1.
298 Calls: getaddrinfo(), socket(), connect(). Creates a DATA_SOCKET.
300 Applies socket option TCP_NODELAY in order to reduce latency.
302 int socket_open_tcp_client(socket_manager* mgr, int port, const char* dest_addr) {
304 struct sockaddr_in remoteAddr;
307 // ------------------------------------------------------------------
308 // Get the IP address of the hostname (for TCP only)
309 // ------------------------------------------------------------------
310 struct addrinfo hints = { 0, 0, 0, 0, 0, NULL, NULL, NULL };
311 hints.ai_socktype = SOCK_STREAM;
312 struct addrinfo* addr_info = NULL;
314 int rc = getaddrinfo( dest_addr, NULL, &hints, &addr_info );
315 if( rc || ! addr_info ) {
316 osrfLogWarning( OSRF_LOG_MARK, "socket_open_tcp_client(): No Such Host => %s: %s",
317 dest_addr, gai_strerror( rc ) );
321 // Look for an address supporting IPv4. Someday we'll look for
322 // either IPv4 or IPv6, and branch according to what we find.
323 while( addr_info && addr_info->ai_family != PF_INET ) {
324 addr_info = addr_info->ai_next;
328 osrfLogWarning( OSRF_LOG_MARK,
329 "socket_open_tcp_client(): Host %s does not support IPV4", dest_addr );
333 // ------------------------------------------------------------------
335 // ------------------------------------------------------------------
337 if( (sock_fd = socket( AF_INET, SOCK_STREAM, 0 )) < 0 ) {
338 osrfLogWarning( OSRF_LOG_MARK, "socket_open_tcp_client(): Cannot create TCP socket: %s",
344 setsockopt(sock_fd, IPPROTO_TCP, TCP_NODELAY, &i, sizeof(i));
346 // ------------------------------------------------------------------
347 // Construct server info struct
348 // ------------------------------------------------------------------
349 memset( &remoteAddr, 0, sizeof(remoteAddr));
350 remoteAddr.sin_family = AF_INET;
351 remoteAddr.sin_port = htons( port );
352 struct sockaddr_in* ai_addr_in = (struct sockaddr_in*) addr_info->ai_addr;
353 remoteAddr.sin_addr.s_addr = ai_addr_in->sin_addr.s_addr;
355 freeaddrinfo( addr_info );
357 // ------------------------------------------------------------------
359 // ------------------------------------------------------------------
361 if( connect( sock_fd, (struct sockaddr*) &remoteAddr, sizeof( struct sockaddr_in ) ) < 0 ) {
362 osrfLogWarning( OSRF_LOG_MARK, "socket_open_tcp_client(): Cannot connect to server %s: %s",
363 dest_addr, strerror(errno) );
368 _socket_add_node(mgr, DATA_SOCKET, INET, sock_fd, -1 );
375 @brief Create a client UDP socket and add it to a socket_manager's list.
376 @param mgr Pointer to the socket_manager that will own the socket.
377 @return The socket's file descriptor if successful; otherwise -1.
379 Calls: socket(). Creates a DATA_SOCKET.
381 int socket_open_udp_client( socket_manager* mgr ) {
386 if( (sockfd = socket(AF_INET,SOCK_DGRAM,0)) < 0 ) {
387 osrfLogWarning( OSRF_LOG_MARK,
388 "socket_open_udp_client(): Unable to create UDP socket: %s", strerror( errno ) );
392 _socket_add_node(mgr, DATA_SOCKET, INET, sockfd, -1 );
399 @brief Create a UNIX domain client socket, connect with it, add it to the socket_manager's list
400 @param mgr Pointer to the socket_manager that will own the socket.
401 @param sock_path Name of the socket within the file system.
402 @return The socket's file descriptor if successful; otherwise -1.
404 Calls: socket(), connect(). Creates a DATA_SOCKET.
406 int socket_open_unix_client(socket_manager* mgr, const char* sock_path) {
409 struct sockaddr_un usock;
411 if(strlen(sock_path) > sizeof(usock.sun_path) - 1)
413 osrfLogWarning( OSRF_LOG_MARK, "socket_open_unix_client(): path too long: %s",
419 if( (sock_fd = socket( AF_UNIX, SOCK_STREAM, 0 )) < 0 ) {
420 osrfLogWarning( OSRF_LOG_MARK, "socket_open_unix_client(): Cannot create UNIX socket: %s", strerror( errno ) );
424 usock.sun_family = AF_UNIX;
425 strcpy( usock.sun_path, sock_path );
427 len = sizeof( usock.sun_family ) + strlen( usock.sun_path );
430 if( connect( sock_fd, (struct sockaddr *) &usock, len ) < 0 ) {
431 osrfLogWarning( OSRF_LOG_MARK, "Error connecting to unix socket: %s",
437 _socket_add_node(mgr, DATA_SOCKET, UNIX, sock_fd, -1 );
444 @brief Search a socket_manager's list for a socket node for a given file descriptor.
445 @param mgr Pointer to the socket manager.
446 @param sock_fd The file descriptor to be sought.
447 @return A pointer to the socket_node if found; otherwise NULL.
449 Traverse a linked list owned by the socket_manager.
451 static socket_node* socket_find_node(socket_manager* mgr, int sock_fd) {
452 if(mgr == NULL) return NULL;
453 socket_node* node = mgr->socket;
455 if(node->sock_fd == sock_fd)
462 /* removes the node with the given sock_fd from the list and frees it */
464 @brief Remove a socket node for a given fd from a socket_manager's list.
465 @param mgr Pointer to the socket_manager.
466 @param sock_fd The file descriptor whose socket_node is to be removed.
468 This function does @em not close the socket. It just removes a node from the list, and
469 frees it. The disposition of the socket is the responsibility of the calling code.
471 static void socket_remove_node(socket_manager* mgr, int sock_fd) {
473 if(mgr == NULL) return;
475 osrfLogDebug( OSRF_LOG_MARK, "removing socket %d", sock_fd);
477 socket_node* head = mgr->socket;
478 socket_node* tail = head;
479 if(head == NULL) return;
481 /* if removing the first node in the list */
482 if(head->sock_fd == sock_fd) {
483 mgr->socket = head->next;
490 /* if removing any other node */
492 if(head->sock_fd == sock_fd) {
493 tail->next = head->next;
504 @brief Write to the log: a list of socket_nodes in a socket_manager's list.
505 @param mgr Pointer to the socket_manager.
507 For testing and debugging.
509 The messages are issued as DEBG messages, and show each file descriptor and its parent.
511 void _socket_print_list(socket_manager* mgr) {
512 if(mgr == NULL) return;
513 socket_node* node = mgr->socket;
514 osrfLogDebug( OSRF_LOG_MARK, "socket_node list: [");
516 osrfLogDebug( OSRF_LOG_MARK, "sock_fd: %d | parent_id: %d",
517 node->sock_fd, node->parent_id);
520 osrfLogDebug( OSRF_LOG_MARK, "]");
524 @brief Send a nul-terminated string over a socket.
525 @param sock_fd The file descriptor for the socket.
526 @param data Pointer to the string to be sent.
527 @return 0 if successful, -1 if not.
529 This function is a thin wrapper for _socket_send().
531 int socket_send(int sock_fd, const char* data) {
532 return _socket_send( sock_fd, data, 0);
536 @brief Send a nul-terminated string over a socket.
537 @param sock_fd The file descriptor for the socket.
538 @param data Pointer to the string to be sent.
539 @param flags A set of bitflags to be passed to send().
540 @return 0 if successful, -1 if not.
542 This function is the final common pathway for all outgoing socket traffic.
544 static int _socket_send(int sock_fd, const char* data, int flags) {
546 signal(SIGPIPE, SIG_IGN); /* in case a unix socket was closed */
549 size_t r = send( sock_fd, data, strlen(data), flags );
550 int local_errno = errno;
553 osrfLogWarning( OSRF_LOG_MARK, "_socket_send(): Error sending data with return %d", r );
554 osrfLogWarning( OSRF_LOG_MARK, "Last Sys Error: %s", strerror(local_errno));
562 /* sends the given data to the given socket.
563 * sets the send flag MSG_DONTWAIT which will allow the
564 * process to continue even if the socket buffer is full
565 * returns 0 on success, -1 otherwise */
566 //int socket_send_nowait( int sock_fd, const char* data) {
567 // return _socket_send( sock_fd, data, MSG_DONTWAIT);
572 @brief Wait for a socket to be ready to send, and then send a string over it.
573 @param sock_fd File descriptor of the socket.
574 @param data Pointer to a nul-terminated string to be sent.
575 @param usecs How long to wait, in microseconds, before timing out.
576 @return 0 if successful, -1 if not.
578 The socket may not accept all the data we want to give it.
580 int socket_send_timeout( int sock_fd, const char* data, int usecs ) {
583 FD_ZERO( &write_set );
584 FD_SET( sock_fd, &write_set );
586 const int mil = 1000000;
587 int secs = (int) usecs / mil;
588 usecs = usecs - (secs * mil);
595 int ret = select( sock_fd + 1, NULL, &write_set, NULL, &tv);
596 if( ret > 0 ) return _socket_send( sock_fd, data, 0);
598 osrfLogError(OSRF_LOG_MARK, "socket_send_timeout(): "
599 "timed out on send for socket %d after %d secs, %d usecs: %s",
600 sock_fd, secs, usecs, strerror( errno ) );
606 /* disconnects the node with the given sock_fd and removes
607 it from the socket set */
609 @brief Close a socket, and remove it from the socket_manager's list.
610 @param mgr Pointer to the socket_manager.
611 @param sock_fd File descriptor for the socket to be closed.
613 We close the socket before determining whether it belongs to the socket_manager in question.
615 void socket_disconnect(socket_manager* mgr, int sock_fd) {
616 osrfLogInternal( OSRF_LOG_MARK, "Closing socket %d", sock_fd);
618 socket_remove_node(mgr, sock_fd);
623 @brief Determine whether a socket is valid.
624 @param sock_fd File descriptor for the socket.
625 @return 1 if the socket is valid, or 0 if it isn't.
627 The test is based on a call to select(). If the socket is valid but is not ready to be
628 written to, we wait until it is ready, then return 1.
630 If the select() fails, it may be because it was interrupted by a signal. In that case
631 we try again. Otherwise we assume that the socket is no longer valid. This can happen
632 if, for example, the other end of a connection has closed the connection.
634 The select() can also fail if it is unable to allocate enough memory for its own internal
635 use. If that happens, we may erroneously report a valid socket as invalid, but we
636 probably wouldn't be able to use it anyway if we're that close to exhausting memory.
638 int socket_connected(int sock_fd) {
640 FD_ZERO( &read_set );
641 FD_SET( sock_fd, &read_set );
643 if( select( sock_fd + 1, &read_set, NULL, NULL, NULL) == -1 )
645 else if( EINTR == errno )
653 @brief Look for input on a given socket. If you find some, react to it.
654 @param mgr Pointer to the socket_manager that presumably owns the socket.
655 @param timeout Timeout interval, in seconds (see notes).
656 @param sock_fd The file descriptor to look at.
657 @return 0 if successful, or -1 if a timeout or other error occurs, or if the sender
658 closes the connection.
660 If @a timeout is -1, wait indefinitely for input activity to appear. If @a timeout is
661 zero, don't wait at all. If @a timeout is positive, wait that number of seconds
662 before timing out. If @a timeout has a negative value other than -1, the results are not
663 well defined, but we'll probably get an EINVAL error from select().
665 If we detect activity, branch on the type of socket:
667 - If it's a listener, accept a new connection, and add the new socket to the
668 socket_manager's list, without actually reading any data.
669 - Otherwise, read as much data as is available from the input socket, passing it a
670 buffer at a time to whatever callback function has been defined to the socket_manager.
672 int socket_wait( socket_manager* mgr, int timeout, int sock_fd ) {
676 FD_ZERO( &read_set );
677 FD_SET( sock_fd, &read_set );
686 // If timeout is -1, we block indefinitely
687 if( (retval = select( sock_fd + 1, &read_set, NULL, NULL, NULL)) == -1 ) {
688 osrfLogDebug( OSRF_LOG_MARK, "Call to select() interrupted: Sys Error: %s",
693 } else if( timeout > 0 ) { /* timeout of 0 means don't block */
695 if( (retval = select( sock_fd + 1, &read_set, NULL, NULL, &tv)) == -1 ) {
696 osrfLogDebug( OSRF_LOG_MARK, "Call to select() interrupted: Sys Error: %s",
702 osrfLogInternal( OSRF_LOG_MARK, "%d active sockets after select()", retval);
704 socket_node* node = socket_find_node(mgr, sock_fd);
706 if( node->endpoint == LISTENER_SOCKET ) {
707 _socket_handle_new_client( mgr, node ); // accept new connection
709 int status = _socket_handle_client_data( mgr, node ); // read data
712 socket_remove_node( mgr, sock_fd );
719 return -1; // No such file descriptor for this socket_manager
724 @brief Wait for input on all of a socket_manager's sockets; react to any input found.
725 @param mgr Pointer to the socket_manager.
726 @param timeout How many seconds to wait before timing out (see notes).
727 @return 0 if successful, or -1 if a timeout or other error occurs.
729 If @a timeout is -1, wait indefinitely for input activity to appear. If @a timeout is
730 zero, don't wait at all. If @a timeout is positive, wait that number of seconds
731 before timing out. If @a timeout has a negative value other than -1, the results are not
732 well defined, but we'll probably get an EINVAL error from select().
734 For each active socket found:
736 - If it's a listener, accept a new connection, and add the new socket to the
737 socket_manager's list, without actually reading any data.
738 - Otherwise, read as much data as is available from the input socket, passing it a
739 buffer at a time to whatever callback function has been defined to the socket_manager.
741 int socket_wait_all(socket_manager* mgr, int timeout) {
744 osrfLogWarning( OSRF_LOG_MARK, "socket_wait_all(): null mgr" );
750 FD_ZERO( &read_set );
752 socket_node* node = mgr->socket;
755 osrfLogInternal( OSRF_LOG_MARK, "Adding socket fd %d to select set",node->sock_fd);
756 FD_SET( node->sock_fd, &read_set );
757 if(node->sock_fd > max_fd) max_fd = node->sock_fd;
769 // If timeout is -1, there is no timeout passed to the call to select
770 if( (num_active = select( max_fd, &read_set, NULL, NULL, NULL)) == -1 ) {
771 osrfLogWarning( OSRF_LOG_MARK, "select() call aborted: %s", strerror(errno));
775 } else if( timeout != 0 ) { /* timeout of 0 means don't block */
777 if( (num_active = select( max_fd, &read_set, NULL, NULL, &tv)) == -1 ) {
778 osrfLogWarning( OSRF_LOG_MARK, "select() call aborted: %s", strerror(errno));
783 osrfLogDebug( OSRF_LOG_MARK, "%d active sockets after select()", num_active);
788 while(node && (handled < num_active)) {
790 socket_node* next_node = node->next;
791 int sock_fd = node->sock_fd;
793 /* does this socket have data? */
794 if( FD_ISSET( sock_fd, &read_set ) ) {
796 osrfLogInternal( OSRF_LOG_MARK, "Socket %d active", sock_fd);
798 FD_CLR(sock_fd, &read_set);
800 if(node->endpoint == LISTENER_SOCKET)
801 _socket_handle_new_client(mgr, node);
804 if( _socket_handle_client_data(mgr, node) == -1 ) {
805 /* someone may have yanked a socket_node out from under us */
807 socket_remove_node( mgr, sock_fd );
819 @brief Accept a new socket from a listener, and add it to the socket_manager's list.
820 @param mgr Pointer to the socket_manager that will own the new socket.
821 @param node Pointer to the socket_node for the listener socket.
822 @return 0 if successful, or -1 if not.
824 Call: accept(). Creates a DATA_SOCKET (even though the socket resides on the server).
826 static int _socket_handle_new_client(socket_manager* mgr, socket_node* node) {
827 if(mgr == NULL || node == NULL) return -1;
831 new_sock_fd = accept(node->sock_fd, NULL, NULL);
832 if(new_sock_fd < 0) {
833 osrfLogWarning( OSRF_LOG_MARK, "_socket_handle_new_client(): accept() failed: %s",
838 if(node->addr_type == INET) {
839 _socket_add_node(mgr, DATA_SOCKET, INET, new_sock_fd, node->sock_fd);
840 osrfLogDebug( OSRF_LOG_MARK, "Adding new INET client for %d", node->sock_fd);
842 } else if(node->addr_type == UNIX) {
843 _socket_add_node(mgr, DATA_SOCKET, UNIX, new_sock_fd, node->sock_fd);
844 osrfLogDebug( OSRF_LOG_MARK, "Adding new UNIX client for %d", node->sock_fd);
852 @brief Receive data on a streaming socket.
853 @param mgr Pointer to the socket_manager that owns the socket_node.
854 @param node Pointer to the socket_node that owns the socket.
855 @return 0 if successful, or -1 upon failure.
857 Receive one or more buffers until no more bytes are available for receipt. Add a
858 terminal nul to each buffer and pass it to a callback function previously defined by the
859 application to the socket_manager.
861 If the sender closes the connection, call another callback function, if one has been
864 Even when the function returns successfully, the received message may not be complete --
865 there may be more data that hasn't arrived yet. It is the responsibility of the
866 calling code to recognize message boundaries.
868 Called only for a DATA_SOCKET.
870 static int _socket_handle_client_data(socket_manager* mgr, socket_node* node) {
871 if(mgr == NULL || node == NULL) return -1;
875 int sock_fd = node->sock_fd;
877 set_fl(sock_fd, O_NONBLOCK);
879 osrfLogInternal( OSRF_LOG_MARK, "%ld : Received data at %f\n",
880 (long) getpid(), get_timestamp_millis());
882 while( (read_bytes = recv(sock_fd, buf, RBUFSIZE-1, 0) ) > 0 ) {
883 buf[read_bytes] = '\0';
884 osrfLogInternal( OSRF_LOG_MARK, "Socket %d Read %d bytes and data: %s",
885 sock_fd, read_bytes, buf);
886 if(mgr->data_received)
887 mgr->data_received(mgr->blob, mgr, sock_fd, buf, node->parent_id);
889 int local_errno = errno; /* capture errno as set by recv() */
891 if(socket_find_node(mgr, sock_fd)) { /* someone may have closed this socket */
892 clr_fl(sock_fd, O_NONBLOCK);
894 // EAGAIN would have meant that no more data was available
895 if(local_errno != EAGAIN) // but if that's not the case...
896 osrfLogWarning( OSRF_LOG_MARK, " * Error reading socket with error %s",
897 strerror(local_errno) );
900 } else { return -1; } /* inform the caller that this node has been tampered with */
902 if(read_bytes == 0) { /* socket closed by client */
903 if(mgr->on_socket_closed) {
904 mgr->on_socket_closed(mgr->blob, sock_fd);
915 @brief Destroy a socket_manager, and close all of its sockets.
916 @param mgr Pointer to the socket_manager to be destroyed.
918 void socket_manager_free(socket_manager* mgr) {
919 if(mgr == NULL) return;
922 tmp = mgr->socket->next;
923 socket_disconnect(mgr, mgr->socket->sock_fd);