... | ... |
@@ -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" ); |
... | ... |
@@ -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 |
|