- more tcp stuff (uses locking.h, hashtables, mostly untested)
authorAndrei Pelinescu-Onciul <andrei@iptel.org>
Mon, 20 Jan 2003 18:35:09 +0000 (18:35 +0000)
committerAndrei Pelinescu-Onciul <andrei@iptel.org>
Mon, 20 Jan 2003 18:35:09 +0000 (18:35 +0000)
- main exit cleanups (created cleanup(show_status() function that should prepare ser for exiting: dellocate everything, free sems a.s.o).

Makefile.defs
TODO
ip_addr.h
locking.h
main.c
sr_module.c
tcp_conn.h
tcp_init.h
tcp_main.c
timer.c
timer.h

index 2fb4d9c..f73c72e 100644 (file)
@@ -8,7 +8,7 @@
 VERSION = 0
 PATCHLEVEL = 8
 SUBLEVEL =   11
-EXTRAVERSION = pre4-tcp0-locking
+EXTRAVERSION = pre4-tcp1-locking
 
 RELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 OS = $(shell uname -s | sed -e s/SunOS/solaris/ | tr "[A-Z]" "[a-z]")
@@ -150,7 +150,7 @@ DEFS+= -DNAME='"$(NAME)"' -DVERSION='"$(RELEASE)"' -DARCH='"$(ARCH)"' \
         -DDNS_IP_HACK \
         -DUSE_IPV6 \
         -DDBG_QM_MALLOC \
-        -DUSE_TCP \
+        -DUSE_TCP \
         #-DF_MALLOC \
         #-DNO_DEBUG \
         #-DNO_LOG
diff --git a/TODO b/TODO
index 7181abd..01a2798 100644 (file)
--- a/TODO
+++ b/TODO
@@ -16,7 +16,7 @@ x (different way) add request header bitmap field for the modules
 
 
 High priority:
-- parse_uri should not copy anymore the uri members (and it should not 0
+x- parse_uri should not copy anymore the uri members (and it should not 0
  terminate them anylonger).
 x fix/replace T_REF/T_UNREF
 x review all the tm locking
@@ -66,3 +66,5 @@ x freopen stdin, stdout, stderr to /dev/null
 - add a section on building ser & configuring it for maximum performance
  (-DF_MALLOC, -DNO_DBG, ... sip_warning=0, a.s.o)
 - add src_port, dst_port, proto to cfg.{y,lex}
+x generic locking lib
+- convert tm to use new locking lib
index 0c1a0a2..3995cd4 100644 (file)
--- a/ip_addr.h
+++ b/ip_addr.h
@@ -49,6 +49,7 @@ struct ip_addr{
        
        /* 64 bits alligned address */
        union {
+               unsigned long  addrl[16/sizeof(long)]; /* long format*/
                unsigned int   addr32[4];
                unsigned short addr16[8];
                unsigned char  addr[16];
index 1b87551..70f7365 100644 (file)
--- a/locking.h
+++ b/locking.h
@@ -44,12 +44,6 @@ Implements:
 #ifndef _locking_h
 #define _locking_h
 
-#include "mem/mem.h"
-#ifdef SHM_MEM
-#include "mem/shm_mem.h"
-#else
-#error "locking requires shared memroy support"
-#endif
 
 #ifdef FAST_LOCK
 #include "fastlock.h"
@@ -179,5 +173,12 @@ inline static void lock_release(lock_t* lock)
 #endif
 
 
+/*shm_{malloc, free}*/
+#include "mem/mem.h"
+#ifdef SHM_MEM
+#include "mem/shm_mem.h"
+#else
+#error "locking requires shared memroy support"
+#endif
 
 #endif
diff --git a/main.c b/main.c
index 03298c5..8f40a2e 100644 (file)
--- a/main.c
+++ b/main.c
@@ -326,6 +326,38 @@ int is_main=0; /* flag = is this the  "main" process? */
 
 char* pid_file = 0; /* filename as asked by use */
 
+
+
+/* callit before exiting; if show_status==1, mem status is displayed */
+void cleanup(show_status)
+{
+       /*clean-up*/
+       destroy_modules();
+#ifdef USE_TCP
+       destroy_tcp();
+#endif
+       destroy_timer();
+#ifdef PKG_MALLOC
+       if (show_status){
+               LOG(memlog, "Memory status (pkg):\n");
+               pkg_status();
+       }
+#endif
+#ifdef SHM_MEM
+       shm_free(pt);
+       pt=0;
+       if (show_status){
+                       LOG(memlog, "Memory status (shm):\n");
+                       shm_status();
+       }
+       /* zero all shmem alloc vars that we still use */
+       shm_mem_destroy();
+#endif
+       if (pid_file) unlink(pid_file);
+}
+
+
+
 /* daemon init, return 0 on success, -1 on error */
 int daemonize(char*  name)
 {
@@ -472,20 +504,8 @@ void handle_sigs()
 
                             /* Wait for all the children to die */
                        while(wait(0) > 0);
-
-                       destroy_modules();
-#ifdef PKG_MALLOC
-                       LOG(memlog, "Memory status (pkg):\n");
-                       pkg_status();
-#endif
-#ifdef SHM_MEM
-                       LOG(memlog, "Memory status (shm):\n");
-                       shm_status();
-                       /* zero all shmem alloc vars that we still use */
-                       pt=0;
-                       shm_mem_destroy();
-#endif
-                       if (pid_file) unlink(pid_file);
+                       
+                       cleanup(1); /* cleanup & show status*/
                        dprint("Thank you for flying " NAME "\n");
                        exit(0);
                        break;
@@ -531,6 +551,8 @@ void handle_sigs()
 #endif
                        /* exit */
                        kill(0, SIGTERM);
+                       while(wait(0) > 0); /* wait for all the children to terminate*/
+                       cleanup(1); /* cleanup & show status*/
                        DBG("terminating due to SIGCHLD\n");
                        exit(0);
                        break;
@@ -1558,11 +1580,15 @@ try_again:
        ret=main_loop();
        /*kill everything*/
        kill(0, SIGTERM);
+       /*clean-up*/
+       cleanup(0);
        return ret;
 
 error:
        /*kill everything*/
        kill(0, SIGTERM);
+       /*clean-up*/
+       cleanup(0);
        return -1;
 
 }
index e3d6fdf..3fea44e 100644 (file)
@@ -256,6 +256,7 @@ void destroy_modules()
 
        for(t=modules;t;t=t->next)
                if  ((t->exports)&&(t->exports->destroy_f)) t->exports->destroy_f();
+       modules=0;
 }
 
 #ifdef NO_REVERSE_INIT
index 2c19567..2ee8d20 100644 (file)
@@ -89,8 +89,12 @@ struct tcp_connection{
        struct tcp_req req; /* request data */
        int refcnt;
        int timeout; /* connection timeout, after this it will be removed*/
+       unsigned addr_hash; /* hash indexes in thge 2 tables */
+       unsigned id_hash;
        struct tcp_connection* next; /* next, prev in hash table, used by "main" */
        struct tcp_connection* prev;
+       struct tcp_connection* id_next; /* next, prev in id hash table */
+       struct tcp_connection* id_prev;
        struct tcp_connection* c_next; /* child next prev (use locally) */
        struct tcp_connection* c_prev;
 };
@@ -128,11 +132,26 @@ struct tcp_connection{
        }while(0)
 
 
-#define TCPCONN_LOCK LOG(L_CRIT, "LOCK not implemented yet: %s : %d: %s\n", \
-                                                       __FILE__, __LINE__, __FUNCTION__);
-#define TCPCONN_UNLOCK LOG(L_CRIT, "UNLOCK not implemented yet: %s: %d: %s\n",\
-                                                       __FILE__, __LINE__, __FUNCTION__);
+#define TCPCONN_LOCK lock_get(tcpconn_lock);
+#define TCPCONN_UNLOCK lock_release(tcpconn_lock);
 
+#define TCP_ADDR_HASH_SIZE 1024
+#define TCP_ID_HASH_SIZE 1024
+
+static inline unsigned tcp_addr_hash(struct ip_addr* ip, unsigned short port)
+{
+       if(ip->len==4) return (ip->u.addr32[0]^port)&(TCP_ADDR_HASH_SIZE-1);
+       else if (ip->len==16) 
+                       return (ip->u.addr32[0]^ip->u.addr32[1]^ip->u.addr32[2]^
+                                       ip->u.addr32[3]^port) & (TCP_ADDR_HASH_SIZE-1);
+       else{
+               LOG(L_CRIT, "tcp_addr_hash: BUG: bad len %d for an ip address\n",
+                               ip->len);
+               return 0;
+       }
+}
+
+#define tcp_id_hash(id) (id&(TCP_ID_HASH_SIZE-1))
 
 
 #endif
index 383cec0..9226da0 100644 (file)
@@ -30,6 +30,7 @@
 #include "ip_addr.h"
 
 int init_tcp();
+void destroy_tcp();
 int tcp_init(struct socket_info* sock_info);
 int tcp_init_children();
 void tcp_main_loop();
index 7438d81..d3fd42d 100644 (file)
@@ -51,6 +51,7 @@
 #include "tcp_conn.h"
 #include "globals.h"
 #include "pt.h"
+#include "locking.h"
 #include "mem/mem.h"
 #include "mem/shm_mem.h"
 #include "timer.h"
@@ -59,6 +60,7 @@
 
 
 
+
 #define local_malloc pkg_malloc
 #define local_free   pkg_free
 
@@ -73,7 +75,12 @@ struct tcp_child{
 
 
 
-struct tcp_connection** conn_list=0;
+/* connection hash table (after ip&port) */
+struct tcp_connection** tcpconn_addr_hash=0;
+/* connection hash table (after connection id) */
+struct tcp_connection** tcpconn_id_hash=0;
+lock_t* tcpconn_lock=0;
+
 struct tcp_child tcp_children[MAX_TCP_CHILDREN];
 static int connection_id=1; /*  unique for each connection, used for 
                                                                quickly finding the corresponding connection
@@ -143,11 +150,24 @@ error:
 
 struct tcp_connection*  tcpconn_add(struct tcp_connection *c)
 {
-       TCPCONN_LOCK;
-       /* add it at the begining of the list*/
-       if (c) tcpconn_listadd(*conn_list, c, next, prev);
-       TCPCONN_UNLOCK;
-       return c;
+       unsigned hash;
+
+       if (c){
+               TCPCONN_LOCK;
+               /* add it at the begining of the list*/
+               hash=tcp_addr_hash(&c->rcv.src_ip, c->rcv.src_port);
+               c->addr_hash=hash;
+               tcpconn_listadd(tcpconn_addr_hash[hash], c, next, prev);
+               hash=tcp_id_hash(c->id);
+               c->id_hash=hash;
+               tcpconn_listadd(tcpconn_id_hash[hash], c, id_next, id_prev);
+               TCPCONN_UNLOCK;
+               DBG("tcpconn_add: hashes: %d, %d\n", c->addr_hash, c->id_hash);
+               return c;
+       }else{
+               LOG(L_CRIT, "tcpconn_add: BUG: null connection pointer\n");
+               return 0;
+       }
 }
 
 
@@ -155,39 +175,52 @@ struct tcp_connection*  tcpconn_add(struct tcp_connection *c)
 void tcpconn_rm(struct tcp_connection* c)
 {
        TCPCONN_LOCK;
-       tcpconn_listrm(*conn_list, c, next, prev);
+       tcpconn_listrm(tcpconn_addr_hash[c->addr_hash], c, next, prev);
+       tcpconn_listrm(tcpconn_id_hash[c->id_hash], c, id_next, id_prev);
        TCPCONN_UNLOCK;
        shm_free(c);
 }
 
 
-/* finds a connection, if id=0 uses the ip addr & port */
-struct tcp_connection* tcpconn_find(int id, struct ip_addr* ip, int port)
+/* finds a connection, if id=0 uses the ip addr & port
+ * WARNING: unprotected (locks) use tcpconn_get unless you really
+ * know what you are doing */
+struct tcp_connection* _tcpconn_find(int id, struct ip_addr* ip, int port)
 {
 
        struct tcp_connection *c;
+       unsigned hash;
        
        DBG("tcpconn_find: %d ",id ); print_ip(ip); DBG(" %d\n", ntohs(port));
-       for (c=*conn_list; c; c=c->next){
-               DBG("c=%p, c->id=%d, ip=",c, c->id);
-               print_ip(&c->rcv.src_ip);
-               DBG(" port=%d\n", ntohs(c->rcv.src_port));
-               if (id){
+       if (id){
+               hash=tcp_id_hash(id);
+               for (c=tcpconn_id_hash[hash]; c; c=c->id_next){
+                       DBG("c=%p, c->id=%d, ip=",c, c->id);
+                       print_ip(&c->rcv.src_ip);
+                       DBG(" port=%d\n", ntohs(c->rcv.src_port));
                        if (id==c->id) return c;
-               }else if (ip && (port==c->rcv.src_port)&&
-                                       (ip_addr_cmp(ip, &c->rcv.src_ip)))
-                       return c;
+               }
+       }else if (ip){
+               hash=tcp_addr_hash(ip, port);
+               for (c=tcpconn_addr_hash[hash]; c; c=c->next){
+                       DBG("c=%p, c->id=%d, ip=",c, c->id);
+                       print_ip(&c->rcv.src_ip);
+                       DBG(" port=%d\n", ntohs(c->rcv.src_port));
+                       if ( (port==c->rcv.src_port) && (ip_addr_cmp(ip, &c->rcv.src_ip)) )
+                               return c;
+               }
        }
        return 0;
 }
 
 
 
+/* _tcpconn_find with locks */
 struct tcp_connection* tcpconn_get(int id, struct ip_addr* ip, int port)
 {
        struct tcp_connection* c;
        TCPCONN_LOCK;
-       c=tcpconn_find(id, ip, port);
+       c=_tcpconn_find(id, ip, port);
        if (c) c->refcnt++;
        TCPCONN_UNLOCK;
        return c;
@@ -275,27 +308,30 @@ send_it:
 
 
 
-/* very ineficient for now, use hashtable some day - FIXME*/
+/* very ineficient for now - FIXME*/
 void tcpconn_timeout(fd_set* set)
 {
        struct tcp_connection *c, *next;
-       int ticks;;
+       int ticks;
+       unsigned h;;
        
        
        ticks=get_ticks();
-       c=*conn_list;
-       while(c){
-               next=c->next;
-               if ((c->refcnt==0) && (ticks>c->timeout)) {
-                       DBG("tcpconn_timeout: timeout for %p (%d > %d)\n",
-                                       c, ticks, c->timeout);
-                       if (c->s>0) {
-                               FD_CLR(c->s, set);
-                               close(c->s);
+       for(h=0; h<TCP_ADDR_HASH_SIZE; h++){
+               c=tcpconn_addr_hash[h];
+               while(c){
+                       next=c->next;
+                       if ((c->refcnt==0) && (ticks>c->timeout)) {
+                               DBG("tcpconn_timeout: timeout for hash=%d - %p (%d > %d)\n",
+                                               h, c, ticks, c->timeout);
+                               if (c->s>0) {
+                                       FD_CLR(c->s, set);
+                                       close(c->s);
+                               }
+                               tcpconn_rm(c);
                        }
-                       tcpconn_rm(c);
+                       c=next;
                }
-               c=next;
        }
 }
 
@@ -390,6 +426,7 @@ void tcp_main_loop()
        int new_sock;
        union sockaddr_union su;
        struct tcp_connection* tcpconn;
+       unsigned h;
        long response[2];
        int cmd;
        int bytes;
@@ -459,24 +496,26 @@ void tcp_main_loop()
                        }
                }
                
-               /* check all the read fds (from the tcpconn list) */
-               
-               for(tcpconn=*conn_list; tcpconn && n; tcpconn=tcpconn->next){
-                       if ((tcpconn->refcnt==0)&&(FD_ISSET(tcpconn->s, &sel_set))){
-                               /* new data available */
-                               n--;
-                               /* pass it to child, so remove it from select list */
-                               DBG("tcp_main_loop: data available on %p %d\n",
-                                               tcpconn, tcpconn->s);
-                               FD_CLR(tcpconn->s, &master_set);
-                               if (send2child(tcpconn)<0){
-                                       LOG(L_ERR,"ERROR: tcp_main_loop: no children available\n");
-                                       close(tcpconn->s);
-                                       tcpconn_rm(tcpconn);
+               /* check all the read fds (from the tcpconn_addr_hash ) */
+               for (h=0; h<TCP_ADDR_HASH_SIZE; h++){
+                       for(tcpconn=tcpconn_addr_hash[h]; tcpconn && n; 
+                                       tcpconn=tcpconn->next){
+                               if ((tcpconn->refcnt==0)&&(FD_ISSET(tcpconn->s, &sel_set))){
+                                       /* new data available */
+                                       n--;
+                                       /* pass it to child, so remove it from select list */
+                                       DBG("tcp_main_loop: data available on %p [h:%d] %d\n",
+                                                       tcpconn, h, tcpconn->s);
+                                       FD_CLR(tcpconn->s, &master_set);
+                                       if (send2child(tcpconn)<0){
+                                               LOG(L_ERR,"ERROR: tcp_main_loop: no "
+                                                                       "children available\n");
+                                               close(tcpconn->s);
+                                               tcpconn_rm(tcpconn);
+                                       }
                                }
                        }
                }
-               
                /* check unix sockets & listen | destroy connections */
                /* start from 1, the "main" process does not transmit anything*/
                for (r=1; r<process_no && n; r++){
@@ -589,13 +628,46 @@ read_again:
 
 int init_tcp()
 {
-       /* allocate list head*/
-       conn_list=shm_malloc(sizeof(struct tcp_connection*));
-       if (conn_list==0){
-               LOG(L_CRIT, "ERROR: init_tcp: memory allocation failure\n");
+       /* init lock */
+       tcpconn_lock=lock_alloc();
+       if (tcpconn_lock==0){
+               LOG(L_CRIT, "ERROR: init_tcp: could not alloc lock\n");
+               goto error;
+       }
+       if (lock_init(tcpconn_lock)==0){
+               LOG(L_CRIT, "ERROR: init_tcp: could not init lock\n");
+               lock_dealloc((void*)tcpconn_lock);
+               tcpconn_lock=0;
+               goto error;
+       }
+       /* alloc hashtables*/
+       tcpconn_addr_hash=(struct tcp_connection**)shm_malloc(TCP_ADDR_HASH_SIZE*
+                                                               sizeof(struct tcp_connection*));
+
+       if (tcpconn_addr_hash==0){
+               LOG(L_CRIT, "ERROR: init_tcp: could not alloc address hashtable\n");
+               lock_destroy(tcpconn_lock);
+               lock_dealloc((void*)tcpconn_lock);
+               tcpconn_lock=0;
+               goto error;
+       }
+       
+       tcpconn_id_hash=(struct tcp_connection**)shm_malloc(TCP_ID_HASH_SIZE*
+                                                               sizeof(struct tcp_connection*));
+       if (tcpconn_id_hash==0){
+               LOG(L_CRIT, "ERROR: init_tcp: could not alloc id hashtable\n");
+               shm_free(tcpconn_addr_hash);
+               tcpconn_addr_hash=0;
+               lock_destroy(tcpconn_lock);
+               lock_dealloc((void*)tcpconn_lock);
+               tcpconn_lock=0;
                goto error;
        }
-       *conn_list=0;
+       /* init hashtables*/
+       memset((void*)tcpconn_addr_hash, 0, 
+                       TCP_ADDR_HASH_SIZE * sizeof(struct tcp_connection*));
+       memset((void*)tcpconn_id_hash, 0, 
+                       TCP_ID_HASH_SIZE * sizeof(struct tcp_connection*));
        return 0;
 error:
                return -1;
@@ -603,6 +675,26 @@ error:
 
 
 
+/* cleanup before exit */
+void destroy_tcp()
+{
+       if (tcpconn_lock){
+               lock_destroy(tcpconn_lock);
+               lock_dealloc((void*)tcpconn_lock);
+               tcpconn_lock=0;
+       }
+       if(tcpconn_addr_hash){
+               shm_free(tcpconn_addr_hash);
+               tcpconn_addr_hash=0;
+       }
+       if(tcpconn_id_hash){
+               shm_free(tcpconn_id_hash);
+               tcpconn_id_hash=0;
+       }
+}
+
+
+
 /* starts the tcp processes */
 int tcp_init_children()
 {
diff --git a/timer.c b/timer.c
index e22befc..ff53de0 100644 (file)
--- a/timer.c
+++ b/timer.c
@@ -66,7 +66,19 @@ int init_timer()
 
 
 
-       
+void destroy_timer()
+{
+       if (jiffies){
+#ifdef SHM_MEM
+               shm_free(jiffies); jiffies=0;
+#else
+               free(jiffies); jiffies=0;
+#endif
+       }
+}
+
+
+
 /*register a periodic timer;
  * ret: <0 on error*/
 int register_timer(timer_function f, void* param, unsigned int interval)
diff --git a/timer.h b/timer.h
index 120a7a7..3a6e982 100644 (file)
--- a/timer.h
+++ b/timer.h
@@ -54,6 +54,7 @@ extern struct sr_timer* timer_list;
 
 
 int init_timer();
+void destroy_timer();
 /*register a periodic timer;
  * ret: <0 on errror*/
 int register_timer(timer_function f, void* param, unsigned int interval);