broke out a lot of the code from generic_utils into their
authorerickson <erickson@9efc2488-bf62-4759-914b-345cdb29e865>
Sun, 19 Jun 2005 17:32:45 +0000 (17:32 +0000)
committererickson <erickson@9efc2488-bf62-4759-914b-345cdb29e865>
Sun, 19 Jun 2005 17:32:45 +0000 (17:32 +0000)
own packages and moved them here

git-svn-id: svn://svn.open-ils.org/OpenSRF/trunk@359 9efc2488-bf62-4759-914b-345cdb29e865

src/utils/logging.c [new file with mode: 0644]
src/utils/logging.h [new file with mode: 0644]
src/utils/md5.h [new file with mode: 0644]
src/utils/sha.h [new file with mode: 0644]
src/utils/socket_bundle.c [new file with mode: 0644]
src/utils/socket_bundle.h [new file with mode: 0644]
src/utils/socket_test.c [new file with mode: 0644]
src/utils/string_array.c [new file with mode: 0644]
src/utils/string_array.h [new file with mode: 0644]
src/utils/utils.c
src/utils/utils.h [new file with mode: 0644]

diff --git a/src/utils/logging.c b/src/utils/logging.c
new file mode 100644 (file)
index 0000000..ebaaf25
--- /dev/null
@@ -0,0 +1,185 @@
+#include "logging.h"
+
+void get_timestamp( char buf_36chars[]) {
+
+       struct timeb tb;
+       ftime(&tb);
+       char* localtime = strdup( ctime( &(tb.time) ) );
+       char mil[4];
+       memset(mil,0,4);
+       sprintf(mil," (%d)",tb.millitm);
+       strcpy( buf_36chars, localtime );
+       buf_36chars[ strlen(localtime)-1] = '\0'; // remove newline
+       strcat(buf_36chars,mil);
+       free(localtime);
+}
+
+static FILE* log_file = NULL;
+static int log_level = -1;
+static int logging = 0;
+
+void log_free() { if( log_file != NULL ) fclose(log_file ); }
+
+int fatal_handler( char* msg, ... ) {
+               
+       char buf[36];
+       memset( buf, 0, 36 );
+       get_timestamp( buf );
+       pid_t  pid = getpid();
+       va_list args;
+
+       if( logging ) {
+
+               if( log_level < LOG_ERROR )
+                       return -1;
+
+               fprintf( log_file, "[%s %d] [%s] ", buf, pid, "ERR " );
+       
+               va_start(args, msg);
+               vfprintf(log_file, msg, args);
+               va_end(args);
+       
+               fprintf(log_file, "\n");
+               fflush( log_file );
+
+       }
+       
+       /* also log to stderr  for ERRORS*/
+       fprintf( stderr, "[%s %d] [%s] ", buf, pid, "ERR " );
+       va_start(args, msg);
+       vfprintf(stderr, msg, args);
+       va_end(args);
+       fprintf( stderr, "\n" );
+
+       exit(99);
+       return -1; /* for consistency */
+}
+
+int warning_handler( char* msg, ... ) {
+
+       char buf[36];
+       memset( buf, 0, 36 );
+       get_timestamp( buf );
+       pid_t  pid = getpid();
+       va_list args;
+       
+       if(logging) {
+
+               if( log_level < LOG_WARNING )
+                       return -1;
+
+               fprintf( log_file, "[%s %d] [%s] ", buf, pid, "WARN" );
+       
+               va_start(args, msg);
+               vfprintf(log_file, msg, args);
+               va_end(args);
+       
+               fprintf(log_file, "\n");
+               fflush( log_file );
+
+       } else {
+
+               fprintf( stderr, "[%s %d] [%s] ", buf, pid, "WARN" );
+               va_start(args, msg);
+               vfprintf(stderr, msg, args);
+               va_end(args);
+               fprintf( stderr, "\n" );
+       }
+
+       return -1;
+}
+
+int info_handler( char* msg, ... ) {
+
+       char buf[36];
+       memset( buf, 0, 36 );
+       get_timestamp( buf );
+       pid_t  pid = getpid();
+       va_list args;
+
+       if(logging) {
+
+               if( log_level < LOG_INFO )
+                       return -1;
+               fprintf( log_file, "[%s %d] [%s] ", buf, pid, "INFO" );
+
+               va_start(args, msg);
+               vfprintf(log_file, msg, args);
+               va_end(args);
+       
+               fprintf(log_file, "\n");
+               fflush( log_file );
+
+       } else {
+
+               fprintf( stderr, "[%s %d] [%s] ", buf, pid, "INFO" );
+               va_start(args, msg);
+               vfprintf(stderr, msg, args);
+               va_end(args);
+               fprintf( stderr, "\n" );
+               fflush(stderr);
+
+       }
+       return -1;
+}
+
+
+int debug_handler( char* msg, ... ) {
+
+       char buf[36];
+       memset( buf, 0, 36 );
+       get_timestamp( buf );
+       pid_t  pid = getpid();
+       va_list args;
+       
+       if(logging) {
+
+               if( log_level < LOG_DEBUG )
+                       return -1;
+
+               fprintf( log_file, "[%s %d] [%s] ", buf, pid, "DEBG" );
+       
+               va_start(args, msg);
+               vfprintf(log_file, msg, args);
+               va_end(args);
+       
+               fprintf(log_file, "\n");
+               fflush( log_file );
+
+       } else {
+
+               fprintf( stderr, "[%s %d] [%s] ", buf, pid, "DEBG" );
+               va_start(args, msg);
+               vfprintf(stderr, msg, args);
+               va_end(args);
+               fprintf( stderr, "\n" );
+       }
+
+       return -1;
+}
+
+
+int log_init( int llevel, char* lfile ) {
+
+
+       if( llevel < 1 ) {
+               logging = 0;
+               return 0;
+       }
+
+       log_level = llevel;
+
+       /* log to stderr */
+       if(lfile == NULL) return 0;
+
+       log_file = fopen( lfile, "a" );
+       if( log_file == NULL ) {
+               fprintf( stderr, "Unable to open log file %s for appending\n", lfile );
+               return 0;
+       }
+       logging = 1;
+       return 1;
+
+}
+
+
diff --git a/src/utils/logging.h b/src/utils/logging.h
new file mode 100644 (file)
index 0000000..c2523af
--- /dev/null
@@ -0,0 +1,40 @@
+
+#include <stdarg.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/timeb.h>
+
+#include <string.h>
+#include <time.h>
+#include <stdlib.h>
+
+#ifndef LOGGING_H
+#define LOGGING_H
+
+
+#define LOG_ERROR 1
+#define LOG_WARNING 2
+#define LOG_INFO 3
+#define LOG_DEBUG 4
+
+// ---------------------------------------------------------------------------------
+// Error handling interface.
+// ---------------------------------------------------------------------------------
+void get_timestamp(    char buf_36chars[]);
+int fatal_handler(     char* message, ...);
+int warning_handler( char* message, ... );
+int info_handler(              char* message, ... );
+int debug_handler(     char* message, ... );
+
+
+/** If we return 0 either the log level is less than LOG_ERROR  
+  * or we could not open the log file
+  */
+int log_init( int log_level, char* log_file );
+void log_free(); 
+
+#endif
diff --git a/src/utils/md5.h b/src/utils/md5.h
new file mode 100644 (file)
index 0000000..53dd2b1
--- /dev/null
@@ -0,0 +1,35 @@
+/* --- The MD5 routines --- */
+
+/* MD5 routines, after Ron Rivest */
+/* Written by David Madore <david.madore@ens.fr>, with code taken in
+ * part from Colin Plumb. */
+/* Public domain (1999/11/24) */
+
+/* Note: these routines do not depend on endianness. */
+
+/* === The header === */
+
+/* Put this in md5.h if you don't like having everything in one big
+ * file. */
+
+#ifndef _DMADORE_MD5_H
+#define _DMADORE_MD5_H
+
+struct md5_ctx {
+  /* The four chaining variables */
+  unsigned long buf[4];
+  /* Count number of message bits */
+  unsigned long bits[2];
+  /* Data being fed in */
+  unsigned long in[16];
+  /* Our position within the 512 bits (always between 0 and 63) */
+  int b;
+};
+
+void MD5_transform (unsigned long buf[4], const unsigned long in[16]);
+void MD5_start (struct md5_ctx *context);
+void MD5_feed (struct md5_ctx *context, unsigned char inb);
+void MD5_stop (struct md5_ctx *context, unsigned char digest[16]);
+
+#endif /* not defined _DMADORE_MD5_H */
+
diff --git a/src/utils/sha.h b/src/utils/sha.h
new file mode 100644 (file)
index 0000000..6c3d2d4
--- /dev/null
@@ -0,0 +1,41 @@
+// sha.h
+// Jabber client library
+//
+// Original Code Copyright (C) 1999-2001 Dave Smith (dave@jabber.org)
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//
+// Contributor(s): Julian Missig
+//
+// This Original Code has been modified by IBM Corporation. Modifications 
+// made by IBM described herein are Copyright (c) International Business 
+// Machines Corporation, 2002.
+//
+// Date             Modified by     Description of modification
+// 01/20/2002       IBM Corp.       Updated to libjudo 1.1.1
+// 2002-03-05       IBM Corp.       Updated to libjudo 1.1.5
+// 2002-07-09       IBM Corp.       Added Roster::getSession()
+//
+// =====================================================================================
+
+
+//#ifdef WIN32
+     char* shahash(const char* str);
+//#else
+//extern "C" {
+//     char* shahash(const char* str);
+//}
+//#endif
+
diff --git a/src/utils/socket_bundle.c b/src/utils/socket_bundle.c
new file mode 100644 (file)
index 0000000..113f2f8
--- /dev/null
@@ -0,0 +1,407 @@
+#include "socket_bundle.h"
+
+/* -------------------------------------------------------------------- 
+       Test Code 
+       -------------------------------------------------------------------- */
+/*
+int count = 0;
+void printme(void* blob, socket_manager* mgr, 
+               int sock_fd, char* data, int parent_id) {
+
+       fprintf(stderr, "Got data from socket %d with parent %d => %s", 
+                       sock_fd, parent_id, data );
+
+       socket_send(sock_fd, data);
+
+       if(count++ > 2) {
+               socket_disconnect(mgr, sock_fd);
+               _socket_print_list(mgr);
+       }
+}
+
+int main(int argc, char* argv[]) {
+       socket_manager manager;
+       memset(&manager, 0, sizeof(socket_manager));
+       int port = 11000;
+       if(argv[1])
+               port = atoi(argv[1]);
+
+       manager.data_received = &printme;
+       socket_open_tcp_server(&manager, port);
+
+       while(1)
+               socket_wait_all(&manager, -1);
+
+       return 0;
+}
+*/
+/* -------------------------------------------------------------------- */
+
+
+/*
+int debug_handler(char* msg, ...) {
+       va_list args;
+       va_start(args, msg);
+       vfprintf(stderr, msg, args);
+       va_end(args);
+       fprintf( stderr, "\n" );
+       return -1;
+}
+
+int warning_handler(char* msg, ...) {
+       va_list args;
+       va_start(args, msg);
+       vfprintf(stderr, msg, args);
+       va_end(args);
+       fprintf( stderr, "\n" );
+       return -1;
+}
+*/
+
+
+socket_node* _socket_add_node(socket_manager* mgr, 
+               int endpoint, int addr_type, int sock_fd, int parent_id ) {
+
+       if(mgr == NULL) return NULL;
+       debug_handler("Adding socket node with fd %d", sock_fd);
+       socket_node* new_node = safe_malloc(sizeof(socket_node));
+
+       new_node->endpoint      = endpoint;
+       new_node->addr_type     = addr_type;
+       new_node->sock_fd               = sock_fd;
+       new_node->next                  = NULL;
+       new_node->parent_id = 0;
+       if(parent_id > 0)
+               new_node->parent_id = parent_id;
+
+       new_node->next                  = mgr->socket;
+       mgr->socket                             = new_node;
+       return new_node;
+}
+
+/* creates a new server socket node and adds it to the socket set.
+       returns new socket fd on success.  -1 on failure.
+       socket_type is one of INET or UNIX  */
+int socket_open_tcp_server(socket_manager* mgr, int port) {
+
+       if( mgr == NULL ) return warning_handler("socket_open_tcp_server(): NULL mgr"); 
+
+       int sock_fd;
+       struct sockaddr_in server_addr;
+
+       sock_fd = socket(AF_INET, SOCK_STREAM, 0);
+
+       if(sock_fd < 0) 
+               return warning_handler("tcp_server_connect(): Unable to create socket");
+
+       server_addr.sin_family = AF_INET;
+       server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+       server_addr.sin_port = htons(port);
+
+       if(bind( sock_fd, (struct sockaddr*) &server_addr, sizeof(server_addr)) < 0)
+               return warning_handler("tcp_server_connect(): cannot bind to port %d", port );
+
+       if(listen(sock_fd, 20) == -1) 
+               return warning_handler("tcp_server_connect(): listen() returned error");
+
+       _socket_add_node(mgr, SERVER_SOCKET, INET, sock_fd, 0);
+       return sock_fd;
+}
+
+int socket_open_unix_server(socket_manager* mgr, char* path) {
+       if(mgr == NULL || path == NULL) return -1;
+
+       debug_handler("opening unix socket at %s", path);
+       int sock_fd;
+       struct sockaddr_un server_addr;
+
+       sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
+       if(sock_fd < 0)
+               return warning_handler("socket_open_unix_server(): socket() failed");
+
+       server_addr.sun_family = AF_UNIX;
+       strcpy(server_addr.sun_path, path);
+
+       if( bind(sock_fd, (struct sockaddr*) &server_addr, 
+                               sizeof(struct sockaddr_un)) < 0) {
+               return warning_handler(
+                       "socket_open_unix_server(): cannot bind to unix port %s", path );
+       }
+
+       if(listen(sock_fd, 20) == -1) 
+               return warning_handler("socket_open_unix_server(): listen() returned error");
+
+       debug_handler("unix socket successfully opened");
+       _socket_add_node(mgr, SERVER_SOCKET, UNIX, sock_fd, 0);
+       return sock_fd;
+}
+
+
+
+/* creates a client socket and adds it to the socket set.
+       returns 0 on success.  -1 on failure.
+       socket_type is one of INET or UNIX  */
+int socket_open_client(socket_manager* mgr, 
+               int socket_type, int port, char* dest_addr) {
+       return 0;
+}
+
+/* returns the socket_node with the given sock_fd */
+socket_node* socket_find_node(socket_manager* mgr, int sock_fd) {
+       if(mgr == NULL) return NULL;
+       socket_node* node = mgr->socket;
+       while(node) {
+               if(node->sock_fd == sock_fd)
+                       return node;
+               node = node->next;
+       }
+       return NULL;
+}
+
+/* removes the node with the given sock_fd from the list and frees it */
+void socket_remove_node(socket_manager* mgr, int sock_fd) {
+
+       if(mgr == NULL) return;
+
+       debug_handler("removing socket %d", sock_fd);
+
+       socket_node* head = mgr->socket;
+       socket_node* tail = head;
+       if(head == NULL) return;
+
+       /* if removing the first node in the list */
+       if(head->sock_fd == sock_fd) {
+               mgr->socket = head->next;
+               free(head);
+               debug_handler("removing first socket in list");
+               return;
+       }
+
+       head = head->next;
+
+       /* if removing any other node */
+       while(head) {
+               if(head->sock_fd == sock_fd) {
+                       tail->next = head->next;
+                       free(head);
+                       return;
+               }
+               tail = head;
+               head = head->next;
+       }
+}
+
+
+
+void _socket_print_list(socket_manager* mgr) {
+       if(mgr == NULL) return;
+       socket_node* node = mgr->socket;
+       debug_handler("socket_node list: [");
+       while(node) {
+               debug_handler("sock_fd: %d | parent_id: %d", 
+                               node->sock_fd, node->parent_id);
+               node = node->next;
+       }
+       debug_handler("]");
+}
+
+/* sends the given data to the given socket */
+int socket_send(int sock_fd, const char* data) {
+       debug_handler( "socket_bundle sending to %d data %s",
+               sock_fd, data);
+
+       signal(SIGPIPE, SIG_IGN); /* in case a unix socket was closed */
+       if( send( sock_fd, data, strlen(data), 0 ) < 0 ) {
+               return warning_handler( "tcp_server_send(): Error sending data" );
+       }
+
+       return 0;
+}
+
+/* disconnects the node with the given sock_fd and removes
+       it from the socket set */
+void socket_disconnect(socket_manager* mgr, int sock_fd) {
+
+       debug_handler("Closing socket %d", sock_fd);
+       if( close( sock_fd ) == -1 ) 
+               warning_handler( "socket_disconnect(): Error closing socket, removing anyway" );
+
+       if(mgr != NULL) 
+               socket_remove_node(mgr, sock_fd);
+       
+}
+
+
+/* we assume that if select() fails, the socket is no longer valid */
+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;
+
+}
+
+int socket_wait(socket_manager* mgr, int timeout, int sock_fd) {
+       return 0;
+}
+
+
+int socket_wait_all(socket_manager* mgr, int timeout) {
+
+       if(mgr == NULL) return warning_handler( "tcp_wait(): null mgr" );
+
+       int retval = 0;
+       fd_set read_set;
+       FD_ZERO( &read_set );
+
+       socket_node* node = mgr->socket;
+       int max_fd = 0;
+       while(node) {
+               //debug_handler("Adding socket %d to select set",node->sock_fd);
+               FD_SET( node->sock_fd, &read_set );
+               if(node->sock_fd > max_fd) max_fd = node->sock_fd;
+               node = node->next;
+       }
+       max_fd += 1;
+
+       struct timeval tv;
+       tv.tv_sec = timeout;
+       tv.tv_usec = 0;
+
+       if( timeout == -1 ) {  
+
+               // If timeout is -1, there is no timeout passed to the call to select
+               if( (retval = select( max_fd, &read_set, NULL, NULL, NULL)) == -1 ) {
+                       return warning_handler("Call to select interrupted");
+               }
+
+       } else if( timeout != 0 ) { /* timeout of 0 means don't block */
+
+               if( (retval = select( max_fd, &read_set, NULL, NULL, &tv)) == -1 ) {
+                       return warning_handler( "Call to select interrupted" );
+               }
+       }
+
+       debug_handler("%d active sockets after select()", retval);
+       return _socket_route_data(mgr, retval, &read_set);
+}
+
+/* determines if we'er receiving a new client or data
+       on an existing client */
+int _socket_route_data(
+       socket_manager* mgr, int num_active, fd_set* read_set) {
+
+       socket_node* node = mgr->socket;
+       int handled = 0;
+       
+       while(node && (handled < num_active)) {
+
+               int sock_fd = node->sock_fd;
+
+               /* does this socket have data? */
+               if( FD_ISSET( sock_fd, read_set ) ) {
+
+                       debug_handler("Socket %d active", sock_fd);
+                       handled++;
+                       FD_CLR(sock_fd, read_set);
+
+                       if(node->endpoint == SERVER_SOCKET) 
+                               _socket_handle_new_client(mgr, node);
+
+                       if(node->endpoint == CLIENT_SOCKET ) 
+                               _socket_handle_client_data(mgr, node);
+
+               } // is_set
+               
+               node = node->next;
+
+       } // while(node)
+
+       return 0;
+}
+
+
+int _socket_handle_new_client(socket_manager* mgr, socket_node* node) {
+       if(mgr == NULL || node == NULL) return -1;
+
+       //struct sockaddr_in client_addr_in; 
+       //struct sockaddr_un client_addr_un; 
+       //int client_len, new_sock_fd; 
+
+       int new_sock_fd;
+       new_sock_fd = accept(node->sock_fd, NULL, NULL);
+       if(new_sock_fd < 0)
+               return warning_handler("_socket_route_data(): accept() failed");
+
+       if(node->addr_type == INET) {
+               _socket_add_node(mgr, CLIENT_SOCKET, INET, new_sock_fd, node->sock_fd);
+               debug_handler("Adding new INET client for %d", node->sock_fd);
+
+       } else if(node->addr_type == UNIX) {
+               _socket_add_node(mgr, CLIENT_SOCKET, UNIX, new_sock_fd, node->sock_fd);
+               debug_handler("Adding new UNIX client for %d", node->sock_fd);
+       }
+
+       return 0;
+}
+
+
+int _socket_handle_client_data(socket_manager* mgr, socket_node* node) {
+       if(mgr == NULL || node == NULL) return -1;
+
+       char buf[BUFSIZE];
+       int read_bytes;
+       int sock_fd = node->sock_fd;
+
+       memset(buf, 0, BUFSIZE);
+       set_fl(sock_fd, O_NONBLOCK);
+       debug_handler("Gathering client data for %d", node->sock_fd);
+
+       debug_handler("Socket buf before read %s", buf);
+       while( (read_bytes = recv(sock_fd, buf, BUFSIZE-1, 0) ) > 0 ) {
+               debug_handler("Socket %d Read %d bytes and data: %s", sock_fd, read_bytes, buf);
+
+               /*
+               int l = strlen(buf); 
+               if(l > 1) {buf[l-1] = '\0';buf[l-2] = '\0';}
+               debug_handler("Socket data after cleanup: %s", sock_fd, read_bytes, buf);
+               */
+
+
+               if(mgr->data_received)
+                       mgr->data_received(mgr->blob, mgr, sock_fd, buf, node->parent_id);
+
+               memset(buf, 0, BUFSIZE);
+       }
+
+       if(socket_find_node(mgr, sock_fd)) {  /* someone may have closed this socket */
+               clr_fl(sock_fd, O_NONBLOCK); 
+               if(read_bytes < 0) { 
+                       if( errno != EAGAIN ) 
+                               warning_handler( " * Error reading socket with errno %d", errno );
+               }
+       }
+
+       if(read_bytes == 0) {  /* socket closed by client */
+               if(mgr->on_socket_closed)
+                       mgr->on_socket_closed(mgr->blob, sock_fd);
+       }
+
+       return 0;
+
+}
+
+
+void socket_manager_free(socket_manager* mgr) {
+       if(mgr == NULL) return;
+       socket_node* tmp;
+       while(mgr->socket) {
+               tmp = mgr->socket->next;
+               socket_disconnect(mgr, mgr->socket->sock_fd);
+               mgr->socket = tmp;
+       }
+       free(mgr);
+
+}
diff --git a/src/utils/socket_bundle.h b/src/utils/socket_bundle.h
new file mode 100644 (file)
index 0000000..3b0121f
--- /dev/null
@@ -0,0 +1,127 @@
+#include "utils.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <errno.h>
+
+#include "utils.h"
+#include "logging.h"
+
+//---------------------------------------------------------------
+// Unix headers
+//---------------------------------------------------------------
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+
+#include <signal.h>
+
+#ifndef SOCKET_BUNDLE_H
+#define SOCKET_BUNDLE_H
+
+
+#define SERVER_SOCKET                  1
+#define CLIENT_SOCKET                  2
+
+#define INET 10 
+#define UNIX 11 
+
+/* buffer used to read from the sockets */
+#define BUFSIZE 1024 
+
+
+/* models a single socket connection */
+struct socket_node_struct {
+       int endpoint;           /* SERVER_SOCKET or CLIENT_SOCKET */
+       int addr_type;          /* INET or UNIX */
+       int sock_fd;
+       int parent_id;          /* if we're a new client for a server socket, 
+                                                               this points to the server socket we spawned from */
+       struct socket_node_struct* next;
+};
+typedef struct socket_node_struct socket_node;
+
+
+/* Maintains the socket set */
+struct socket_manager_struct {
+       /* callback for passing up any received data.  sock_fd is the socket
+               that read the data.  parent_id (if > 0) is the socket id of the 
+               server that this socket spawned from (i.e. it's a new client connection) */
+       void (*data_received) 
+               (void* blob, struct socket_manager_struct*, 
+                int sock_fd, char* data, int parent_id);
+
+       void (*on_socket_closed) (void* blob, int sock_fd);
+
+       socket_node* socket;
+       void* blob;
+};
+typedef struct socket_manager_struct socket_manager;
+
+void socket_manager_free(socket_manager* mgr);
+
+/* creates a new server socket node and adds it to the socket set.
+       returns socket id on success.  -1 on failure.
+       socket_type is one of INET or UNIX  */
+int socket_open_tcp_server(socket_manager*, int port);
+
+int socket_open_unix_server(socket_manager* mgr, char* path);
+
+/* creates a client socket and adds it to the socket set.
+       returns 0 on success.  -1 on failure.
+       socket_type is one of INET or UNIX  */
+int socket_open_client(socket_manager*, 
+               int socket_type, int port, char* dest_addr);
+
+/* returns the socket_node with the given sock_fd */
+socket_node* socket_find_node(socket_manager*, int sock_fd);
+
+/* removes the node with the given sock_fd from the list and frees it */
+void socket_remove_node(socket_manager*, int sock_fd);
+
+
+/* sends the given data to the given socket. returns 0 on success, -1 otherwise */
+int socket_send(int sock_fd, const char* data);
+
+/* disconnects the node with the given sock_fd and removes
+       it from the socket set */
+void socket_disconnect(socket_manager*, int sock_fd);
+
+/* allocates and inserts a new socket node into the nodeset.
+       if parent_id is positive and non-zero, it will be set */
+socket_node*  _socket_add_node(socket_manager* mgr, 
+               int endpoint, int addr_type, int sock_fd, int parent_id );
+
+int socket_wait(socket_manager* mgr, int timeout, int sock_fd);
+
+/* waits on all sockets for incoming data.  
+       timeout == -1   | block indefinitely
+       timeout == 0    | don't block, just read any available data off all sockets
+       timeout == x    | block for at most x seconds */
+int socket_wait_all(socket_manager* mgr, int timeout);
+
+/* iterates over the sockets in the set and handles active sockets.
+       new sockets connecting to server sockets cause the creation
+       of a new socket node.
+       Any new data read is is passed off to the data_received callback
+       as it arrives */
+int _socket_route_data(socket_manager* mgr, int num_active, fd_set* read_set);
+
+/* utility function for displaying the currently attached sockets */
+void _socket_print_list(socket_manager* mgr);
+
+int socket_connected(int sock_fd);
+
+
+int _socket_handle_new_client(socket_manager* mgr, socket_node* node);
+int _socket_handle_client_data(socket_manager* mgr, socket_node* node);
+
+
+#endif
diff --git a/src/utils/socket_test.c b/src/utils/socket_test.c
new file mode 100644 (file)
index 0000000..4bc7653
--- /dev/null
@@ -0,0 +1,33 @@
+#include "socket_bundle.h"
+
+int count = 0;
+void printme(void* blob, socket_manager* mgr, 
+               int sock_fd, char* data, int parent_id) {
+
+       fprintf(stderr, "Got data from socket %d with parent %d => %s", 
+                       sock_fd, parent_id, data );
+
+       socket_send(sock_fd, data);
+
+       if(count++ > 2) {
+//             socket_disconnect(mgr, sock_fd);
+               _socket_print_list(mgr);
+               socket_manager_free(mgr);
+               exit(0);
+       }
+}
+
+int main(int argc, char* argv[]) {
+       socket_manager* manager = safe_malloc(sizeof(socket_manager));
+       int port = 11000;
+       if(argv[1])
+               port = atoi(argv[1]);
+
+       manager->data_received = &printme;
+       socket_open_tcp_server(manager, port);
+
+       while(1)
+               socket_wait_all(manager, -1);
+
+       return 0;
+}
diff --git a/src/utils/string_array.c b/src/utils/string_array.c
new file mode 100644 (file)
index 0000000..8290a43
--- /dev/null
@@ -0,0 +1,89 @@
+#include "string_array.h"
+
+/*
+int main() {
+       string_array* arr = init_string_array(1);
+       string_array_add(arr, "1");
+       fprintf(stderr,"adding 3\n");
+       string_array_add(arr, "3");
+       string_array_destroy(arr);
+       return 0;
+}
+*/
+
+
+
+string_array* init_string_array(int size) {
+       if(size > STRING_ARRAY_MAX_SIZE)
+               fatal_handler("init_string_array size is too large");
+
+       string_array* arr = 
+               (string_array*) safe_malloc(sizeof(string_array));
+       arr->array = (char**) safe_malloc(size * sizeof(char*));
+       arr->size = 0;
+       arr->arr_size = size;
+       return arr;
+}
+
+
+void string_array_add(string_array* arr, char* str) {
+       if(arr == NULL || str == NULL ) {
+               warning_handler("Invalid params to string_array_add");
+               return;
+       }
+
+       if( strlen(str) < 1 ) return;
+
+       arr->size++;
+       //fprintf(stderr,"size is %d\n", arr->size);
+
+       if( arr->size > STRING_ARRAY_MAX_SIZE ) 
+               fatal_handler("string_array_add size is too large");
+
+       /* if necessary, double capacity */
+       if(arr->size >= arr->arr_size) {
+               arr->arr_size *= 2;
+               debug_handler("string_array: Doubling array size to %d", arr->arr_size);
+               char** tmp = (char**) safe_malloc(arr->arr_size * sizeof(char*));
+               int i;
+
+               /* copy the string pointers over */
+               for( i = 0; i!= arr->size; i++ ) 
+                       tmp[i] = arr->array[i];
+
+               free(arr->array);
+               arr->array = tmp;
+       }
+
+       //fprintf(stderr, "String is %s", str);
+       //debug_handler("string_array_add: Adding string %s", str);
+       //arr->array[arr->size - 1] = (char*) safe_malloc(strlen(str));
+       arr->array[arr->size - 1] = strdup(str);
+       //fprintf(stderr,"we have %s\n", arr->array[arr->size - 1]);
+}
+
+char* string_array_get_string(string_array* arr, int index) {
+       if(!arr || index < 0 || index >= arr->size )
+               return NULL;
+       char* str = arr->array[index]; 
+
+       if(str == NULL)
+               warning_handler("Somehow we have a NULL string in the string array");
+
+       //debug_handler("string_array_get_string: getting string %s", str);
+       return str;
+}
+
+
+void string_array_destroy(string_array* arr) {
+       if(!arr) return;
+       int i;
+       for( i = 0; i!= arr->size; i++ ) {
+               if( arr->array[i] != NULL ) {
+                       //debug_handler("Freeing string from string array %s", arr->array[i]);
+                       free(arr->array[i]);
+               }
+       }
+       free(arr->array);
+       free(arr);
+}
diff --git a/src/utils/string_array.h b/src/utils/string_array.h
new file mode 100644 (file)
index 0000000..0a20eab
--- /dev/null
@@ -0,0 +1,29 @@
+#include <stdio.h>
+
+#include "utils.h"
+#include "logging.h"
+
+#define STRING_ARRAY_MAX_SIZE 1024
+
+#ifndef STRING_ARRAY_H
+#define STRING_ARRAY_H
+
+struct string_array_struct {
+               char** array;   
+               int size;
+               int arr_size;
+               int total_string_size;
+};
+typedef struct string_array_struct string_array;
+
+string_array* init_string_array(int size);
+void string_array_add(string_array*, char* string);
+
+char* string_array_get_string(string_array* arr, int index);
+void string_array_destroy(string_array*);
+
+/* total size of all included strings */
+int string_array_get_total_size(string_array* arr);
+
+
+#endif
index 4f92b61..1e2f773 100644 (file)
@@ -26,6 +26,43 @@ double get_timestamp_millis() {
 }
 
 
+/* setting/clearing file flags */
+int set_fl( int fd, int flags ) {
+       
+       int val;
+
+       if( (val = fcntl( fd, F_GETFL, 0) ) < 0 ) {
+               fprintf(stderr, "fcntl F_GETFL error");
+               return -1;
+       }
+
+       val |= flags;
+
+       if( fcntl( fd, F_SETFL, val ) < 0 ) {
+               fprintf(stderr, "fcntl F_SETFL error");
+               return -1;
+       }
+       return 0;
+}
+       
+int clr_fl( int fd, int flags ) {
+       
+       int val;
+
+       if( (val = fcntl( fd, F_GETFL, 0) ) < 0 ) {
+               fprintf(stderr, "fcntl F_GETFL error" );
+               return -1;
+       }
+
+       val &= ~flags;
+
+       if( fcntl( fd, F_SETFL, val ) < 0 ) {
+               fprintf( stderr, "fcntl F_SETFL error" );
+               return -1;
+       }
+       return 0;
+}
+
 // ---------------------------------------------------------------------------------
 // Flesh out a ubiqitous growing string buffer
 // ---------------------------------------------------------------------------------
diff --git a/src/utils/utils.h b/src/utils/utils.h
new file mode 100644 (file)
index 0000000..faa31ca
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef UTILS_H
+#define UTILS_H
+
+#include <stdarg.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#define BUFFER_MAX_SIZE 10485760 
+
+void* safe_malloc(int size);
+
+// ---------------------------------------------------------------------------------
+// Generic growing buffer. Add data all you want
+// ---------------------------------------------------------------------------------
+struct growing_buffer_struct {
+       char *buf;
+       int n_used;
+       int size;
+};
+typedef struct growing_buffer_struct growing_buffer;
+
+growing_buffer* buffer_init( int initial_num_bytes);
+int buffer_addchar(growing_buffer* gb, char c);
+int buffer_add(growing_buffer* gb, char* c);
+int buffer_fadd(growing_buffer* gb, const char* format, ... );
+int buffer_reset( growing_buffer* gb);
+char* buffer_data( growing_buffer* gb);
+int buffer_free( growing_buffer* gb );
+int buffer_add_char(growing_buffer* gb, char c);
+
+
+char* uescape( const char* string, int size, int full_escape );
+double get_timestamp_millis();
+
+/* utility methods */
+int set_fl( int fd, int flags );
+int clr_fl( int fd, int flags );
+
+
+
+// Utility method
+double get_timestamp_millis();
+
+
+
+
+#endif