3 @brief Collection of socket-handling routines.
6 #include <opensrf/socket_bundle.h>
9 @brief Represents a socket owned by a socket_manager.
11 A socket_manager owns a linked list of socket_nodes representing the collection of
12 sockets that it manages. It may contain a single socket for passing data, or it may
13 contain a listener socket together with any associated sockets (created by accept())
14 for communicating with a client.
16 struct socket_node_struct {
17 int endpoint; /**< Role of socket: SERVER_SOCKET or CLIENT_SOCKET. */
18 int addr_type; /**< INET or UNIX. */
19 int sock_fd; /**< File descriptor for socket. */
20 int parent_id; /**< If we're a new client for a server socket,
21 this is the listener socket we spawned from. */
22 struct socket_node_struct* next; /**< Linkage pointer for linked list. */
25 /** @brief Size of buffer used to read from the sockets */
28 static socket_node* _socket_add_node(socket_manager* mgr,
29 int endpoint, int addr_type, int sock_fd, int parent_id );
30 static socket_node* socket_find_node(socket_manager* mgr, int sock_fd);
31 static void socket_remove_node(socket_manager*, int sock_fd);
32 static int _socket_send(int sock_fd, const char* data, int flags);
33 static int _socket_handle_new_client(socket_manager* mgr, socket_node* node);
34 static int _socket_handle_client_data(socket_manager* mgr, socket_node* node);
37 /* --------------------------------------------------------------------
39 -------------------------------------------------------------------- */
42 void printme(void* blob, socket_manager* mgr,
43 int sock_fd, char* data, int parent_id) {
45 fprintf(stderr, "Got data from socket %d with parent %d => %s",
46 sock_fd, parent_id, data );
48 socket_send(sock_fd, data);
51 socket_disconnect(mgr, sock_fd);
52 _socket_print_list(mgr);
56 int main(int argc, char* argv[]) {
57 socket_manager manager;
58 memset(&manager, 0, sizeof(socket_manager));
63 manager.data_received = &printme;
64 socket_open_tcp_server(&manager, port);
67 socket_wait_all(&manager, -1);
72 /* -------------------------------------------------------------------- */
76 @brief Create a new socket_node and add it to a socket_manager's list.
77 @param mgr Pointer to the socket_manager.
78 @param endpoint SERVER_SOCKET or CLIENT_SOCKET, denoting how the socket is to be used.
79 @param addr_type address type: INET or UNIX.
80 @param sock_fd sock_fd for the new socket_node.
81 @param parent_id parent_id for the new node.
82 @return Pointer to the new socket_node.
84 If @a parent_id is negative, the new socket_node receives a parent_id of 0.
86 static socket_node* _socket_add_node(socket_manager* mgr,
87 int endpoint, int addr_type, int sock_fd, int parent_id ) {
89 if(mgr == NULL) return NULL;
90 osrfLogInternal( OSRF_LOG_MARK, "Adding socket node with fd %d", sock_fd);
91 socket_node* new_node = safe_malloc(sizeof(socket_node));
93 new_node->endpoint = endpoint;
94 new_node->addr_type = addr_type;
95 new_node->sock_fd = sock_fd;
96 new_node->next = NULL;
97 new_node->parent_id = 0;
99 new_node->parent_id = parent_id;
101 new_node->next = mgr->socket;
102 mgr->socket = new_node;
107 @brief Create an TCP INET listener socket and add it to a socket_manager's list.
108 @param mgr Pointer to the socket manager that will own the socket.
109 @param port The port number to bind to.
110 @param listen_ip The IP address to bind to; or, NULL for INADDR_ANY.
111 @return The socket's file descriptor if successful; otherwise -1.
113 Calls: socket(), bind(), and listen(). Creates a SERVER_SOCKET.
115 int socket_open_tcp_server(socket_manager* mgr, int port, const char* listen_ip) {
118 osrfLogWarning( OSRF_LOG_MARK, "socket_open_tcp_server(): NULL mgr");
123 struct sockaddr_in server_addr;
125 server_addr.sin_family = AF_INET;
127 if(listen_ip != NULL) {
129 if( inet_aton( listen_ip, &addr ) )
130 server_addr.sin_addr.s_addr = addr.s_addr;
132 osrfLogError( OSRF_LOG_MARK, "Listener address is invalid: %s", listen_ip );
136 server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
139 server_addr.sin_port = htons(port);
142 sock_fd = socket(AF_INET, SOCK_STREAM, 0);
144 osrfLogWarning( OSRF_LOG_MARK, "socket_open_tcp_server(): Unable to create TCP socket: %s",
150 if(bind( sock_fd, (struct sockaddr*) &server_addr, sizeof(server_addr)) < 0) {
151 osrfLogWarning( OSRF_LOG_MARK, "socket_open_tcp_server(): cannot bind to port %d: %s",
152 port, strerror( errno ) );
158 if(listen(sock_fd, 20) == -1) {
159 osrfLogWarning( OSRF_LOG_MARK, "socket_open_tcp_server(): listen() returned error: %s",
165 _socket_add_node(mgr, SERVER_SOCKET, INET, sock_fd, 0);
170 @brief Create a UNIX domain listener socket and add it to the socket_manager's list.
171 @param mgr Pointer to the socket_manager that will own the socket.
172 @param path Name of the socket within the file system.
173 @return The socket's file descriptor if successful; otherwise -1.
175 Calls: socket(), bind(), listen(). Creates a SERVER_SOCKET.
177 Apply socket option TCP_NODELAY in order to reduce latency.
179 int socket_open_unix_server(socket_manager* mgr, const char* path) {
180 if(mgr == NULL || path == NULL) return -1;
182 osrfLogDebug( OSRF_LOG_MARK, "opening unix socket at %s", path);
184 struct sockaddr_un server_addr;
186 if(strlen(path) > sizeof(server_addr.sun_path) - 1)
188 osrfLogWarning( OSRF_LOG_MARK, "socket_open_unix_server(): path too long: %s",
194 sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
196 osrfLogWarning( OSRF_LOG_MARK, "socket_open_unix_server(): socket() failed: %s",
201 server_addr.sun_family = AF_UNIX;
202 strcpy(server_addr.sun_path, path);
205 if( bind(sock_fd, (struct sockaddr*) &server_addr,
206 sizeof(struct sockaddr_un)) < 0) {
207 osrfLogWarning( OSRF_LOG_MARK,
208 "socket_open_unix_server(): cannot bind to unix port %s: %s",
209 path, strerror( errno ) );
215 if(listen(sock_fd, 20) == -1) {
216 osrfLogWarning( OSRF_LOG_MARK, "socket_open_unix_server(): listen() returned error: %s",
222 osrfLogDebug( OSRF_LOG_MARK, "unix socket successfully opened");
226 /* causing problems with router for some reason ... */
227 //osrfLogDebug( OSRF_LOG_MARK, "Setting SO_REUSEADDR");
228 //setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
230 //osrfLogDebug( OSRF_LOG_MARK, "Setting TCP_NODELAY");
231 setsockopt(sock_fd, IPPROTO_TCP, TCP_NODELAY, &i, sizeof(i));
233 _socket_add_node(mgr, SERVER_SOCKET, UNIX, sock_fd, 0);
239 @brief Create a UDP socket for a server, and add it to a socket_manager's list.
240 @param mgr Pointer to the socket_manager that will own the socket.
241 @param port The port number to bind to.
242 @param listen_ip The IP address to bind to, or NULL for INADDR_ANY.
243 @return The socket's file descriptor if successful; otherwise -1.
245 Calls: socket(), bind(). Creates a SERVER_SOCKET.
247 int socket_open_udp_server(
248 socket_manager* mgr, int port, const char* listen_ip ) {
251 struct sockaddr_in server_addr;
253 server_addr.sin_family = AF_INET;
254 server_addr.sin_port = htons(port);
257 if( inet_aton( listen_ip, &addr ) )
258 server_addr.sin_addr.s_addr = addr.s_addr;
260 osrfLogError( OSRF_LOG_MARK, "UDP listener address is invalid: %s", listen_ip );
264 server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
267 if( (sockfd = socket( AF_INET, SOCK_DGRAM, 0 )) < 0 ) {
268 osrfLogWarning( OSRF_LOG_MARK, "Unable to create UDP socket: %s", strerror( errno ) );
273 if( (bind (sockfd, (struct sockaddr *) &server_addr,sizeof(server_addr))) ) {
274 osrfLogWarning( OSRF_LOG_MARK, "Unable to bind to UDP port %d: %s",
275 port, strerror( errno ) );
280 _socket_add_node(mgr, SERVER_SOCKET, INET, sockfd, 0);
286 @brief Create a client TCP socket, connect with it, and add it to a socket_manager's list.
287 @param mgr Pointer to the socket_manager that will own the socket.
288 @param port What port number to connect to.
289 @param dest_addr Host name or IP address of the server to which we are connecting.
290 @return The socket's file descriptor if successful; otherwise -1.
292 Calls: getaddrinfo(), socket(), connect(). Creates a CLIENT_SOCKET.
294 Applies socket option TCP_NODELAY in order to reduce latency.
296 int socket_open_tcp_client(socket_manager* mgr, int port, const char* dest_addr) {
298 struct sockaddr_in remoteAddr;
301 // ------------------------------------------------------------------
302 // Get the IP address of the hostname (for TCP only)
303 // ------------------------------------------------------------------
304 struct addrinfo hints = { 0, 0, 0, 0, 0, NULL, NULL, NULL };
305 hints.ai_socktype = SOCK_STREAM;
306 struct addrinfo* addr_info = NULL;
308 int rc = getaddrinfo( dest_addr, NULL, &hints, &addr_info );
309 if( rc || ! addr_info ) {
310 osrfLogWarning( OSRF_LOG_MARK, "socket_open_tcp_client(): No Such Host => %s: %s",
311 dest_addr, gai_strerror( rc ) );
315 // Look for an address supporting IPv4. Someday we'll look for
316 // either IPv4 or IPv6, and branch according to what we find.
317 while( addr_info && addr_info->ai_family != PF_INET ) {
318 addr_info = addr_info->ai_next;
322 osrfLogWarning( OSRF_LOG_MARK,
323 "socket_open_tcp_client(): Host %s does not support IPV4", dest_addr );
327 // ------------------------------------------------------------------
329 // ------------------------------------------------------------------
331 if( (sock_fd = socket( AF_INET, SOCK_STREAM, 0 )) < 0 ) {
332 osrfLogWarning( OSRF_LOG_MARK, "socket_open_tcp_client(): Cannot create TCP socket: %s",
338 setsockopt(sock_fd, IPPROTO_TCP, TCP_NODELAY, &i, sizeof(i));
340 // ------------------------------------------------------------------
341 // Construct server info struct
342 // ------------------------------------------------------------------
343 memset( &remoteAddr, 0, sizeof(remoteAddr));
344 remoteAddr.sin_family = AF_INET;
345 remoteAddr.sin_port = htons( port );
346 struct sockaddr_in* ai_addr_in = (struct sockaddr_in*) addr_info->ai_addr;
347 remoteAddr.sin_addr.s_addr = ai_addr_in->sin_addr.s_addr;
349 freeaddrinfo( addr_info );
351 // ------------------------------------------------------------------
353 // ------------------------------------------------------------------
355 if( connect( sock_fd, (struct sockaddr*) &remoteAddr, sizeof( struct sockaddr_in ) ) < 0 ) {
356 osrfLogWarning( OSRF_LOG_MARK, "socket_open_tcp_client(): Cannot connect to server %s: %s",
357 dest_addr, strerror(errno) );
362 _socket_add_node(mgr, CLIENT_SOCKET, INET, sock_fd, -1 );
369 @brief Create a client UDP socket and add it to a socket_manager's list.
370 @param mgr Pointer to the socket_manager that will own the socket.
371 @return The socket's file descriptor if successful; otherwise -1.
373 Calls: socket(). Creates a CLIENT_SOCKET.
375 int socket_open_udp_client( socket_manager* mgr ) {
380 if( (sockfd = socket(AF_INET,SOCK_DGRAM,0)) < 0 ) {
381 osrfLogWarning( OSRF_LOG_MARK,
382 "socket_open_udp_client(): Unable to create UDP socket: %s", strerror( errno ) );
386 _socket_add_node(mgr, CLIENT_SOCKET, INET, sockfd, -1 );
393 @brief Create a UNIX domain client socket, connect with it, add it to the socket_manager's list
394 @param mgr Pointer to the socket_manager that will own the socket.
395 @param sock_path Name of the socket within the file system.
396 @return The socket's file descriptor if successful; otherwise -1.
398 Calls: socket(), connect(). Creates a CLIENT_SOCKET.
400 int socket_open_unix_client(socket_manager* mgr, const char* sock_path) {
403 struct sockaddr_un usock;
405 if(strlen(sock_path) > sizeof(usock.sun_path) - 1)
407 osrfLogWarning( OSRF_LOG_MARK, "socket_open_unix_client(): path too long: %s",
413 if( (sock_fd = socket( AF_UNIX, SOCK_STREAM, 0 )) < 0 ) {
414 osrfLogWarning( OSRF_LOG_MARK, "socket_open_unix_client(): Cannot create UNIX socket: %s", strerror( errno ) );
418 usock.sun_family = AF_UNIX;
419 strcpy( usock.sun_path, sock_path );
421 len = sizeof( usock.sun_family ) + strlen( usock.sun_path );
424 if( connect( sock_fd, (struct sockaddr *) &usock, len ) < 0 ) {
425 osrfLogWarning( OSRF_LOG_MARK, "Error connecting to unix socket: %s",
431 _socket_add_node(mgr, CLIENT_SOCKET, UNIX, sock_fd, -1 );
438 @brief Search a socket_manager's list for a socket node for a given file descriptor.
439 @param mgr Pointer to the socket manager.
440 @param sock_fd The file descriptor to be sought.
441 @return A pointer to the socket_node if found; otherwise NULL.
443 Traverse a linked list owned by the socket_manager.
445 static socket_node* socket_find_node(socket_manager* mgr, int sock_fd) {
446 if(mgr == NULL) return NULL;
447 socket_node* node = mgr->socket;
449 if(node->sock_fd == sock_fd)
456 /* removes the node with the given sock_fd from the list and frees it */
458 @brief Remove a socket node for a given fd from a socket_manager's list.
459 @param mgr Pointer to the socket_manager.
460 @param sock_fd The file descriptor whose socket_node is to be removed.
462 This function does @em not close the socket. It just removes a node from the list, and
463 frees it. The disposition of the socket is the responsibility of the calling code.
465 static void socket_remove_node(socket_manager* mgr, int sock_fd) {
467 if(mgr == NULL) return;
469 osrfLogDebug( OSRF_LOG_MARK, "removing socket %d", sock_fd);
471 socket_node* head = mgr->socket;
472 socket_node* tail = head;
473 if(head == NULL) return;
475 /* if removing the first node in the list */
476 if(head->sock_fd == sock_fd) {
477 mgr->socket = head->next;
484 /* if removing any other node */
486 if(head->sock_fd == sock_fd) {
487 tail->next = head->next;
498 @brief Write to the log: a list of socket_nodes in a socket_manager's list.
499 @param mgr Pointer to the socket_manager.
501 For testing and debugging.
503 The messages are issued as DEBG messages, and show each file descriptor and its parent.
505 void _socket_print_list(socket_manager* mgr) {
506 if(mgr == NULL) return;
507 socket_node* node = mgr->socket;
508 osrfLogDebug( OSRF_LOG_MARK, "socket_node list: [");
510 osrfLogDebug( OSRF_LOG_MARK, "sock_fd: %d | parent_id: %d",
511 node->sock_fd, node->parent_id);
514 osrfLogDebug( OSRF_LOG_MARK, "]");
518 @brief Send a nul-terminated string over a socket.
519 @param sock_fd The file descriptor for the socket.
520 @param data Pointer to the string to be sent.
521 @return 0 if successful, -1 if not.
523 This function is a thin wrapper for _socket_send().
525 int socket_send(int sock_fd, const char* data) {
526 return _socket_send( sock_fd, data, 0);
530 @brief Send a nul-terminated string over a socket.
531 @param sock_fd The file descriptor for the socket.
532 @param data Pointer to the string to be sent.
533 @param flags A set of bitflags to be passed to send().
534 @return 0 if successful, -1 if not.
536 This function is the final common pathway for all outgoing socket traffic.
538 static int _socket_send(int sock_fd, const char* data, int flags) {
540 signal(SIGPIPE, SIG_IGN); /* in case a unix socket was closed */
543 size_t r = send( sock_fd, data, strlen(data), flags );
544 int local_errno = errno;
547 osrfLogWarning( OSRF_LOG_MARK, "_socket_send(): Error sending data with return %d", r );
548 osrfLogWarning( OSRF_LOG_MARK, "Last Sys Error: %s", strerror(local_errno));
556 /* sends the given data to the given socket.
557 * sets the send flag MSG_DONTWAIT which will allow the
558 * process to continue even if the socket buffer is full
559 * returns 0 on success, -1 otherwise */
560 //int socket_send_nowait( int sock_fd, const char* data) {
561 // return _socket_send( sock_fd, data, MSG_DONTWAIT);
566 @brief Wait for a socket to be ready to send, and then send a string over it.
567 @param sock_fd File descriptor of the socket.
568 @param data Pointer to a nul-terminated string to be sent.
569 @param usecs How long to wait, in microseconds, before timing out.
570 @return 0 if successful, -1 if not.
572 The socket may not accept all the data we want to give it.
574 int socket_send_timeout( int sock_fd, const char* data, int usecs ) {
577 FD_ZERO( &write_set );
578 FD_SET( sock_fd, &write_set );
580 const int mil = 1000000;
581 int secs = (int) usecs / mil;
582 usecs = usecs - (secs * mil);
589 int ret = select( sock_fd + 1, NULL, &write_set, NULL, &tv);
590 if( ret > 0 ) return _socket_send( sock_fd, data, 0);
592 osrfLogError(OSRF_LOG_MARK, "socket_send_timeout(): "
593 "timed out on send for socket %d after %d secs, %d usecs: %s",
594 sock_fd, secs, usecs, strerror( errno ) );
600 /* disconnects the node with the given sock_fd and removes
601 it from the socket set */
603 @brief Close a socket, and remove it from the socket_manager's list.
604 @param mgr Pointer to the socket_manager.
605 @param sock_fd File descriptor for the socket to be closed.
607 We close the socket before determining whether it belongs to the socket_manager in question.
609 void socket_disconnect(socket_manager* mgr, int sock_fd) {
610 osrfLogInternal( OSRF_LOG_MARK, "Closing socket %d", sock_fd);
612 socket_remove_node(mgr, sock_fd);
617 @brief Determine whether a socket is valid.
618 @param sock_fd File descriptor for the socket.
619 @return 1 if the socket is valid, or 0 if it isn't.
621 The test is based on a call to select(). If the socket is valid but is not ready to be
622 written to, we wait until it is ready, then return 1.
624 If the select() fails, it may be because it was interrupted by a signal. In that case
625 we try again. Otherwise we assume that the socket is no longer valid. This can happen
626 if, for example, the other end of a connection has closed the connection.
628 The select() can also fail if it is unable to allocate enough memory for its own internal
629 use. If that happens, we may erroneously report a valid socket as invalid, but we
630 probably wouldn't be able to use it anyway if we're that close to exhausting memory.
632 int socket_connected(int sock_fd) {
634 FD_ZERO( &read_set );
635 FD_SET( sock_fd, &read_set );
637 if( select( sock_fd + 1, &read_set, NULL, NULL, NULL) == -1 )
639 else if( EINTR == errno )
647 @brief Look for input on a given socket. If you find some, react to it.
648 @param mgr Pointer to the socket_manager that presumably owns the socket.
649 @param timeout Timeout interval, in seconds (see notes).
650 @param sock_fd The file descriptor to look at.
651 @return 0 if successful, or -1 if a timeout or other error occurs, or if the sender
652 closes the connection.
654 If @a timeout is -1, wait indefinitely for input activity to appear. If @a timeout is
655 zero, don't wait at all. If @a timeout is positive, wait that number of seconds
656 before timing out. If @a timeout has a negative value other than -1, the results are not
657 well defined, but we'll probably get an EINVAL error from select().
659 If we detect activity, branch on the type of socket:
661 - If it's a listener, accept a new connection, and add the new socket to the
662 socket_manager's list, without actually reading any data.
663 - Otherwise, read as much data as is available from the input socket, passing it a
664 buffer at a time to whatever callback function has been defined to the socket_manager.
666 int socket_wait( socket_manager* mgr, int timeout, int sock_fd ) {
670 FD_ZERO( &read_set );
671 FD_SET( sock_fd, &read_set );
680 // If timeout is -1, we block indefinitely
681 if( (retval = select( sock_fd + 1, &read_set, NULL, NULL, NULL)) == -1 ) {
682 osrfLogDebug( OSRF_LOG_MARK, "Call to select() interrupted: Sys Error: %s",
687 } else if( timeout > 0 ) { /* timeout of 0 means don't block */
689 if( (retval = select( sock_fd + 1, &read_set, NULL, NULL, &tv)) == -1 ) {
690 osrfLogDebug( OSRF_LOG_MARK, "Call to select() interrupted: Sys Error: %s",
696 osrfLogInternal( OSRF_LOG_MARK, "%d active sockets after select()", retval);
698 socket_node* node = socket_find_node(mgr, sock_fd);
700 if( node->endpoint == SERVER_SOCKET ) {
701 _socket_handle_new_client( mgr, node ); // accept new connection
703 int status = _socket_handle_client_data( mgr, node ); // read data
705 socket_remove_node(mgr, sock_fd);
712 return -1; // No such file descriptor for this socket_manager
717 @brief Wait for input on all of a socket_manager's sockets; react to any input found.
718 @param mgr Pointer to the socket_manager.
719 @param timeout How many seconds to wait before timing out (see notes).
720 @return 0 if successful, or -1 if a timeout or other error occurs.
722 If @a timeout is -1, wait indefinitely for input activity to appear. If @a timeout is
723 zero, don't wait at all. If @a timeout is positive, wait that number of seconds
724 before timing out. If @a timeout has a negative value other than -1, the results are not
725 well defined, but we'll probably get an EINVAL error from select().
727 For each active socket found:
729 - If it's a listener, accept a new connection, and add the new socket to the
730 socket_manager's list, without actually reading any data.
731 - Otherwise, read as much data as is available from the input socket, passing it a
732 buffer at a time to whatever callback function has been defined to the socket_manager.
734 int socket_wait_all(socket_manager* mgr, int timeout) {
737 osrfLogWarning( OSRF_LOG_MARK, "socket_wait_all(): null mgr" );
743 FD_ZERO( &read_set );
745 socket_node* node = mgr->socket;
748 osrfLogInternal( OSRF_LOG_MARK, "Adding socket fd %d to select set",node->sock_fd);
749 FD_SET( node->sock_fd, &read_set );
750 if(node->sock_fd > max_fd) max_fd = node->sock_fd;
762 // If timeout is -1, there is no timeout passed to the call to select
763 if( (num_active = select( max_fd, &read_set, NULL, NULL, NULL)) == -1 ) {
764 osrfLogWarning( OSRF_LOG_MARK, "select() call aborted: %s", strerror(errno));
768 } else if( timeout != 0 ) { /* timeout of 0 means don't block */
770 if( (num_active = select( max_fd, &read_set, NULL, NULL, &tv)) == -1 ) {
771 osrfLogWarning( OSRF_LOG_MARK, "select() call aborted: %s", strerror(errno));
776 osrfLogDebug( OSRF_LOG_MARK, "%d active sockets after select()", num_active);
781 while(node && (handled < num_active)) {
783 socket_node* next_node = node->next;
784 int sock_fd = node->sock_fd;
786 /* does this socket have data? */
787 if( FD_ISSET( sock_fd, &read_set ) ) {
789 osrfLogInternal( OSRF_LOG_MARK, "Socket %d active", sock_fd);
791 FD_CLR(sock_fd, &read_set);
793 if(node->endpoint == SERVER_SOCKET)
794 _socket_handle_new_client(mgr, node);
797 if( _socket_handle_client_data(mgr, node) == -1 ) {
798 /* someone may have yanked a socket_node out from under us */
799 socket_remove_node( mgr, sock_fd );
811 @brief Accept a new socket from a listener, and add it to the socket_manager's list.
812 @param mgr Pointer to the socket_manager that will own the new socket.
813 @param node Pointer to the socket_node for the listener socket.
814 @return 0 if successful, or -1 if not.
816 Call: accept(). Creates a CLIENT_SOCKET (even though the socket resides on the server).
818 static int _socket_handle_new_client(socket_manager* mgr, socket_node* node) {
819 if(mgr == NULL || node == NULL) return -1;
823 new_sock_fd = accept(node->sock_fd, NULL, NULL);
824 if(new_sock_fd < 0) {
825 osrfLogWarning( OSRF_LOG_MARK, "_socket_handle_new_client(): accept() failed: %s",
830 if(node->addr_type == INET) {
831 _socket_add_node(mgr, CLIENT_SOCKET, INET, new_sock_fd, node->sock_fd);
832 osrfLogDebug( OSRF_LOG_MARK, "Adding new INET client for %d", node->sock_fd);
834 } else if(node->addr_type == UNIX) {
835 _socket_add_node(mgr, CLIENT_SOCKET, UNIX, new_sock_fd, node->sock_fd);
836 osrfLogDebug( OSRF_LOG_MARK, "Adding new UNIX client for %d", node->sock_fd);
844 @brief Receive data on a streaming socket.
845 @param mgr Pointer to the socket_manager that owns the socket_node.
846 @param node Pointer to the socket_node that owns the socket.
847 @return 0 if successful, or -1 upon failure.
849 Receive one or more buffers until no more bytes are available for receipt. Add a
850 terminal nul to each buffer and pass it to a callback function previously defined by the
851 application to the socket_manager.
853 If the sender closes the connection, call another callback function, if one has been
856 Even when the function returns successfully, the received message may not be complete --
857 there may be more data that hasn't arrived yet. It is the responsibility of the
858 calling code to recognize message boundaries.
860 Called only for a CLIENT_SOCKET.
862 static int _socket_handle_client_data(socket_manager* mgr, socket_node* node) {
863 if(mgr == NULL || node == NULL) return -1;
867 int sock_fd = node->sock_fd;
869 set_fl(sock_fd, O_NONBLOCK);
871 osrfLogInternal( OSRF_LOG_MARK, "%ld : Received data at %f\n",
872 (long) getpid(), get_timestamp_millis());
874 while( (read_bytes = recv(sock_fd, buf, RBUFSIZE-1, 0) ) > 0 ) {
875 buf[read_bytes] = '\0';
876 osrfLogInternal( OSRF_LOG_MARK, "Socket %d Read %d bytes and data: %s",
877 sock_fd, read_bytes, buf);
878 if(mgr->data_received)
879 mgr->data_received(mgr->blob, mgr, sock_fd, buf, node->parent_id);
881 int local_errno = errno; /* capture errno as set by recv() */
883 if(socket_find_node(mgr, sock_fd)) { /* someone may have closed this socket */
884 clr_fl(sock_fd, O_NONBLOCK);
886 // EAGAIN would have meant that no more data was available
887 if(local_errno != EAGAIN) // but if that's not the case...
888 osrfLogWarning( OSRF_LOG_MARK, " * Error reading socket with error %s",
889 strerror(local_errno) );
892 } else { return -1; } /* inform the caller that this node has been tampered with */
894 if(read_bytes == 0) { /* socket closed by client */
895 if(mgr->on_socket_closed) {
896 mgr->on_socket_closed(mgr->blob, sock_fd);
907 @brief Destroy a socket_manager, and close all of its sockets.
908 @param mgr Pointer to the socket_manager to be destroyed.
910 void socket_manager_free(socket_manager* mgr) {
911 if(mgr == NULL) return;
914 tmp = mgr->socket->next;
915 socket_disconnect(mgr, mgr->socket->sock_fd);