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 173
 #endif
180 174
 
181 175
 
176
+/*shm_{malloc, free}*/
177
+#include "mem/mem.h"
178
+#ifdef SHM_MEM
179
+#include "mem/shm_mem.h"
180
+#else
181
+#error "locking requires shared memroy support"
182
+#endif
182 183
 
183 184
 #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 504
 
473 505
 			     /* Wait for all the children to die */
474 506
 			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);
507
+			
508
+			cleanup(1); /* cleanup & show status*/
489 509
 			dprint("Thank you for flying " NAME "\n");
490 510
 			exit(0);
491 511
 			break;
... ...
@@ -531,6 +551,8 @@ void handle_sigs()
531 551
 #endif
532 552
 			/* exit */
533 553
 			kill(0, SIGTERM);
554
+			while(wait(0) > 0); /* wait for all the children to terminate*/
555
+			cleanup(1); /* cleanup & show status*/
534 556
 			DBG("terminating due to SIGCHLD\n");
535 557
 			exit(0);
536 558
 			break;
... ...
@@ -1558,11 +1580,15 @@ try_again:
1558 1580
 	ret=main_loop();
1559 1581
 	/*kill everything*/
1560 1582
 	kill(0, SIGTERM);
1583
+	/*clean-up*/
1584
+	cleanup(0);
1561 1585
 	return ret;
1562 1586
 
1563 1587
 error:
1564 1588
 	/*kill everything*/
1565 1589
 	kill(0, SIGTERM);
1590
+	/*clean-up*/
1591
+	cleanup(0);
1566 1592
 	return -1;
1567 1593
 
1568 1594
 }
... ...
@@ -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 132
 	}while(0)
129 133
 
130 134
 
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__);
135
+#define TCPCONN_LOCK lock_get(tcpconn_lock);
136
+#define TCPCONN_UNLOCK lock_release(tcpconn_lock);
135 137
 
138
+#define TCP_ADDR_HASH_SIZE 1024
139
+#define TCP_ID_HASH_SIZE 1024
140
+
141
+static inline unsigned tcp_addr_hash(struct ip_addr* ip, unsigned short port)
142
+{
143
+	if(ip->len==4) return (ip->u.addr32[0]^port)&(TCP_ADDR_HASH_SIZE-1);
144
+	else if (ip->len==16) 
145
+			return (ip->u.addr32[0]^ip->u.addr32[1]^ip->u.addr32[2]^
146
+					ip->u.addr32[3]^port) & (TCP_ADDR_HASH_SIZE-1);
147
+	else{
148
+		LOG(L_CRIT, "tcp_addr_hash: BUG: bad len %d for an ip address\n",
149
+				ip->len);
150
+		return 0;
151
+	}
152
+}
153
+
154
+#define tcp_id_hash(id) (id&(TCP_ID_HASH_SIZE-1))
136 155
 
137 156
 
138 157
 #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 60
 
60 61
 
61 62
 
63
+
62 64
 #define local_malloc pkg_malloc
63 65
 #define local_free   pkg_free
64 66
 
... ...
@@ -73,7 +75,12 @@ struct tcp_child{
73 75
 
74 76
 
75 77
 
76
-struct tcp_connection** conn_list=0;
78
+/* connection hash table (after ip&port) */
79
+struct tcp_connection** tcpconn_addr_hash=0;
80
+/* connection hash table (after connection id) */
81
+struct tcp_connection** tcpconn_id_hash=0;
82
+lock_t* tcpconn_lock=0;
83
+
77 84
 struct tcp_child tcp_children[MAX_TCP_CHILDREN];
78 85
 static int connection_id=1; /*  unique for each connection, used for 
79 86
 								quickly finding the corresponding connection
... ...
@@ -143,11 +150,24 @@ error:
143 150
 
144 151
 struct tcp_connection*  tcpconn_add(struct tcp_connection *c)
145 152
 {
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;
153
+	unsigned hash;
154
+
155
+	if (c){
156
+		TCPCONN_LOCK;
157
+		/* add it at the begining of the list*/
158
+		hash=tcp_addr_hash(&c->rcv.src_ip, c->rcv.src_port);
159
+		c->addr_hash=hash;
160
+		tcpconn_listadd(tcpconn_addr_hash[hash], c, next, prev);
161
+		hash=tcp_id_hash(c->id);
162
+		c->id_hash=hash;
163
+		tcpconn_listadd(tcpconn_id_hash[hash], c, id_next, id_prev);
164
+		TCPCONN_UNLOCK;
165
+		DBG("tcpconn_add: hashes: %d, %d\n", c->addr_hash, c->id_hash);
166
+		return c;
167
+	}else{
168
+		LOG(L_CRIT, "tcpconn_add: BUG: null connection pointer\n");
169
+		return 0;
170
+	}
151 171
 }
152 172
 
153 173
 
... ...
@@ -155,39 +175,52 @@ struct tcp_connection*  tcpconn_add(struct tcp_connection *c)
155 175
 void tcpconn_rm(struct tcp_connection* c)
156 176
 {
157 177
 	TCPCONN_LOCK;
158
-	tcpconn_listrm(*conn_list, c, next, prev);
178
+	tcpconn_listrm(tcpconn_addr_hash[c->addr_hash], c, next, prev);
179
+	tcpconn_listrm(tcpconn_id_hash[c->id_hash], c, id_next, id_prev);
159 180
 	TCPCONN_UNLOCK;
160 181
 	shm_free(c);
161 182
 }
162 183
 
163 184
 
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)
185
+/* finds a connection, if id=0 uses the ip addr & port
186
+ * WARNING: unprotected (locks) use tcpconn_get unless you really
187
+ * know what you are doing */
188
+struct tcp_connection* _tcpconn_find(int id, struct ip_addr* ip, int port)
166 189
 {
167 190
 
168 191
 	struct tcp_connection *c;
192
+	unsigned hash;
169 193
 	
170 194
 	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){
195
+	if (id){
196
+		hash=tcp_id_hash(id);
197
+		for (c=tcpconn_id_hash[hash]; c; c=c->id_next){
198
+			DBG("c=%p, c->id=%d, ip=",c, c->id);
199
+			print_ip(&c->rcv.src_ip);
200
+			DBG(" port=%d\n", ntohs(c->rcv.src_port));
176 201
 			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;
202
+		}
203
+	}else if (ip){
204
+		hash=tcp_addr_hash(ip, port);
205
+		for (c=tcpconn_addr_hash[hash]; c; c=c->next){
206
+			DBG("c=%p, c->id=%d, ip=",c, c->id);
207
+			print_ip(&c->rcv.src_ip);
208
+			DBG(" port=%d\n", ntohs(c->rcv.src_port));
209
+			if ( (port==c->rcv.src_port) && (ip_addr_cmp(ip, &c->rcv.src_ip)) )
210
+				return c;
211
+		}
180 212
 	}
181 213
 	return 0;
182 214
 }
183 215
 
184 216
 
185 217
 
218
+/* _tcpconn_find with locks */
186 219
 struct tcp_connection* tcpconn_get(int id, struct ip_addr* ip, int port)
187 220
 {
188 221
 	struct tcp_connection* c;
189 222
 	TCPCONN_LOCK;
190
-	c=tcpconn_find(id, ip, port);
223
+	c=_tcpconn_find(id, ip, port);
191 224
 	if (c) c->refcnt++;
192 225
 	TCPCONN_UNLOCK;
193 226
 	return c;
... ...
@@ -275,27 +308,30 @@ send_it:
275 308
 
276 309
 
277 310
 
278
-/* very ineficient for now, use hashtable some day - FIXME*/
311
+/* very ineficient for now - FIXME*/
279 312
 void tcpconn_timeout(fd_set* set)
280 313
 {
281 314
 	struct tcp_connection *c, *next;
282
-	int ticks;;
315
+	int ticks;
316
+	unsigned h;;
283 317
 	
284 318
 	
285 319
 	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);
320
+	for(h=0; h<TCP_ADDR_HASH_SIZE; h++){
321
+		c=tcpconn_addr_hash[h];
322
+		while(c){
323
+			next=c->next;
324
+			if ((c->refcnt==0) && (ticks>c->timeout)) {
325
+				DBG("tcpconn_timeout: timeout for hash=%d - %p (%d > %d)\n",
326
+						h, c, ticks, c->timeout);
327
+				if (c->s>0) {
328
+					FD_CLR(c->s, set);
329
+					close(c->s);
330
+				}
331
+				tcpconn_rm(c);
295 332
 			}
296
-			tcpconn_rm(c);
333
+			c=next;
297 334
 		}
298
-		c=next;
299 335
 	}
300 336
 }
301 337
 
... ...
@@ -390,6 +426,7 @@ void tcp_main_loop()
390 426
 	int new_sock;
391 427
 	union sockaddr_union su;
392 428
 	struct tcp_connection* tcpconn;
429
+	unsigned h;
393 430
 	long response[2];
394 431
 	int cmd;
395 432
 	int bytes;
... ...
@@ -459,24 +496,26 @@ void tcp_main_loop()
459 496
 			}
460 497
 		}
461 498
 		
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);
499
+		/* check all the read fds (from the tcpconn_addr_hash ) */
500
+		for (h=0; h<TCP_ADDR_HASH_SIZE; h++){
501
+			for(tcpconn=tcpconn_addr_hash[h]; tcpconn && n; 
502
+					tcpconn=tcpconn->next){
503
+				if ((tcpconn->refcnt==0)&&(FD_ISSET(tcpconn->s, &sel_set))){
504
+					/* new data available */
505
+					n--;
506
+					/* pass it to child, so remove it from select list */
507
+					DBG("tcp_main_loop: data available on %p [h:%d] %d\n",
508
+							tcpconn, h, tcpconn->s);
509
+					FD_CLR(tcpconn->s, &master_set);
510
+					if (send2child(tcpconn)<0){
511
+						LOG(L_ERR,"ERROR: tcp_main_loop: no "
512
+									"children available\n");
513
+						close(tcpconn->s);
514
+						tcpconn_rm(tcpconn);
515
+					}
476 516
 				}
477 517
 			}
478 518
 		}
479
-		
480 519
 		/* check unix sockets & listen | destroy connections */
481 520
 		/* start from 1, the "main" process does not transmit anything*/
482 521
 		for (r=1; r<process_no && n; r++){
... ...
@@ -589,13 +628,46 @@ read_again:
589 628
 
590 629
 int init_tcp()
591 630
 {
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");
631
+	/* init lock */
632
+	tcpconn_lock=lock_alloc();
633
+	if (tcpconn_lock==0){
634
+		LOG(L_CRIT, "ERROR: init_tcp: could not alloc lock\n");
635
+		goto error;
636
+	}
637
+	if (lock_init(tcpconn_lock)==0){
638
+		LOG(L_CRIT, "ERROR: init_tcp: could not init lock\n");
639
+		lock_dealloc((void*)tcpconn_lock);
640
+		tcpconn_lock=0;
641
+		goto error;
642
+	}
643
+	/* alloc hashtables*/
644
+	tcpconn_addr_hash=(struct tcp_connection**)shm_malloc(TCP_ADDR_HASH_SIZE*
645
+								sizeof(struct tcp_connection*));
646
+
647
+	if (tcpconn_addr_hash==0){
648
+		LOG(L_CRIT, "ERROR: init_tcp: could not alloc address hashtable\n");
649
+		lock_destroy(tcpconn_lock);
650
+		lock_dealloc((void*)tcpconn_lock);
651
+		tcpconn_lock=0;
652
+		goto error;
653
+	}
654
+	
655
+	tcpconn_id_hash=(struct tcp_connection**)shm_malloc(TCP_ID_HASH_SIZE*
656
+								sizeof(struct tcp_connection*));
657
+	if (tcpconn_id_hash==0){
658
+		LOG(L_CRIT, "ERROR: init_tcp: could not alloc id hashtable\n");
659
+		shm_free(tcpconn_addr_hash);
660
+		tcpconn_addr_hash=0;
661
+		lock_destroy(tcpconn_lock);
662
+		lock_dealloc((void*)tcpconn_lock);
663
+		tcpconn_lock=0;
596 664
 		goto error;
597 665
 	}
598
-	*conn_list=0;
666
+	/* init hashtables*/
667
+	memset((void*)tcpconn_addr_hash, 0, 
668
+			TCP_ADDR_HASH_SIZE * sizeof(struct tcp_connection*));
669
+	memset((void*)tcpconn_id_hash, 0, 
670
+			TCP_ID_HASH_SIZE * sizeof(struct tcp_connection*));
599 671
 	return 0;
600 672
 error:
601 673
 		return -1;
... ...
@@ -603,6 +675,26 @@ error:
603 675
 
604 676
 
605 677
 
678
+/* cleanup before exit */
679
+void destroy_tcp()
680
+{
681
+	if (tcpconn_lock){
682
+		lock_destroy(tcpconn_lock);
683
+		lock_dealloc((void*)tcpconn_lock);
684
+		tcpconn_lock=0;
685
+	}
686
+	if(tcpconn_addr_hash){
687
+		shm_free(tcpconn_addr_hash);
688
+		tcpconn_addr_hash=0;
689
+	}
690
+	if(tcpconn_id_hash){
691
+		shm_free(tcpconn_id_hash);
692
+		tcpconn_id_hash=0;
693
+	}
694
+}
695
+
696
+
697
+
606 698
 /* starts the tcp processes */
607 699
 int tcp_init_children()
608 700
 {
... ...
@@ -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);