1 #include "socket_bundle.h"
3 /* --------------------------------------------------------------------
5 -------------------------------------------------------------------- */
8 void printme(void* blob, socket_manager* mgr,
9 int sock_fd, char* data, int parent_id) {
11 fprintf(stderr, "Got data from socket %d with parent %d => %s",
12 sock_fd, parent_id, data );
14 socket_send(sock_fd, data);
17 socket_disconnect(mgr, sock_fd);
18 _socket_print_list(mgr);
22 int main(int argc, char* argv[]) {
23 socket_manager manager;
24 memset(&manager, 0, sizeof(socket_manager));
29 manager.data_received = &printme;
30 socket_open_tcp_server(&manager, port);
33 socket_wait_all(&manager, -1);
38 /* -------------------------------------------------------------------- */
42 int debug_handler(char* msg, ...) {
45 vfprintf(stderr, msg, args);
47 fprintf( stderr, "\n" );
51 int warning_handler(char* msg, ...) {
54 vfprintf(stderr, msg, args);
56 fprintf( stderr, "\n" );
62 socket_node* _socket_add_node(socket_manager* mgr,
63 int endpoint, int addr_type, int sock_fd, int parent_id ) {
65 if(mgr == NULL) return NULL;
66 debug_handler("Adding socket node with fd %d", sock_fd);
67 socket_node* new_node = safe_malloc(sizeof(socket_node));
69 new_node->endpoint = endpoint;
70 new_node->addr_type = addr_type;
71 new_node->sock_fd = sock_fd;
72 new_node->next = NULL;
73 new_node->parent_id = 0;
75 new_node->parent_id = parent_id;
77 new_node->next = mgr->socket;
78 mgr->socket = new_node;
82 /* creates a new server socket node and adds it to the socket set.
83 returns new socket fd on success. -1 on failure.
84 socket_type is one of INET or UNIX */
85 int socket_open_tcp_server(socket_manager* mgr, int port) {
87 if( mgr == NULL ) return warning_handler("socket_open_tcp_server(): NULL mgr");
90 struct sockaddr_in server_addr;
92 sock_fd = socket(AF_INET, SOCK_STREAM, 0);
95 return warning_handler("tcp_server_connect(): Unable to create socket");
97 server_addr.sin_family = AF_INET;
98 server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
99 server_addr.sin_port = htons(port);
101 if(bind( sock_fd, (struct sockaddr*) &server_addr, sizeof(server_addr)) < 0)
102 return warning_handler("tcp_server_connect(): cannot bind to port %d", port );
104 if(listen(sock_fd, 20) == -1)
105 return warning_handler("tcp_server_connect(): listen() returned error");
107 _socket_add_node(mgr, SERVER_SOCKET, INET, sock_fd, 0);
111 int socket_open_unix_server(socket_manager* mgr, char* path) {
112 if(mgr == NULL || path == NULL) return -1;
114 debug_handler("opening unix socket at %s", path);
116 struct sockaddr_un server_addr;
118 sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
120 return warning_handler("socket_open_unix_server(): socket() failed");
122 server_addr.sun_family = AF_UNIX;
123 strcpy(server_addr.sun_path, path);
125 if( bind(sock_fd, (struct sockaddr*) &server_addr,
126 sizeof(struct sockaddr_un)) < 0) {
127 return warning_handler(
128 "socket_open_unix_server(): cannot bind to unix port %s", path );
131 if(listen(sock_fd, 20) == -1)
132 return warning_handler("socket_open_unix_server(): listen() returned error");
134 debug_handler("unix socket successfully opened");
135 _socket_add_node(mgr, SERVER_SOCKET, UNIX, sock_fd, 0);
141 /* creates a client socket and adds it to the socket set.
142 returns 0 on success. -1 on failure.
143 socket_type is one of INET or UNIX */
144 int socket_open_client(socket_manager* mgr,
145 int socket_type, int port, char* dest_addr) {
149 /* returns the socket_node with the given sock_fd */
150 socket_node* socket_find_node(socket_manager* mgr, int sock_fd) {
151 if(mgr == NULL) return NULL;
152 socket_node* node = mgr->socket;
154 if(node->sock_fd == sock_fd)
161 /* removes the node with the given sock_fd from the list and frees it */
162 void socket_remove_node(socket_manager* mgr, int sock_fd) {
164 if(mgr == NULL) return;
166 debug_handler("removing socket %d", sock_fd);
168 socket_node* head = mgr->socket;
169 socket_node* tail = head;
170 if(head == NULL) return;
172 /* if removing the first node in the list */
173 if(head->sock_fd == sock_fd) {
174 mgr->socket = head->next;
176 debug_handler("removing first socket in list");
182 /* if removing any other node */
184 if(head->sock_fd == sock_fd) {
185 tail->next = head->next;
196 void _socket_print_list(socket_manager* mgr) {
197 if(mgr == NULL) return;
198 socket_node* node = mgr->socket;
199 debug_handler("socket_node list: [");
201 debug_handler("sock_fd: %d | parent_id: %d",
202 node->sock_fd, node->parent_id);
208 /* sends the given data to the given socket */
209 int socket_send(int sock_fd, const char* data) {
210 debug_handler( "socket_bundle sending to %d data %s",
213 signal(SIGPIPE, SIG_IGN); /* in case a unix socket was closed */
214 if( send( sock_fd, data, strlen(data), 0 ) < 0 ) {
215 return warning_handler( "tcp_server_send(): Error sending data" );
221 /* disconnects the node with the given sock_fd and removes
222 it from the socket set */
223 void socket_disconnect(socket_manager* mgr, int sock_fd) {
225 debug_handler("Closing socket %d", sock_fd);
227 if( shutdown( sock_fd, SHUT_RDWR ) )
228 warning_handler( "socket_disconnect(): Error shuting down socket, removing anyway" );
230 if( close( sock_fd ) == -1 )
231 warning_handler( "socket_disconnect(): Error closing socket, removing anyway" );
234 socket_remove_node(mgr, sock_fd);
239 /* we assume that if select() fails, the socket is no longer valid */
240 int socket_connected(int sock_fd) {
242 FD_ZERO( &read_set );
243 FD_SET( sock_fd, &read_set );
244 if( select( sock_fd + 1, &read_set, NULL, NULL, NULL) == -1 )
250 int socket_wait(socket_manager* mgr, int timeout, int sock_fd) {
255 int socket_wait_all(socket_manager* mgr, int timeout) {
257 if(mgr == NULL) return warning_handler( "tcp_wait(): null mgr" );
261 FD_ZERO( &read_set );
263 socket_node* node = mgr->socket;
266 //debug_handler("Adding socket %d to select set",node->sock_fd);
267 FD_SET( node->sock_fd, &read_set );
268 if(node->sock_fd > max_fd) max_fd = node->sock_fd;
277 if( timeout == -1 ) {
279 // If timeout is -1, there is no timeout passed to the call to select
280 if( (retval = select( max_fd, &read_set, NULL, NULL, NULL)) == -1 ) {
281 return warning_handler("Call to select interrupted");
284 } else if( timeout != 0 ) { /* timeout of 0 means don't block */
286 if( (retval = select( max_fd, &read_set, NULL, NULL, &tv)) == -1 ) {
287 return warning_handler( "Call to select interrupted" );
291 debug_handler("%d active sockets after select()", retval);
292 return _socket_route_data(mgr, retval, &read_set);
295 /* determines if we'er receiving a new client or data
296 on an existing client */
297 int _socket_route_data(
298 socket_manager* mgr, int num_active, fd_set* read_set) {
300 if(mgr == NULL) return -1;
302 int last_failed_id = -1;
305 /* come back here if someone yanks a socket_node from beneath us */
308 socket_node* node = mgr->socket;
312 while(node && (handled < num_active)) {
314 int sock_fd = node->sock_fd;
316 if(last_failed_id != -1) {
317 /* in case it was not removed by our overlords */
318 debug_handler("Attempting to remove last_failed_id of %d", last_failed_id);
319 socket_remove_node( mgr, last_failed_id );
326 /* does this socket have data? */
327 if( FD_ISSET( sock_fd, read_set ) ) {
330 debug_handler("Socket %d active", sock_fd);
332 FD_CLR(sock_fd, read_set);
334 if(node->endpoint == SERVER_SOCKET)
335 _socket_handle_new_client(mgr, node);
337 if(node->endpoint == CLIENT_SOCKET )
338 status = _socket_handle_client_data(mgr, node);
340 /* someone may have yanked a socket_node out from under
341 us...start over with the first socket */
343 last_failed_id = sock_fd;
344 debug_handler("Backtracking back to start of loop because "
345 "of -1 return code from _socket_handle_client_data()");
349 if(status == -1) break;
354 if(status == 0) break;
355 if(status == -1) status = 0;
362 int _socket_handle_new_client(socket_manager* mgr, socket_node* node) {
363 if(mgr == NULL || node == NULL) return -1;
365 //struct sockaddr_in client_addr_in;
366 //struct sockaddr_un client_addr_un;
367 //int client_len, new_sock_fd;
370 new_sock_fd = accept(node->sock_fd, NULL, NULL);
372 return warning_handler("_socket_route_data(): accept() failed");
374 if(node->addr_type == INET) {
375 _socket_add_node(mgr, CLIENT_SOCKET, INET, new_sock_fd, node->sock_fd);
376 debug_handler("Adding new INET client for %d", node->sock_fd);
378 } else if(node->addr_type == UNIX) {
379 _socket_add_node(mgr, CLIENT_SOCKET, UNIX, new_sock_fd, node->sock_fd);
380 debug_handler("Adding new UNIX client for %d", node->sock_fd);
387 int _socket_handle_client_data(socket_manager* mgr, socket_node* node) {
388 if(mgr == NULL || node == NULL) return -1;
392 int sock_fd = node->sock_fd;
394 memset(buf, 0, BUFSIZE);
395 set_fl(sock_fd, O_NONBLOCK);
396 debug_handler("Gathering client data for %d", node->sock_fd);
398 debug_handler("Socket buf before read %s", buf);
399 while( (read_bytes = recv(sock_fd, buf, BUFSIZE-1, 0) ) > 0 ) {
400 debug_handler("Socket %d Read %d bytes and data: %s", sock_fd, read_bytes, buf);
404 if(l > 1) {buf[l-1] = '\0';buf[l-2] = '\0';}
405 debug_handler("Socket data after cleanup: %s", sock_fd, read_bytes, buf);
409 if(mgr->data_received)
410 mgr->data_received(mgr->blob, mgr, sock_fd, buf, node->parent_id);
412 memset(buf, 0, BUFSIZE);
415 if(socket_find_node(mgr, sock_fd)) { /* someone may have closed this socket */
416 clr_fl(sock_fd, O_NONBLOCK);
418 if( errno != EAGAIN )
419 warning_handler( " * Error reading socket with errno %d", errno );
423 if(read_bytes == 0) { /* socket closed by client */
424 if(mgr->on_socket_closed) {
425 mgr->on_socket_closed(mgr->blob, sock_fd);
435 void socket_manager_free(socket_manager* mgr) {
436 if(mgr == NULL) return;
439 tmp = mgr->socket->next;
440 socket_disconnect(mgr, mgr->socket->sock_fd);