Browse code

- more tcp stuff (uses locking.h, hashtables, mostly untested) - main exit cleanups (created cleanup(show_status() function that should prepare ser for exiting: dellocate everything, free sems a.s.o).

Andrei Pelinescu-Onciul authored on 20/01/2003 18:35:09
Showing 11 changed files
... ...
@@ -8,7 +8,7 @@
8 8
 VERSION = 0
9 9
 PATCHLEVEL = 8
10 10
 SUBLEVEL =   11
11
-EXTRAVERSION = pre4-tcp0-locking
11
+EXTRAVERSION = pre4-tcp1-locking
12 12
 
13 13
 RELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
14 14
 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)"' \
150 150
 	 -DDNS_IP_HACK \
151 151
 	 -DUSE_IPV6 \
152 152
 	 -DDBG_QM_MALLOC \
153
-	 # -DUSE_TCP \
153
+	 -DUSE_TCP \
154 154
 	 #-DF_MALLOC \
155 155
 	 #-DNO_DEBUG \
156 156
 	 #-DNO_LOG
... ...
@@ -16,7 +16,7 @@ x (different way) add request header bitmap field for the modules
16 16
 
17 17
 
18 18
 High priority:
19
-- parse_uri should not copy anymore the uri members (and it should not 0
19
+x- parse_uri should not copy anymore the uri members (and it should not 0
20 20
  terminate them anylonger).
21 21
 x fix/replace T_REF/T_UNREF
22 22
 x review all the tm locking
... ...
@@ -66,3 +66,5 @@ x freopen stdin, stdout, stderr to /dev/null
66 66
 - add a section on building ser & configuring it for maximum performance
67 67
  (-DF_MALLOC, -DNO_DBG, ... sip_warning=0, a.s.o)
68 68
 - add src_port, dst_port, proto to cfg.{y,lex}
69
+x generic locking lib
70
+- convert tm to use new locking lib
... ...
@@ -49,6 +49,7 @@ struct ip_addr{
49 49
 	
50 50
 	/* 64 bits alligned address */
51 51
 	union {
52
+		unsigned long  addrl[16/sizeof(long)]; /* long format*/
52 53
 		unsigned int   addr32[4];
53 54
 		unsigned short addr16[8];
54 55
 		unsigned char  addr[16];
... ...
@@ -44,12 +44,6 @@ Implements:
44 44
 #ifndef _locking_h
45 45
 #define _locking_h
46 46
 
47
-#include "mem/mem.h"
48
-#ifdef SHM_MEM
49
-#include "mem/shm_mem.h"
50
-#else
51
-#error "locking requires shared memroy support"
52
-#endif
53 47
 
54 48
 #ifdef FAST_LOCK
55 49
 #include "fastlock.h"
... ...
@@ -179,5 +173,12 @@ inline static void lock_release(lock_t* lock)
179 179
 #endif
180 180
 
181 181
 
182
+/*shm_{malloc, free}*/
183
+#include "mem/mem.h"
184
+#ifdef SHM_MEM
185
+#include "mem/shm_mem.h"
186
+#else
187
+#error "locking requires shared memroy support"
188
+#endif
182 189
 
183 190
 #endif
... ...
@@ -326,6 +326,38 @@ int is_main=0; /* flag = is this the  "main" process? */
326 326
 
327 327
 char* pid_file = 0; /* filename as asked by use */
328 328
 
329
+
330
+
331
+/* callit before exiting; if show_status==1, mem status is displayed */
332
+void cleanup(show_status)
333
+{
334
+	/*clean-up*/
335
+	destroy_modules();
336
+#ifdef USE_TCP
337
+	destroy_tcp();
338
+#endif
339
+	destroy_timer();
340
+#ifdef PKG_MALLOC
341
+	if (show_status){
342
+		LOG(memlog, "Memory status (pkg):\n");
343
+		pkg_status();
344
+	}
345
+#endif
346
+#ifdef SHM_MEM
347
+	shm_free(pt);
348
+	pt=0;
349
+	if (show_status){
350
+			LOG(memlog, "Memory status (shm):\n");
351
+			shm_status();
352
+	}
353
+	/* zero all shmem alloc vars that we still use */
354
+	shm_mem_destroy();
355
+#endif
356
+	if (pid_file) unlink(pid_file);
357
+}
358
+
359
+
360
+
329 361
 /* daemon init, return 0 on success, -1 on error */
330 362
 int daemonize(char*  name)
331 363
 {
... ...
@@ -472,20 +504,8 @@ void handle_sigs()
472 472
 
473 473
 			     /* Wait for all the children to die */
474 474
 			while(wait(0) > 0);
475
-
476
-			destroy_modules();
477
-#ifdef PKG_MALLOC
478
-			LOG(memlog, "Memory status (pkg):\n");
479
-			pkg_status();
480
-#endif
481
-#ifdef SHM_MEM
482
-			LOG(memlog, "Memory status (shm):\n");
483
-			shm_status();
484
-			/* zero all shmem alloc vars that we still use */
485
-			pt=0;
486
-			shm_mem_destroy();
487
-#endif
488
-			if (pid_file) unlink(pid_file);
475
+			
476
+			cleanup(1); /* cleanup & show status*/
489 477
 			dprint("Thank you for flying " NAME "\n");
490 478
 			exit(0);
491 479
 			break;
... ...
@@ -531,6 +551,8 @@ void handle_sigs()
531 531
 #endif
532 532
 			/* exit */
533 533
 			kill(0, SIGTERM);
534
+			while(wait(0) > 0); /* wait for all the children to terminate*/
535
+			cleanup(1); /* cleanup & show status*/
534 536
 			DBG("terminating due to SIGCHLD\n");
535 537
 			exit(0);
536 538
 			break;
... ...
@@ -1558,11 +1580,15 @@ try_again:
1558 1558
 	ret=main_loop();
1559 1559
 	/*kill everything*/
1560 1560
 	kill(0, SIGTERM);
1561
+	/*clean-up*/
1562
+	cleanup(0);
1561 1563
 	return ret;
1562 1564
 
1563 1565
 error:
1564 1566
 	/*kill everything*/
1565 1567
 	kill(0, SIGTERM);
1568
+	/*clean-up*/
1569
+	cleanup(0);
1566 1570
 	return -1;
1567 1571
 
1568 1572
 }
... ...
@@ -256,6 +256,7 @@ void destroy_modules()
256 256
 
257 257
 	for(t=modules;t;t=t->next)
258 258
 		if  ((t->exports)&&(t->exports->destroy_f)) t->exports->destroy_f();
259
+	modules=0;
259 260
 }
260 261
 
261 262
 #ifdef NO_REVERSE_INIT
... ...
@@ -89,8 +89,12 @@ struct tcp_connection{
89 89
 	struct tcp_req req; /* request data */
90 90
 	int refcnt;
91 91
 	int timeout; /* connection timeout, after this it will be removed*/
92
+	unsigned addr_hash; /* hash indexes in thge 2 tables */
93
+	unsigned id_hash;
92 94
 	struct tcp_connection* next; /* next, prev in hash table, used by "main" */
93 95
 	struct tcp_connection* prev;
96
+	struct tcp_connection* id_next; /* next, prev in id hash table */
97
+	struct tcp_connection* id_prev;
94 98
 	struct tcp_connection* c_next; /* child next prev (use locally) */
95 99
 	struct tcp_connection* c_prev;
96 100
 };
... ...
@@ -128,11 +132,26 @@ struct tcp_connection{
128 128
 	}while(0)
129 129
 
130 130
 
131
-#define TCPCONN_LOCK LOG(L_CRIT, "LOCK not implemented yet: %s : %d: %s\n", \
132
-							__FILE__, __LINE__, __FUNCTION__);
133
-#define TCPCONN_UNLOCK LOG(L_CRIT, "UNLOCK not implemented yet: %s: %d: %s\n",\
134
-							__FILE__, __LINE__, __FUNCTION__);
131
+#define TCPCONN_LOCK lock_get(tcpconn_lock);
132
+#define TCPCONN_UNLOCK lock_release(tcpconn_lock);
135 133
 
134
+#define TCP_ADDR_HASH_SIZE 1024
135
+#define TCP_ID_HASH_SIZE 1024
136
+
137
+static inline unsigned tcp_addr_hash(struct ip_addr* ip, unsigned short port)
138
+{
139
+	if(ip->len==4) return (ip->u.addr32[0]^port)&(TCP_ADDR_HASH_SIZE-1);
140
+	else if (ip->len==16) 
141
+			return (ip->u.addr32[0]^ip->u.addr32[1]^ip->u.addr32[2]^
142
+					ip->u.addr32[3]^port) & (TCP_ADDR_HASH_SIZE-1);
143
+	else{
144
+		LOG(L_CRIT, "tcp_addr_hash: BUG: bad len %d for an ip address\n",
145
+				ip->len);
146
+		return 0;
147
+	}
148
+}
149
+
150
+#define tcp_id_hash(id) (id&(TCP_ID_HASH_SIZE-1))
136 151
 
137 152
 
138 153
 #endif
... ...
@@ -30,6 +30,7 @@
30 30
 #include "ip_addr.h"
31 31
 
32 32
 int init_tcp();
33
+void destroy_tcp();
33 34
 int tcp_init(struct socket_info* sock_info);
34 35
 int tcp_init_children();
35 36
 void tcp_main_loop();
... ...
@@ -51,6 +51,7 @@
51 51
 #include "tcp_conn.h"
52 52
 #include "globals.h"
53 53
 #include "pt.h"
54
+#include "locking.h"
54 55
 #include "mem/mem.h"
55 56
 #include "mem/shm_mem.h"
56 57
 #include "timer.h"
... ...
@@ -59,6 +60,7 @@
59 59
 
60 60
 
61 61
 
62
+
62 63
 #define local_malloc pkg_malloc
63 64
 #define local_free   pkg_free
64 65
 
... ...
@@ -73,7 +75,12 @@ struct tcp_child{
73 73
 
74 74
 
75 75
 
76
-struct tcp_connection** conn_list=0;
76
+/* connection hash table (after ip&port) */
77
+struct tcp_connection** tcpconn_addr_hash=0;
78
+/* connection hash table (after connection id) */
79
+struct tcp_connection** tcpconn_id_hash=0;
80
+lock_t* tcpconn_lock=0;
81
+
77 82
 struct tcp_child tcp_children[MAX_TCP_CHILDREN];
78 83
 static int connection_id=1; /*  unique for each connection, used for 
79 84
 								quickly finding the corresponding connection
... ...
@@ -143,11 +150,24 @@ error:
143 143
 
144 144
 struct tcp_connection*  tcpconn_add(struct tcp_connection *c)
145 145
 {
146
-	TCPCONN_LOCK;
147
-	/* add it at the begining of the list*/
148
-	if (c) tcpconn_listadd(*conn_list, c, next, prev);
149
-	TCPCONN_UNLOCK;
150
-	return c;
146
+	unsigned hash;
147
+
148
+	if (c){
149
+		TCPCONN_LOCK;
150
+		/* add it at the begining of the list*/
151
+		hash=tcp_addr_hash(&c->rcv.src_ip, c->rcv.src_port);
152
+		c->addr_hash=hash;
153
+		tcpconn_listadd(tcpconn_addr_hash[hash], c, next, prev);
154
+		hash=tcp_id_hash(c->id);
155
+		c->id_hash=hash;
156
+		tcpconn_listadd(tcpconn_id_hash[hash], c, id_next, id_prev);
157
+		TCPCONN_UNLOCK;
158
+		DBG("tcpconn_add: hashes: %d, %d\n", c->addr_hash, c->id_hash);
159
+		return c;
160
+	}else{
161
+		LOG(L_CRIT, "tcpconn_add: BUG: null connection pointer\n");
162
+		return 0;
163
+	}
151 164
 }
152 165
 
153 166
 
... ...
@@ -155,39 +175,52 @@ struct tcp_connection*  tcpconn_add(struct tcp_connection *c)
155 155
 void tcpconn_rm(struct tcp_connection* c)
156 156
 {
157 157
 	TCPCONN_LOCK;
158
-	tcpconn_listrm(*conn_list, c, next, prev);
158
+	tcpconn_listrm(tcpconn_addr_hash[c->addr_hash], c, next, prev);
159
+	tcpconn_listrm(tcpconn_id_hash[c->id_hash], c, id_next, id_prev);
159 160
 	TCPCONN_UNLOCK;
160 161
 	shm_free(c);
161 162
 }
162 163
 
163 164
 
164
-/* finds a connection, if id=0 uses the ip addr & port */
165
-struct tcp_connection* tcpconn_find(int id, struct ip_addr* ip, int port)
165
+/* finds a connection, if id=0 uses the ip addr & port
166
+ * WARNING: unprotected (locks) use tcpconn_get unless you really
167
+ * know what you are doing */
168
+struct tcp_connection* _tcpconn_find(int id, struct ip_addr* ip, int port)
166 169
 {
167 170
 
168 171
 	struct tcp_connection *c;
172
+	unsigned hash;
169 173
 	
170 174
 	DBG("tcpconn_find: %d ",id ); print_ip(ip); DBG(" %d\n", ntohs(port));
171
-	for (c=*conn_list; c; c=c->next){
172
-		DBG("c=%p, c->id=%d, ip=",c, c->id);
173
-		print_ip(&c->rcv.src_ip);
174
-		DBG(" port=%d\n", ntohs(c->rcv.src_port));
175
-		if (id){
175
+	if (id){
176
+		hash=tcp_id_hash(id);
177
+		for (c=tcpconn_id_hash[hash]; c; c=c->id_next){
178
+			DBG("c=%p, c->id=%d, ip=",c, c->id);
179
+			print_ip(&c->rcv.src_ip);
180
+			DBG(" port=%d\n", ntohs(c->rcv.src_port));
176 181
 			if (id==c->id) return c;
177
-		}else if (ip &&	(port==c->rcv.src_port)&&
178
-					(ip_addr_cmp(ip, &c->rcv.src_ip)))
179
-			return c;
182
+		}
183
+	}else if (ip){
184
+		hash=tcp_addr_hash(ip, port);
185
+		for (c=tcpconn_addr_hash[hash]; c; c=c->next){
186
+			DBG("c=%p, c->id=%d, ip=",c, c->id);
187
+			print_ip(&c->rcv.src_ip);
188
+			DBG(" port=%d\n", ntohs(c->rcv.src_port));
189
+			if ( (port==c->rcv.src_port) && (ip_addr_cmp(ip, &c->rcv.src_ip)) )
190
+				return c;
191
+		}
180 192
 	}
181 193
 	return 0;
182 194
 }
183 195
 
184 196
 
185 197
 
198
+/* _tcpconn_find with locks */
186 199
 struct tcp_connection* tcpconn_get(int id, struct ip_addr* ip, int port)
187 200
 {
188 201
 	struct tcp_connection* c;
189 202
 	TCPCONN_LOCK;
190
-	c=tcpconn_find(id, ip, port);
203
+	c=_tcpconn_find(id, ip, port);
191 204
 	if (c) c->refcnt++;
192 205
 	TCPCONN_UNLOCK;
193 206
 	return c;
... ...
@@ -275,27 +308,30 @@ send_it:
275 275
 
276 276
 
277 277
 
278
-/* very ineficient for now, use hashtable some day - FIXME*/
278
+/* very ineficient for now - FIXME*/
279 279
 void tcpconn_timeout(fd_set* set)
280 280
 {
281 281
 	struct tcp_connection *c, *next;
282
-	int ticks;;
282
+	int ticks;
283
+	unsigned h;;
283 284
 	
284 285
 	
285 286
 	ticks=get_ticks();
286
-	c=*conn_list;
287
-	while(c){
288
-		next=c->next;
289
-		if ((c->refcnt==0) && (ticks>c->timeout)) {
290
-			DBG("tcpconn_timeout: timeout for %p (%d > %d)\n",
291
-					c, ticks, c->timeout);
292
-			if (c->s>0) {
293
-				FD_CLR(c->s, set);
294
-				close(c->s);
287
+	for(h=0; h<TCP_ADDR_HASH_SIZE; h++){
288
+		c=tcpconn_addr_hash[h];
289
+		while(c){
290
+			next=c->next;
291
+			if ((c->refcnt==0) && (ticks>c->timeout)) {
292
+				DBG("tcpconn_timeout: timeout for hash=%d - %p (%d > %d)\n",
293
+						h, c, ticks, c->timeout);
294
+				if (c->s>0) {
295
+					FD_CLR(c->s, set);
296
+					close(c->s);
297
+				}
298
+				tcpconn_rm(c);
295 299
 			}
296
-			tcpconn_rm(c);
300
+			c=next;
297 301
 		}
298
-		c=next;
299 302
 	}
300 303
 }
301 304
 
... ...
@@ -390,6 +426,7 @@ void tcp_main_loop()
390 390
 	int new_sock;
391 391
 	union sockaddr_union su;
392 392
 	struct tcp_connection* tcpconn;
393
+	unsigned h;
393 394
 	long response[2];
394 395
 	int cmd;
395 396
 	int bytes;
... ...
@@ -459,24 +496,26 @@ void tcp_main_loop()
459 459
 			}
460 460
 		}
461 461
 		
462
-		/* check all the read fds (from the tcpconn list) */
463
-		
464
-		for(tcpconn=*conn_list; tcpconn && n; tcpconn=tcpconn->next){
465
-			if ((tcpconn->refcnt==0)&&(FD_ISSET(tcpconn->s, &sel_set))){
466
-				/* new data available */
467
-				n--;
468
-				/* pass it to child, so remove it from select list */
469
-				DBG("tcp_main_loop: data available on %p %d\n",
470
-						tcpconn, tcpconn->s);
471
-				FD_CLR(tcpconn->s, &master_set);
472
-				if (send2child(tcpconn)<0){
473
-					LOG(L_ERR,"ERROR: tcp_main_loop: no children available\n");
474
-					close(tcpconn->s);
475
-					tcpconn_rm(tcpconn);
462
+		/* check all the read fds (from the tcpconn_addr_hash ) */
463
+		for (h=0; h<TCP_ADDR_HASH_SIZE; h++){
464
+			for(tcpconn=tcpconn_addr_hash[h]; tcpconn && n; 
465
+					tcpconn=tcpconn->next){
466
+				if ((tcpconn->refcnt==0)&&(FD_ISSET(tcpconn->s, &sel_set))){
467
+					/* new data available */
468
+					n--;
469
+					/* pass it to child, so remove it from select list */
470
+					DBG("tcp_main_loop: data available on %p [h:%d] %d\n",
471
+							tcpconn, h, tcpconn->s);
472
+					FD_CLR(tcpconn->s, &master_set);
473
+					if (send2child(tcpconn)<0){
474
+						LOG(L_ERR,"ERROR: tcp_main_loop: no "
475
+									"children available\n");
476
+						close(tcpconn->s);
477
+						tcpconn_rm(tcpconn);
478
+					}
476 479
 				}
477 480
 			}
478 481
 		}
479
-		
480 482
 		/* check unix sockets & listen | destroy connections */
481 483
 		/* start from 1, the "main" process does not transmit anything*/
482 484
 		for (r=1; r<process_no && n; r++){
... ...
@@ -589,13 +628,46 @@ read_again:
589 589
 
590 590
 int init_tcp()
591 591
 {
592
-	/* allocate list head*/
593
-	conn_list=shm_malloc(sizeof(struct tcp_connection*));
594
-	if (conn_list==0){
595
-		LOG(L_CRIT, "ERROR: init_tcp: memory allocation failure\n");
592
+	/* init lock */
593
+	tcpconn_lock=lock_alloc();
594
+	if (tcpconn_lock==0){
595
+		LOG(L_CRIT, "ERROR: init_tcp: could not alloc lock\n");
596
+		goto error;
597
+	}
598
+	if (lock_init(tcpconn_lock)==0){
599
+		LOG(L_CRIT, "ERROR: init_tcp: could not init lock\n");
600
+		lock_dealloc((void*)tcpconn_lock);
601
+		tcpconn_lock=0;
602
+		goto error;
603
+	}
604
+	/* alloc hashtables*/
605
+	tcpconn_addr_hash=(struct tcp_connection**)shm_malloc(TCP_ADDR_HASH_SIZE*
606
+								sizeof(struct tcp_connection*));
607
+
608
+	if (tcpconn_addr_hash==0){
609
+		LOG(L_CRIT, "ERROR: init_tcp: could not alloc address hashtable\n");
610
+		lock_destroy(tcpconn_lock);
611
+		lock_dealloc((void*)tcpconn_lock);
612
+		tcpconn_lock=0;
613
+		goto error;
614
+	}
615
+	
616
+	tcpconn_id_hash=(struct tcp_connection**)shm_malloc(TCP_ID_HASH_SIZE*
617
+								sizeof(struct tcp_connection*));
618
+	if (tcpconn_id_hash==0){
619
+		LOG(L_CRIT, "ERROR: init_tcp: could not alloc id hashtable\n");
620
+		shm_free(tcpconn_addr_hash);
621
+		tcpconn_addr_hash=0;
622
+		lock_destroy(tcpconn_lock);
623
+		lock_dealloc((void*)tcpconn_lock);
624
+		tcpconn_lock=0;
596 625
 		goto error;
597 626
 	}
598
-	*conn_list=0;
627
+	/* init hashtables*/
628
+	memset((void*)tcpconn_addr_hash, 0, 
629
+			TCP_ADDR_HASH_SIZE * sizeof(struct tcp_connection*));
630
+	memset((void*)tcpconn_id_hash, 0, 
631
+			TCP_ID_HASH_SIZE * sizeof(struct tcp_connection*));
599 632
 	return 0;
600 633
 error:
601 634
 		return -1;
... ...
@@ -603,6 +675,26 @@ error:
603 603
 
604 604
 
605 605
 
606
+/* cleanup before exit */
607
+void destroy_tcp()
608
+{
609
+	if (tcpconn_lock){
610
+		lock_destroy(tcpconn_lock);
611
+		lock_dealloc((void*)tcpconn_lock);
612
+		tcpconn_lock=0;
613
+	}
614
+	if(tcpconn_addr_hash){
615
+		shm_free(tcpconn_addr_hash);
616
+		tcpconn_addr_hash=0;
617
+	}
618
+	if(tcpconn_id_hash){
619
+		shm_free(tcpconn_id_hash);
620
+		tcpconn_id_hash=0;
621
+	}
622
+}
623
+
624
+
625
+
606 626
 /* starts the tcp processes */
607 627
 int tcp_init_children()
608 628
 {
... ...
@@ -66,7 +66,19 @@ int init_timer()
66 66
 
67 67
 
68 68
 
69
-	
69
+void destroy_timer()
70
+{
71
+	if (jiffies){
72
+#ifdef SHM_MEM
73
+		shm_free(jiffies); jiffies=0;
74
+#else
75
+		free(jiffies); jiffies=0;
76
+#endif
77
+	}
78
+}
79
+
80
+
81
+
70 82
 /*register a periodic timer;
71 83
  * ret: <0 on error*/
72 84
 int register_timer(timer_function f, void* param, unsigned int interval)
... ...
@@ -54,6 +54,7 @@ extern struct sr_timer* timer_list;
54 54
 
55 55
 
56 56
 int init_timer();
57
+void destroy_timer();
57 58
 /*register a periodic timer;
58 59
  * ret: <0 on errror*/
59 60
 int register_timer(timer_function f, void* param, unsigned int interval);