Browse code

- more tcp stuff and a lot of merging w/ latest cvs - content-length is appended automatically to messages that cross from udp to tcp - tcp2udp and udp2tcp now work under heavy stress (e.g.: throttle 200, 10 ser processes on dual cpu) - tcp performance still sucks, some things like disabling Nagle are still not in yet (for better debugging)

Andrei Pelinescu-Onciul authored on 07/02/2003 17:02:15
Showing 14 changed files
... ...
@@ -8,7 +8,7 @@
8 8
 VERSION = 0
9 9
 PATCHLEVEL = 8
10 10
 SUBLEVEL =   11
11
-EXTRAVERSION = pre5-tcp1-locking
11
+EXTRAVERSION = pre6-tcp2
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]")
... ...
@@ -38,6 +38,7 @@ New features
38 38
 - powerpc fast locking support
39 39
 - netbsd support
40 40
 - 64 bits arch. support (e.g. netbsd/sparc64).
41
+- tcp2udp and udp2tcp stateless forwarding (see forward_udp & forward_tcp)
41 42
 
42 43
 Changes to use of ser scripts
43 44
 =============================
... ...
@@ -10,7 +10,7 @@ x fix 0 parameter module f. call
10 10
 x better Via parsing (handle ' ' in uri, eg: foo.bar : 1234 ; received=) and
11 11
  ipv6 addresses ([fec0:aa::01]).
12 12
 - fix format string vulnerability in log()
13
-- fix alignement access problems (warning on Sun)
13
+- fix alignment access problems (warning on Sun)
14 14
 x (different way) add request header bitmap field for the modules
15 15
 - introduce variables & function in the script language (cfg. file)
16 16
 
... ...
@@ -69,4 +69,5 @@ x freopen stdin, stdout, stderr to /dev/null
69 69
 x generic locking lib
70 70
 - convert tm to use new locking lib
71 71
 - tcp disable nagle & other socket stuff (close()?)
72
+- force add rport (setflag(rport)???)
72 73
 
... ...
@@ -43,7 +43,7 @@
43 43
 #include <dmalloc.h>
44 44
 #endif
45 45
 
46
-/* WARNING: all lump add/insert operations excpect a pkg_malloc'ed char* 
46
+/* WARNING: all lump add/insert operations expect a pkg_malloc'ed char* 
47 47
  * pointer the will be DEALLOCATED when the sip_msg is destroyed! */
48 48
 
49 49
 enum lump_dir { LD_NEXT, LD_BEFORE, LD_AFTER };
... ...
@@ -312,7 +312,7 @@ int forward_request( struct sip_msg* msg, struct proxy_l * p, int proto)
312 312
 		goto error1;
313 313
 	}
314 314
 	 /* send it! */
315
-	DBG("Sending:\n%s.\n", buf);
315
+	DBG("Sending:\n%.*s.\n", (int)len, buf);
316 316
 	DBG("orig. len=%d, new_len=%d, proto=%d\n", msg->len, len, proto );
317 317
 	
318 318
 	
... ...
@@ -510,8 +510,9 @@ int forward_reply(struct sip_msg* msg)
510 510
 		STATS_TX_RESPONSE(  (msg->first_line.u.reply.statuscode/100) );
511 511
 #endif
512 512
 
513
-	DBG(" reply forwarded to %s:%d\n", msg->via2->host.s,
514
-		(unsigned short) msg->via2->port);
513
+	DBG(" reply forwarded to %.*s:%d\n", 
514
+			msg->via2->host.len, msg->via2->host.s,
515
+			(unsigned short) msg->via2->port);
515 516
 
516 517
 	pkg_free(new_buf);
517 518
 	free(to);
... ...
@@ -154,25 +154,11 @@ void hashtest_cycle( int hits[TABLE_ENTRIES+5], char *ip )
154 154
 				}
155 155
 }
156 156
 
157
-int init_hash()
158
-{
159
-	if (TABLE_ENTRIES != (1<<10)) {
160
-		LOG(L_WARN, "WARNING: hash function optimized for %d entries\n",
161
-			1<<10);
162
-		LOG(L_WARN, "WARNING: use of %d entries may lead "
163
-			"to unflat distribution\n", TABLE_ENTRIES );
164
-	} else {
165
-		DBG("DEBUG: hash function initialized with optimum table size\n");
166
-	}
167
-	return 1;
168
-}
169
-
170 157
 void hashtest()
171 158
 {
172 159
 	int hits[TABLE_ENTRIES+5];
173 160
 	int i;
174 161
 
175
-	init_hash();	
176 162
 	memset( hits, 0, sizeof hits );
177 163
 	hashtest_cycle( hits, "192.168.99.100" );
178 164
 	hashtest_cycle( hits, "172.168.99.100" );
... ...
@@ -39,7 +39,6 @@
39 39
 int new_hash( str  call_id, str cseq_nr );
40 40
 int new_hash2( str  call_id, str cseq_nr );
41 41
 
42
-int init_hash();
43 42
 
44 43
 #define hash( cid, cseq) new_hash2( cid, cseq )
45 44
 
... ...
@@ -880,8 +880,10 @@ static void sig_usr(int signo)
880 880
 	}else{
881 881
 		/* process the important signals */
882 882
 		switch(signo){
883
-			case SIGINT:
884 883
 			case SIGPIPE:
884
+					LOG(L_INFO, "INFO: signal %d received\n", signo);
885
+				break;
886
+			case SIGINT:
885 887
 			case SIGTERM:
886 888
 					LOG(L_INFO, "INFO: signal %d received\n", signo);
887 889
 					/* print memory stats for non-main too */
... ...
@@ -1280,11 +1282,6 @@ try_again:
1280 1282
 	DBG("test random number %u\n", rand());
1281 1283
 	
1282 1284
 	
1283
-	/* init hash fucntion */
1284
-	if (init_hash()<0) {
1285
-		LOG(L_ERR, "ERROR: init_hash failed\n");
1286
-		goto error;
1287
-	}
1288 1285
 
1289 1286
 	/*init mallocs (before parsing cfg !)*/
1290 1287
 	if (init_mallocs()==-1)
... ...
@@ -342,6 +342,44 @@ char* id_builder(struct sip_msg* msg, unsigned int *id_len)
342 342
 
343 343
 
344 344
 
345
+char* clen_builder(struct sip_msg* msg, unsigned int *clen_len)
346
+{
347
+	char* buf;
348
+	int len;
349
+	int value;
350
+	char* value_s;
351
+	int value_len;
352
+	char* body;
353
+	
354
+	
355
+	body=get_body(msg);
356
+	if (body==0){
357
+		ser_error=E_BAD_REQ;
358
+		LOG(L_ERR, "ERROR: clen_builder: no message body found"
359
+					" (missing crlf?)");
360
+		return 0;
361
+	}
362
+	value=msg->len-(int)(body-msg->buf);
363
+	value_s=int2str(value, &value_len);
364
+	DBG("clen_builder: content-length: %d (%s)\n", value, value_s);
365
+		
366
+	len=CONTENT_LENGTH_LEN+value_len+CRLF_LEN;
367
+	buf=pkg_malloc(sizeof(char)*(len+1));
368
+	if (buf==0){
369
+		ser_error=E_OUT_OF_MEM;
370
+		LOG(L_ERR, "ERROR: clen_builder: out of memory\n");
371
+		return 0;
372
+	}
373
+	memcpy(buf, CONTENT_LENGTH, CONTENT_LENGTH_LEN);
374
+	memcpy(buf+CONTENT_LENGTH_LEN, value_s, value_len);
375
+	memcpy(buf+CONTENT_LENGTH_LEN+value_len, CRLF, CRLF_LEN);
376
+	buf[len+1]=0; /* null terminate it */
377
+	*clen_len=len;
378
+	return buf;
379
+}
380
+
381
+
382
+
345 383
 /* computes the "unpacked" len of a lump list,
346 384
    code moved from build_req_from_req */
347 385
 static inline int lumps_len(struct lump* l)
... ...
@@ -548,10 +586,14 @@ char * build_req_buf_from_sip_req( struct sip_msg* msg,
548 586
 #ifdef USE_TCP
549 587
 	char* id_buf;
550 588
 	int id_len;
589
+	char* clen_buf;
590
+	int clen_len;
551 591
 	
552 592
 	
553 593
 	id_buf=0;
554 594
 	id_len=0;
595
+	clen_buf=0;
596
+	clen_len=0;
555 597
 #endif
556 598
 	extra_params.len=0;
557 599
 	extra_params.s=0;
... ...
@@ -580,6 +622,24 @@ char * build_req_buf_from_sip_req( struct sip_msg* msg,
580 622
 		extra_params.s=id_buf;
581 623
 		extra_params.len=id_len;
582 624
 	}
625
+	/* if sending proto == tcp, check if Content-Length needs to be added*/
626
+	if (proto==PROTO_TCP){
627
+		/* first of all parse content-length */
628
+		if (parse_headers(msg, HDR_CONTENTLENGTH, 0)==-1){
629
+			LOG(L_ERR, "build_req_buf_from_sip_req:"
630
+							" error parsing content-length\n");
631
+			goto skip_clen;
632
+		}
633
+		if (msg->content_length==0){
634
+			/* we need to add it */
635
+			if ((clen_buf=clen_builder(msg, &clen_len))==0){
636
+				LOG(L_ERR, "build_req_buf_from_sip_req:" 
637
+								" clen_builder failed\n");
638
+				goto skip_clen;
639
+			}
640
+		}
641
+	}
642
+skip_clen:
583 643
 #endif
584 644
 	branch.s=msg->add_to_branch_s;
585 645
 	branch.len=msg->add_to_branch_len;
... ...
@@ -652,6 +712,19 @@ char * build_req_buf_from_sip_req( struct sip_msg* msg,
652 712
 		if (insert_new_lump_after(anchor, rport_buf, rport_len, HDR_VIA)==0)
653 713
 			goto error03; /* free rport_buf*/
654 714
 	}
715
+#ifdef USE_TCP
716
+	/* if clen needs to be added, add it */
717
+	if (clen_len){
718
+		/* msg->unparsed should point just before the final crlf,
719
+		 * parse_headers is called from clen_builder */
720
+		anchor=anchor_lump(&(msg->add_rm), msg->unparsed-buf, 0,
721
+							 HDR_CONTENTLENGTH);
722
+		if (anchor==0) goto error04; /* free clen_buf*/
723
+		if (insert_new_lump_after(anchor, clen_buf, clen_len,
724
+					HDR_CONTENTLENGTH)==0)
725
+			goto error04; /* free clen_buf*/
726
+	}
727
+#endif
655 728
 
656 729
 	/* compute new msg len and fix overlapping zones*/
657 730
 	new_len=len+lumps_len(msg->add_rm);
... ...
@@ -716,12 +789,17 @@ error02:
716 789
 	if (received_buf) pkg_free(received_buf);
717 790
 error03:
718 791
 	if (rport_buf) pkg_free(rport_buf);
792
+#ifdef USE_TCP
793
+error04:
794
+	if (clen_buf) pkg_free(clen_buf);
795
+#endif
719 796
 error00:
720 797
 	*returned_len=0;
721 798
 	return 0;
722 799
 }
723 800
 
724 801
 
802
+
725 803
 char * build_res_buf_from_sip_res( struct sip_msg* msg,
726 804
 				unsigned int *returned_len)
727 805
 {
... ...
@@ -733,7 +811,14 @@ char * build_res_buf_from_sip_res( struct sip_msg* msg,
733 811
 #endif
734 812
 	char* buf;
735 813
 	unsigned int len;
736
-
814
+#ifdef USE_TCP
815
+	struct lump* anchor;
816
+	char* clen_buf;
817
+	int clen_len;
818
+	
819
+	clen_buf=0;
820
+	clen_len=0;
821
+#endif
737 822
 #ifdef SCRATCH
738 823
 	orig=msg->orig;
739 824
 #endif
... ...
@@ -763,12 +848,53 @@ char * build_res_buf_from_sip_res( struct sip_msg* msg,
763 848
 		via_offset=msg->h_via1->name.s-buf;
764 849
 	}
765 850
 #endif
851
+
852
+#ifdef USE_TCP
853
+
854
+	/* if sending proto == tcp, check if Content-Length needs to be added*/
855
+	if (msg->via2 && (msg->via2->proto==PROTO_TCP)){
856
+		DBG("build_res_from_sip_res: checking content-length for \n%.*s\n",
857
+				(int)msg->len, msg->buf);
858
+		/* first of all parse content-length */
859
+		if (parse_headers(msg, HDR_CONTENTLENGTH, 0)==-1){
860
+			LOG(L_ERR, "build_res_buf_from_sip_res:"
861
+							" error parsing content-length\n");
862
+			goto skip_clen;
863
+		}
864
+		if (msg->content_length==0){
865
+			DBG("build_res_from_sip_res: no content_length hdr found\n");
866
+			/* we need to add it */
867
+			if ((clen_buf=clen_builder(msg, &clen_len))==0){
868
+				LOG(L_ERR, "build_res_buf_from_sip_res:" 
869
+								" clen_builder failed\n");
870
+				goto skip_clen;
871
+			}
872
+		}
873
+	}
874
+skip_clen:
875
+#endif
876
+	
766 877
 	/* remove the first via*/
767 878
 	if (del_lump( &(msg->repl_add_rm), via_offset, via_len, HDR_VIA)==0){
768 879
 		LOG(L_ERR, "build_res_buf_from_sip_res: error trying to remove first"
769 880
 					"via\n");
770 881
 		goto error;
771 882
 	}
883
+#ifdef USE_TCP
884
+	/* if clen needs to be added, add it */
885
+	if (clen_len){
886
+		/* msg->unparsed should point just before the final crlf,
887
+		 * parse_headers is called from clen_builder */
888
+		anchor=anchor_lump(&(msg->repl_add_rm), msg->unparsed-buf, 0, 
889
+							HDR_CONTENTLENGTH);
890
+		DBG("build_res_from_sip_res: adding content-length: %.*s\n",
891
+				clen_len, clen_buf);
892
+		if (anchor==0) goto error_clen; /* free clen_buf*/
893
+		if (insert_new_lump_after(anchor, clen_buf, clen_len,
894
+					HDR_CONTENTLENGTH)==0)
895
+			goto error_clen; /* free clen_buf*/
896
+	}
897
+#endif
772 898
 	new_len=len+lumps_len(msg->repl_add_rm);
773 899
 
774 900
 	DBG(" old size: %d, new size: %d\n", len, new_len);
... ...
@@ -796,12 +922,15 @@ char * build_res_buf_from_sip_res( struct sip_msg* msg,
796 922
 #endif
797 923
 		len-s_offset);
798 924
 	 /* send it! */
799
-	DBG(" copied size: orig:%d, new: %d, rest: %d\n",
800
-			s_offset, offset,
801
-			len-s_offset );
925
+	DBG("build_res_from_sip_res: copied size: orig:%d, new: %d, rest: %d"
926
+			" msg=\n%s\n", s_offset, offset, len-s_offset, new_buf);
802 927
 
803 928
 	*returned_len=new_len;
804 929
 	return new_buf;
930
+#ifdef USE_TCP
931
+error_clen:
932
+	if (clen_buf) pkg_free(clen_buf);
933
+#endif
805 934
 error:
806 935
 	*returned_len=0;
807 936
 	return 0;
... ...
@@ -28,6 +28,7 @@
28 28
  * ---------
29 29
  * 2003-01-29 transport-independent message zero-termination in
30 30
  *            receive_msg (jiri)
31
+ * 2003-02-07 undoed jiri's zero term. changes (they break tcp) (andrei)
31 32
  */
32 33
 
33 34
 
... ...
@@ -81,7 +82,6 @@ int receive_msg(char* buf, unsigned int len, struct receive_info* rcv_info)
81 82
 	/* zero termination (termination of orig message bellow not that
82 83
 	   useful as most of the work is done with scrath-pad; -jiri  */
83 84
 	/* buf[len]=0; */ /* WARNING: zero term removed! */
84
-	buf[len]=0; /* transport-independent zero-termination */
85 85
 	msg->rcv=*rcv_info;
86 86
 	msg->id=msg_no;
87 87
 #ifdef SCRATCH
... ...
@@ -36,10 +36,12 @@
36 36
 #define _tcp_conn_h
37 37
 
38 38
 #include "ip_addr.h"
39
+#include "locking.h"
39 40
 
40 41
 
41 42
 #define TCP_BUF_SIZE 65535
42 43
 #define TCP_CON_TIMEOUT 60 /* in  seconds */
44
+#define TCP_CON_SEND_TIMEOUT 30 /* timeout after a send */
43 45
 #define TCP_CHILD_TIMEOUT 5 /* after 5 seconds, the child "returns" 
44 46
 							 the connection to the tcp master process */
45 47
 #define TCP_MAIN_SELECT_TIMEOUT 5 /* how often "tcp main" checks for timeout*/
... ...
@@ -82,6 +84,7 @@ struct tcp_req{
82 84
 struct tcp_connection{
83 85
 	int s; /*socket, used by "tcp main" */
84 86
 	int fd; /* used only by "children", don't modify it! private data! */
87
+	lock_t write_lock;
85 88
 	int id; /* id (unique!) used to retrieve a specific connection when
86 89
 	           reply-ing*/
87 90
 	struct receive_info rcv; /* src & dst ip, ports, proto a.s.o*/
... ...
@@ -92,9 +95,10 @@ struct tcp_connection{
92 95
 	union sockaddr_union su;
93 96
 #endif
94 97
 	struct tcp_req req; /* request data */
95
-	int refcnt;
98
+	volatile int refcnt;
99
+	int bad; /* if set this is a "bad" connection */
96 100
 	int timeout; /* connection timeout, after this it will be removed*/
97
-	unsigned addr_hash; /* hash indexes in thge 2 tables */
101
+	unsigned addr_hash; /* hash indexes in the 2 tables */
98 102
 	unsigned id_hash;
99 103
 	struct tcp_connection* next; /* next, prev in hash table, used by "main" */
100 104
 	struct tcp_connection* prev;
... ...
@@ -38,6 +38,7 @@
38 38
 #include <sys/time.h>
39 39
 #include <sys/types.h>
40 40
 #include <sys/socket.h>
41
+#include <sys/uio.h>  /* writev*/
41 42
 
42 43
 #include <unistd.h>
43 44
 
... ...
@@ -102,9 +103,15 @@ struct tcp_connection* tcpconn_new(int sock, union sockaddr_union* su,
102 103
 	}
103 104
 	c->s=sock;
104 105
 	c->fd=-1; /* not initialized */
106
+	if (lock_init(&c->write_lock)==0){
107
+		LOG(L_ERR, "ERROR: tcpconn_add: init lock failed\n");
108
+		goto error;
109
+	}
110
+	
105 111
 	c->rcv.src_su=*su;
106 112
 	
107 113
 	c->refcnt=0;
114
+	c->bad=0;
108 115
 	su2ip_addr(&c->rcv.src_ip, su);
109 116
 	c->rcv.src_port=su_getport(su);
110 117
 	c->rcv.proto=PROTO_TCP;
... ...
@@ -171,6 +178,16 @@ struct tcp_connection*  tcpconn_add(struct tcp_connection *c)
171 178
 }
172 179
 
173 180
 
181
+/* unsafe tcpconn_rm version (nolocks) */
182
+void _tcpconn_rm(struct tcp_connection* c)
183
+{
184
+	tcpconn_listrm(tcpconn_addr_hash[c->addr_hash], c, next, prev);
185
+	tcpconn_listrm(tcpconn_id_hash[c->id_hash], c, id_next, id_prev);
186
+	lock_destroy(&c->write_lock);
187
+	shm_free(c);
188
+}
189
+
190
+
174 191
 
175 192
 void tcpconn_rm(struct tcp_connection* c)
176 193
 {
... ...
@@ -178,6 +195,7 @@ void tcpconn_rm(struct tcp_connection* c)
178 195
 	tcpconn_listrm(tcpconn_addr_hash[c->addr_hash], c, next, prev);
179 196
 	tcpconn_listrm(tcpconn_id_hash[c->id_hash], c, id_next, id_prev);
180 197
 	TCPCONN_UNLOCK;
198
+	lock_destroy(&c->write_lock);
181 199
 	shm_free(c);
182 200
 }
183 201
 
... ...
@@ -198,7 +216,7 @@ struct tcp_connection* _tcpconn_find(int id, struct ip_addr* ip, int port)
198 216
 			DBG("c=%p, c->id=%d, ip=",c, c->id);
199 217
 			print_ip(&c->rcv.src_ip);
200 218
 			DBG(" port=%d\n", ntohs(c->rcv.src_port));
201
-			if (id==c->id) return c;
219
+			if ((id==c->id)&&(!c->bad)) return c;
202 220
 		}
203 221
 	}else if (ip){
204 222
 		hash=tcp_addr_hash(ip, port);
... ...
@@ -206,7 +224,8 @@ struct tcp_connection* _tcpconn_find(int id, struct ip_addr* ip, int port)
206 224
 			DBG("c=%p, c->id=%d, ip=",c, c->id);
207 225
 			print_ip(&c->rcv.src_ip);
208 226
 			DBG(" port=%d\n", ntohs(c->rcv.src_port));
209
-			if ( (port==c->rcv.src_port) && (ip_addr_cmp(ip, &c->rcv.src_ip)) )
227
+			if ( (!c->bad) && (port==c->rcv.src_port) &&
228
+					(ip_addr_cmp(ip, &c->rcv.src_ip)) )
210 229
 				return c;
211 230
 		}
212 231
 	}
... ...
@@ -215,13 +234,17 @@ struct tcp_connection* _tcpconn_find(int id, struct ip_addr* ip, int port)
215 234
 
216 235
 
217 236
 
218
-/* _tcpconn_find with locks */
219
-struct tcp_connection* tcpconn_get(int id, struct ip_addr* ip, int port)
237
+/* _tcpconn_find with locks and timeout */
238
+struct tcp_connection* tcpconn_get(int id, struct ip_addr* ip, int port,
239
+									int timeout)
220 240
 {
221 241
 	struct tcp_connection* c;
222 242
 	TCPCONN_LOCK;
223 243
 	c=_tcpconn_find(id, ip, port);
224
-	if (c) c->refcnt++;
244
+	if (c){ 
245
+			c->refcnt++;
246
+			c->timeout=get_ticks()+timeout;
247
+	}
225 248
 	TCPCONN_UNLOCK;
226 249
 	return c;
227 250
 }
... ...
@@ -249,9 +272,9 @@ int tcp_send(char* buf, unsigned len, union sockaddr_union* to, int id)
249 272
 	if (to){
250 273
 		su2ip_addr(&ip, to);
251 274
 		port=su_getport(to);
252
-		c=tcpconn_get(id, &ip, port); /* lock ;inc refcnt; unlock */
275
+		c=tcpconn_get(id, &ip, port, TCP_CON_SEND_TIMEOUT); 
253 276
 	}else if (id){
254
-		c=tcpconn_get(id, 0, 0);
277
+		c=tcpconn_get(id, 0, 0, TCP_CON_SEND_TIMEOUT);
255 278
 	}else{
256 279
 		LOG(L_CRIT, "BUG: tcp_send called with null id & to\n");
257 280
 		return -1;
... ...
@@ -260,7 +283,8 @@ int tcp_send(char* buf, unsigned len, union sockaddr_union* to, int id)
260 283
 	if (id){
261 284
 		if (c==0) {
262 285
 			if (to){
263
-				c=tcpconn_get(0, &ip, port); /* try again w/o id */
286
+				/* try again w/o id */
287
+				c=tcpconn_get(0, &ip, port, TCP_CON_SEND_TIMEOUT);
264 288
 				goto no_id;
265 289
 			}else{
266 290
 				LOG(L_ERR, "ERROR: tcp_send: id %d not found, dropping\n",
... ...
@@ -323,8 +347,27 @@ get_fd:
323 347
 	
324 348
 send_it:
325 349
 	DBG("tcp_send: sending...\n");
326
-	n=write(fd, buf, len);
350
+	lock_get(&c->write_lock);
351
+	n=send(fd, buf, len, MSG_NOSIGNAL);
352
+	lock_release(&c->write_lock);
327 353
 	DBG("tcp_send: after write: c= %p n=%d fd=%d\n",c, n, fd);
354
+	DBG("tcp_send: buf=\n%.*s\n", (int)len, buf);
355
+	if (n<0){
356
+		LOG(L_ERR, "ERROR: tcpsend: failed to send, n=%d: %s (%d)\n",
357
+				n, strerror(errno), errno);
358
+		/* error on the connection , mark it as bad and set 0 timeout */
359
+		c->bad=1;
360
+		c->timeout=0;
361
+		/* tell "main" it should drop this (optional it will t/o anyway?)*/
362
+		response[0]=(long)c;
363
+		response[1]=CONN_ERROR;
364
+		n=write(unix_tcp_sock, response, sizeof(response));
365
+		if (n<0){
366
+			LOG(L_ERR, "BUG: tcp_send: failed to get fd(write):%s (%d)\n",
367
+					strerror(errno), errno);
368
+			goto release_c;
369
+		}
370
+	}
328 371
 end:
329 372
 	close(fd);
330 373
 release_c:
... ...
@@ -343,6 +386,7 @@ void tcpconn_timeout(fd_set* set)
343 386
 	
344 387
 	
345 388
 	ticks=get_ticks();
389
+	TCPCONN_LOCK; /* fixme: we can lock only on delete IMO */
346 390
 	for(h=0; h<TCP_ADDR_HASH_SIZE; h++){
347 391
 		c=tcpconn_addr_hash[h];
348 392
 		while(c){
... ...
@@ -354,11 +398,12 @@ void tcpconn_timeout(fd_set* set)
354 398
 					FD_CLR(c->s, set);
355 399
 					close(c->s);
356 400
 				}
357
-				tcpconn_rm(c);
401
+				_tcpconn_rm(c);
358 402
 			}
359 403
 			c=next;
360 404
 		}
361 405
 	}
406
+	TCPCONN_UNLOCK;
362 407
 }
363 408
 
364 409
 
... ...
@@ -515,8 +560,12 @@ void tcp_main_loop()
515 560
 					if(send2child(tcpconn)<0){
516 561
 						LOG(L_ERR,"ERROR: tcp_main_loop: no children "
517 562
 								"available\n");
518
-						close(tcpconn->s);
519
-						tcpconn_rm(tcpconn);
563
+						TCPCONN_LOCK;
564
+						if (tcpconn->refcnt==0){
565
+							close(tcpconn->s);
566
+							_tcpconn_rm(tcpconn);
567
+						}else tcpconn->timeout=0; /* force expire */
568
+						TCPCONN_UNLOCK;
520 569
 					}
521 570
 				}
522 571
 			}
... ...
@@ -536,8 +585,12 @@ void tcp_main_loop()
536 585
 					if (send2child(tcpconn)<0){
537 586
 						LOG(L_ERR,"ERROR: tcp_main_loop: no "
538 587
 									"children available\n");
539
-						close(tcpconn->s);
540
-						tcpconn_rm(tcpconn);
588
+						TCPCONN_LOCK;
589
+						if (tcpconn->refcnt==0){
590
+							close(tcpconn->s);
591
+							_tcpconn_rm(tcpconn);
592
+						}else tcpconn->timeout=0; /* force expire*/
593
+						TCPCONN_UNLOCK;
541 594
 					}
542 595
 				}
543 596
 			}
... ...
@@ -578,13 +631,14 @@ read_again:
578 631
 						}
579 632
 						tcpconn=(struct tcp_connection*)response[0];
580 633
 						if (tcpconn){
581
-							tcpconn->refcnt--;
582
-							DBG("tcp_main_loop: %p refcnt= %d\n", 
583
-									tcpconn, tcpconn->refcnt);
634
+								if (tcpconn->bad) goto tcpconn_destroy;
584 635
 								FD_SET(tcpconn->s, &master_set);
585 636
 								if (maxfd<tcpconn->s) maxfd=tcpconn->s;
586 637
 								/* update the timeout*/
587 638
 								tcpconn->timeout=get_ticks()+TCP_CON_TIMEOUT;
639
+								tcpconn_put(tcpconn);
640
+								DBG("tcp_main_loop: %p refcnt= %d\n", 
641
+									tcpconn, tcpconn->refcnt);
588 642
 						}
589 643
 						break;
590 644
 					case CONN_ERROR:
... ...
@@ -597,14 +651,23 @@ read_again:
597 651
 						}
598 652
 						tcpconn=(struct tcp_connection*)response[0];
599 653
 						if (tcpconn){
654
+							if (tcpconn->s!=-1)
655
+								FD_CLR(tcpconn->s, &master_set);
656
+		tcpconn_destroy:
657
+							TCPCONN_LOCK; /*avoid races w/ tcp_send*/
600 658
 							tcpconn->refcnt--;
601
-							if (tcpconn->refcnt==0){
659
+							if (tcpconn->refcnt==0){ 
602 660
 								DBG("tcp_main_loop: destroying connection\n");
603 661
 								close(tcpconn->s);
604
-								tcpconn_rm(tcpconn);
662
+								_tcpconn_rm(tcpconn);
605 663
 							}else{
664
+								/* force timeout */
665
+								tcpconn->timeout=0;
666
+								tcpconn->bad=1;
606 667
 								DBG("tcp_main_loop: delaying ...\n");
668
+								
607 669
 							}
670
+							TCPCONN_UNLOCK;
608 671
 						}
609 672
 						break;
610 673
 					case CONN_GET_FD:
... ...
@@ -46,9 +46,9 @@
46 46
 #include "globals.h"
47 47
 #include "receive.h"
48 48
 #include "timer.h"
49
+#include "ut.h"
49 50
 
50 51
 
51
-#define q_memchr memchr
52 52
 
53 53
 /* reads next available bytes
54 54
  * return number of bytes read, 0 on EOF or -1 on error,
... ...
@@ -77,6 +77,7 @@ again:
77 77
 			return -1;
78 78
 		}
79 79
 	}
80
+	DBG("tcp_read: read %d bytes:\n%.*s\n", bytes_read, bytes_read, r->pos);
80 81
 	
81 82
 	r->pos+=bytes_read;
82 83
 	return bytes_read;
... ...
@@ -133,9 +134,13 @@ int tcp_read_headers(struct tcp_req *r, int fd)
133 134
 							  break
134 135
 
135 136
 
136
-	
137
-	bytes=tcp_read(r, fd);
138
-	if (bytes<=0) return bytes;
137
+	/* if we still have some unparsed part, parse it first, don't do the read*/
138
+	if (r->parsed<r->pos){
139
+		bytes=0;
140
+	}else{
141
+		bytes=tcp_read(r, fd);
142
+		if (bytes<=0) return bytes;
143
+	}
139 144
 	p=r->parsed;
140 145
 	
141 146
 	while(p<r->pos && r->error==TCP_REQ_OK){
... ...
@@ -154,7 +159,7 @@ int tcp_read_headers(struct tcp_req *r, int fd)
154 159
 			case H_SKIP:
155 160
 				/* find lf, we are in this state if we are not interested
156 161
 				 * in anything till end of line*/
157
-				p=q_memchr(p, '\n', r->pos-r->parsed);
162
+				p=q_memchr(p, '\n', r->pos-p);
158 163
 				if (p){
159 164
 					p++;
160 165
 					r->state=H_LF;
... ...
@@ -172,14 +177,18 @@ int tcp_read_headers(struct tcp_req *r, int fd)
172 177
 					case '\n':
173 178
 						/* found LF LF */
174 179
 						r->state=H_BODY;
180
+						DBG("tcp_read_headers: switching to H_BODY (lflf)\n");
175 181
 						if (r->has_content_len){
176 182
 							r->body=p+1;
177 183
 							r->bytes_to_go=r->content_len;
178 184
 							if (r->bytes_to_go==0){
179 185
 								r->complete=1;
186
+								p++;
180 187
 								goto skip;
181 188
 							}
182 189
 						}else{
190
+							DBG("tcp_read_headers: ERROR: no clen, p=%X\n",
191
+									*p);
183 192
 							r->error=TCP_REQ_BAD_LEN;
184 193
 						}
185 194
 						break;
... ...
@@ -193,14 +202,18 @@ int tcp_read_headers(struct tcp_req *r, int fd)
193 202
 				if (*p=='\n'){
194 203
 					/* found LF CR LF */
195 204
 					r->state=H_BODY;
205
+					DBG("tcp_read_headers: switching to H_BODY (lfcrlf)\n");
196 206
 					if (r->has_content_len){
197 207
 						r->body=p+1;
198 208
 						r->bytes_to_go=r->content_len;
199 209
 						if (r->bytes_to_go==0){
200 210
 							r->complete=1;
211
+							p++;
201 212
 							goto skip;
202 213
 						}
203 214
 					}else{
215
+						DBG("tcp_read_headers: ERROR: no clen, p=%X\n",
216
+									*p);
204 217
 						r->error=TCP_REQ_BAD_LEN;
205 218
 					}
206 219
 				}else r->state=H_SKIP;
... ...
@@ -342,17 +355,21 @@ int tcp_read_req(struct tcp_connection* con)
342 355
 		resp=CONN_RELEASE;
343 356
 		s=con->fd;
344 357
 		req=&con->req;
358
+		size=0;
359
+again:
345 360
 		if(req->complete==0 && req->error==TCP_REQ_OK){
346 361
 			bytes=tcp_read_headers(req, s);
347 362
 						/* if timeout state=0; goto end__req; */
348 363
 			DBG("read= %d bytes, parsed=%d, state=%d, error=%d\n",
349
-					bytes, req->parsed-req->buf, req->state, req->error );
364
+					bytes, req->parsed-req->start, req->state, req->error );
365
+			DBG("tcp_read_req: last char=%X, parsed msg=\n%.*s\n",
366
+					*(req->parsed-1), req->parsed-req->start, req->start);
350 367
 			if (bytes==-1){
351 368
 				LOG(L_ERR, "ERROR: tcp_read_req: error reading \n");
352 369
 				resp=CONN_ERROR;
353 370
 				goto end_req;
354 371
 			}
355
-			if (bytes==0){
372
+			if ((size==0) && (bytes==0)){
356 373
 				DBG( "tcp_read_req: EOF\n");
357 374
 				resp=CONN_EOF;
358 375
 				goto end_req;
... ...
@@ -360,15 +377,21 @@ int tcp_read_req(struct tcp_connection* con)
360 377
 		
361 378
 		}
362 379
 		if (req->error!=TCP_REQ_OK){
363
-			LOG(L_ERR,"ERROR: tcp_read_req: bad request, state=%d, error=%d\n",
364
-					req->state, req->error);
380
+			LOG(L_ERR,"ERROR: tcp_read_req: bad request, state=%d, error=%d "
381
+					  "buf:\n%.*s\nparsed:\n%.*s\n", req->state, req->error,
382
+					  req->pos-req->buf, req->buf,
383
+					  req->parsed-req->start, req->start);
384
+			DBG("- received from: port %d, ip -", ntohs(con->rcv.src_port));
385
+			print_ip(&con->rcv.src_ip); DBG("-\n");
365 386
 			resp=CONN_ERROR;
366 387
 			goto end_req;
367 388
 		}
368 389
 		if (req->complete){
369 390
 			DBG("tcp_read_req: end of header part\n");
391
+			DBG("- received from: port %d, ip - ", ntohs(con->rcv.src_port));
392
+			print_ip(&con->rcv.src_ip); DBG("-\n");
370 393
 			DBG("tcp_read_req: headers:\n%.*s.\n",
371
-					req->body-req->buf, req->buf);
394
+					req->body-req->start, req->start);
372 395
 			if (req->has_content_len){
373 396
 				DBG("tcp_read_req: content-length= %d\n", req->content_len);
374 397
 				DBG("tcp_read_req: body:\n%.*s\n", req->content_len,req->body);
... ...
@@ -383,7 +406,7 @@ int tcp_read_req(struct tcp_connection* con)
383 406
 			resp=CONN_RELEASE;
384 407
 			/* just for debugging use sendipv4 as receiving socket */
385 408
 			DBG("calling receive_msg(%p, %d, )\n",
386
-					req->buf, (int)(req->parsed-req->start));
409
+					req->start, (int)(req->parsed-req->start));
387 410
 			bind_address=sendipv4; /*&tcp_info[con->sock_idx];*/
388 411
 			con->rcv.proto_reserved1=con->id; /* copy the id */
389 412
 			if (receive_msg(req->start, req->parsed-req->start, &con->rcv)<0){
... ...
@@ -404,6 +427,8 @@ int tcp_read_req(struct tcp_connection* con)
404 427
 			req->state=H_SKIP_EMPTY;
405 428
 			req->complete=req->content_len=req->has_content_len=0;
406 429
 			req->bytes_to_go=0;
430
+			/* if we still have some unparsed bytes, try to  parse them too*/
431
+			if (size) goto again;
407 432
 			
408 433
 		}
409 434
 		
... ...
@@ -496,11 +521,13 @@ void tcp_receive_loop(int unix_sock)
496 521
 					LOG(L_ERR, "ERROR: tcp_receive_loop: read_fd:"
497 522
 									"no fd read\n");
498 523
 					resp=CONN_ERROR;
524
+					con->bad=1;
499 525
 					release_tcpconn(con, resp, unix_sock);
500 526
 				}
501 527
 				if (con==0){
502 528
 					LOG(L_ERR, "ERROR: tcp_receive_loop: null pointer\n");
503 529
 					resp=CONN_ERROR;
530
+					con->bad=1;
504 531
 					release_tcpconn(con, resp, unix_sock);
505 532
 				}
506 533
 				con->timeout=get_ticks()+TCP_CHILD_TIMEOUT;
... ...
@@ -524,6 +551,7 @@ void tcp_receive_loop(int unix_sock)
524 551
 					if (resp<0){
525 552
 						FD_CLR(con->fd, &master_set);
526 553
 						tcpconn_listrm(list, con, c_next, c_prev);
554
+						con->bad=1;
527 555
 						release_tcpconn(con, resp, unix_sock);
528 556
 					}else{
529 557
 						/* update timeout */
... ...
@@ -34,7 +34,8 @@
34 34
 
35 35
 /* "public" functions*/
36 36
 
37
-struct tcp_connection* tcpconn_get(int id, struct ip_addr* ip, int port);
37
+struct tcp_connection* tcpconn_get(int id, struct ip_addr* ip, int port, 
38
+									int timeout);
38 39
 void tcpconn_put(struct tcp_connection* c);
39 40
 int tcp_send(char* buf, unsigned len, union sockaddr_union* to, int id);
40 41