... | ... |
@@ -25,9 +25,10 @@ |
25 | 25 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
26 | 26 |
* |
27 | 27 |
* |
28 |
- * history: |
|
28 |
+ * History: |
|
29 | 29 |
* -------- |
30 |
- * 2003-01-29 tcp buffer size ++-ed to allow for 0-terminator |
|
30 |
+ * 2003-01-29 tcp buffer size ++-ed to allow for 0-terminator |
|
31 |
+ * 2003-06-30 added tcp_connection flags & state (andrei) |
|
31 | 32 |
*/ |
32 | 33 |
|
33 | 34 |
|
... | ... |
@@ -48,6 +49,10 @@ |
48 | 49 |
#define TCP_CHILD_SELECT_TIMEOUT 2 /* the same as above but for children */ |
49 | 50 |
|
50 | 51 |
|
52 |
+/* tcp connection flags */ |
|
53 |
+#define F_CONN_NON_BLOCKING 1 |
|
54 |
+ |
|
55 |
+ |
|
51 | 56 |
enum tcp_req_errors { TCP_REQ_INIT, TCP_REQ_OK, TCP_READ_ERROR, |
52 | 57 |
TCP_REQ_OVERRUN, TCP_REQ_BAD_LEN }; |
53 | 58 |
enum tcp_req_states { H_SKIP_EMPTY, H_SKIP, H_LF, H_LFCR, H_BODY, H_STARTWS, |
... | ... |
@@ -57,6 +62,10 @@ enum tcp_req_states { H_SKIP_EMPTY, H_SKIP, H_LF, H_LFCR, H_BODY, H_STARTWS, |
57 | 62 |
H_CONT_LEN_BODY, H_CONT_LEN_BODY_PARSE |
58 | 63 |
}; |
59 | 64 |
|
65 |
+enum tcp_conn_states { S_CONN_ERROR=-2, S_CONN_BAD=-1, S_CONN_OK=0, |
|
66 |
+ S_CONN_INIT, S_CONN_ACCEPT, S_CONN_CONNECT }; |
|
67 |
+ |
|
68 |
+ |
|
60 | 69 |
/* fd communication commands */ |
61 | 70 |
enum conn_cmds { CONN_DESTROY=-3, CONN_ERROR=-2, CONN_EOF=-1, CONN_RELEASE, |
62 | 71 |
CONN_GET_FD, CONN_NEW }; |
... | ... |
@@ -90,7 +99,10 @@ struct tcp_connection{ |
90 | 99 |
struct receive_info rcv; /* src & dst ip, ports, proto a.s.o*/ |
91 | 100 |
struct tcp_req req; /* request data */ |
92 | 101 |
volatile int refcnt; |
93 |
- int bad; /* if set this is a "bad" connection */ |
|
102 |
+ int type; /* PROTO_TCP or a protocol over it, e.g. TLS */ |
|
103 |
+ int flags; /* connection related flags */ |
|
104 |
+ int state; /* connection state, not used by raw tcp */ |
|
105 |
+ void* extra_data; /* extra data associated to the connection, 0 for tcp*/ |
|
94 | 106 |
int timeout; /* connection timeout, after this it will be removed*/ |
95 | 107 |
unsigned addr_hash; /* hash indexes in the 2 tables */ |
96 | 108 |
unsigned id_hash; |
... | ... |
@@ -39,6 +39,8 @@ |
39 | 39 |
* a temp. socket and store in in *->bind_address: added |
40 | 40 |
* find_tcp_si, modified tcpconn_connect (andrei) |
41 | 41 |
* 2003-04-14 set sockopts to TOS low delay (andrei) |
42 |
+ * 2003-06-30 moved tcp new connect checking & handling to |
|
43 |
+ * handle_new_connect (andrei) |
|
42 | 44 |
*/ |
43 | 45 |
|
44 | 46 |
|
... | ... |
@@ -114,26 +116,29 @@ int tcp_proto_no=-1; /* tcp protocol number as returned by getprotobyname */ |
114 | 116 |
|
115 | 117 |
|
116 | 118 |
struct tcp_connection* tcpconn_new(int sock, union sockaddr_union* su, |
117 |
- struct socket_info* ba) |
|
119 |
+ struct socket_info* ba, int type, |
|
120 |
+ int state) |
|
118 | 121 |
{ |
119 | 122 |
struct tcp_connection *c; |
123 |
+#ifdef USE_TLS |
|
124 |
+ int flags; |
|
125 |
+#endif |
|
120 | 126 |
|
121 | 127 |
c=(struct tcp_connection*)shm_malloc(sizeof(struct tcp_connection)); |
122 | 128 |
if (c==0){ |
123 |
- LOG(L_ERR, "ERROR: tcpconn_add: mem. allocation failure\n"); |
|
129 |
+ LOG(L_ERR, "ERROR: tcpconn_new: mem. allocation failure\n"); |
|
124 | 130 |
goto error; |
125 | 131 |
} |
126 | 132 |
c->s=sock; |
127 | 133 |
c->fd=-1; /* not initialized */ |
128 | 134 |
if (lock_init(&c->write_lock)==0){ |
129 |
- LOG(L_ERR, "ERROR: tcpconn_add: init lock failed\n"); |
|
135 |
+ LOG(L_ERR, "ERROR: tcpconn_new: init lock failed\n"); |
|
130 | 136 |
goto error; |
131 | 137 |
} |
132 | 138 |
|
133 | 139 |
c->rcv.src_su=*su; |
134 | 140 |
|
135 | 141 |
c->refcnt=0; |
136 |
- c->bad=0; |
|
137 | 142 |
su2ip_addr(&c->rcv.src_ip, su); |
138 | 143 |
c->rcv.src_port=su_getport(su); |
139 | 144 |
c->rcv.proto=PROTO_TCP; |
... | ... |
@@ -143,13 +148,42 @@ struct tcp_connection* tcpconn_new(int sock, union sockaddr_union* su, |
143 | 148 |
c->rcv.dst_port=ba->port_no; |
144 | 149 |
} |
145 | 150 |
init_tcp_req(&c->req); |
146 |
- c->timeout=get_ticks()+TCP_CON_TIMEOUT; |
|
147 | 151 |
c->id=connection_id++; |
148 | 152 |
c->rcv.proto_reserved1=0; /* this will be filled before receive_message*/ |
149 | 153 |
c->rcv.proto_reserved2=0; |
154 |
+ c->state=state; |
|
155 |
+ c->extra_data=0; |
|
156 |
+#ifdef USE_TLS |
|
157 |
+ if (type==PROTO_TLS){ |
|
158 |
+ c->type=PROTO_TLS; |
|
159 |
+ c->rcv.proto=PROTO_TLS; |
|
160 |
+ c->flags=F_CONN_NON_BLOCKING; |
|
161 |
+ flags=fcntl(sock, F_GETFL); |
|
162 |
+ if (flags==-1){ |
|
163 |
+ LOG(L_ERR, "ERROR: tcpconn_new: fcntl failed :%s\n", |
|
164 |
+ strerror(errno)); |
|
165 |
+ goto error; |
|
166 |
+ } |
|
167 |
+ if (fcntl(sock, F_SETFL, flags|O_NONBLOCK)==-1){ |
|
168 |
+ LOG(L_ERR, "ERROR: tcpconn_new: fcntl: set non blocking failed :" |
|
169 |
+ " %s\n", strerror(errno)); |
|
170 |
+ goto error; |
|
171 |
+ } |
|
172 |
+ c->timeout=get_ticks()+TLS_CON_TIMEOUT; |
|
173 |
+ }else |
|
174 |
+#endif /* USE_TLS*/ |
|
175 |
+ { |
|
176 |
+ c->type=PROTO_TCP; |
|
177 |
+ c->rcv.proto=PROTO_TCP; |
|
178 |
+ c->flags=0; |
|
179 |
+ c->timeout=get_ticks()+TCP_CON_TIMEOUT; |
|
180 |
+ } |
|
181 |
+ |
|
182 |
+ |
|
150 | 183 |
return c; |
151 | 184 |
|
152 | 185 |
error: |
186 |
+ if (c) shm_free(c); |
|
153 | 187 |
return 0; |
154 | 188 |
} |
155 | 189 |
|
... | ... |
@@ -171,7 +205,7 @@ struct socket_info* find_tcp_si(union sockaddr_union* s) |
171 | 205 |
} |
172 | 206 |
|
173 | 207 |
|
174 |
-struct tcp_connection* tcpconn_connect(union sockaddr_union* server) |
|
208 |
+struct tcp_connection* tcpconn_connect(union sockaddr_union* server, int type) |
|
175 | 209 |
{ |
176 | 210 |
int s; |
177 | 211 |
struct socket_info* si; |
... | ... |
@@ -224,7 +258,8 @@ struct tcp_connection* tcpconn_connect(union sockaddr_union* server) |
224 | 258 |
else si=sendipv6_tcp; |
225 | 259 |
#endif |
226 | 260 |
} |
227 |
- return tcpconn_new(s, server, si); /*FIXME: set sock idx! */ |
|
261 |
+ return tcpconn_new(s, server, si, type, S_CONN_CONNECT); |
|
262 |
+ /*FIXME: set sock idx! */ |
|
228 | 263 |
error: |
229 | 264 |
return 0; |
230 | 265 |
} |
... | ... |
@@ -260,6 +295,9 @@ void _tcpconn_rm(struct tcp_connection* c) |
260 | 295 |
tcpconn_listrm(tcpconn_addr_hash[c->addr_hash], c, next, prev); |
261 | 296 |
tcpconn_listrm(tcpconn_id_hash[c->id_hash], c, id_next, id_prev); |
262 | 297 |
lock_destroy(&c->write_lock); |
298 |
+#ifdef USE_TLS |
|
299 |
+ if ((c->type==PROTO_TLS)&&(c->extra_data)) tls_tcpconn_clean(c); |
|
300 |
+#endif |
|
263 | 301 |
shm_free(c); |
264 | 302 |
} |
265 | 303 |
|
... | ... |
@@ -272,6 +310,9 @@ void tcpconn_rm(struct tcp_connection* c) |
272 | 310 |
tcpconn_listrm(tcpconn_id_hash[c->id_hash], c, id_next, id_prev); |
273 | 311 |
TCPCONN_UNLOCK; |
274 | 312 |
lock_destroy(&c->write_lock); |
313 |
+#ifdef USE_TLS |
|
314 |
+ if ((c->type==PROTO_TLS)&&(c->extra_data)) tls_tcpconn_clean(c); |
|
315 |
+#endif |
|
275 | 316 |
shm_free(c); |
276 | 317 |
} |
277 | 318 |
|
... | ... |
@@ -296,7 +337,7 @@ struct tcp_connection* _tcpconn_find(int id, struct ip_addr* ip, int port) |
296 | 337 |
print_ip(&c->rcv.src_ip); |
297 | 338 |
DBG(" port=%d\n", c->rcv.src_port); |
298 | 339 |
#endif |
299 |
- if ((id==c->id)&&(!c->bad)) return c; |
|
340 |
+ if ((id==c->id)&&(c->state!=S_CONN_BAD)) return c; |
|
300 | 341 |
} |
301 | 342 |
}else if (ip){ |
302 | 343 |
hash=tcp_addr_hash(ip, port); |
... | ... |
@@ -306,7 +347,7 @@ struct tcp_connection* _tcpconn_find(int id, struct ip_addr* ip, int port) |
306 | 347 |
print_ip(&c->rcv.src_ip); |
307 | 348 |
DBG(" port=%d\n", c->rcv.src_port); |
308 | 349 |
#endif |
309 |
- if ( (!c->bad) && (port==c->rcv.src_port) && |
|
350 |
+ if ( (c->state!=S_CONN_BAD) && (port==c->rcv.src_port) && |
|
310 | 351 |
(ip_addr_cmp(ip, &c->rcv.src_ip)) ) |
311 | 352 |
return c; |
312 | 353 |
} |
... | ... |
@@ -379,7 +420,7 @@ no_id: |
379 | 420 |
if (c==0){ |
380 | 421 |
DBG("tcp_send: no open tcp connection found, opening new one\n"); |
381 | 422 |
/* create tcp connection */ |
382 |
- if ((c=tcpconn_connect(to))==0){ |
|
423 |
+ if ((c=tcpconn_connect(to, PROTO_TCP))==0){ |
|
383 | 424 |
LOG(L_ERR, "ERROR: tcp_send: connect failed\n"); |
384 | 425 |
return -1; |
385 | 426 |
} |
... | ... |
@@ -446,7 +487,7 @@ send_it: |
446 | 487 |
LOG(L_ERR, "ERROR: tcpsend: failed to send, n=%d: %s (%d)\n", |
447 | 488 |
n, strerror(errno), errno); |
448 | 489 |
/* error on the connection , mark it as bad and set 0 timeout */ |
449 |
- c->bad=1; |
|
490 |
+ c->state=S_CONN_BAD; |
|
450 | 491 |
c->timeout=0; |
451 | 492 |
/* tell "main" it should drop this (optional it will t/o anyway?)*/ |
452 | 493 |
response[0]=(long)c; |
... | ... |
@@ -627,6 +668,48 @@ static int send2child(struct tcp_connection* tcpconn) |
627 | 668 |
} |
628 | 669 |
|
629 | 670 |
|
671 |
+/* handle a new connection, called internally by tcp_main_loop */ |
|
672 |
+static inline void handle_new_connect(struct socket_info* si, |
|
673 |
+ fd_set* sel_set, int* n) |
|
674 |
+{ |
|
675 |
+ union sockaddr_union su; |
|
676 |
+ struct tcp_connection* tcpconn; |
|
677 |
+ socklen_t su_len; |
|
678 |
+ int new_sock; |
|
679 |
+ |
|
680 |
+ if ((FD_ISSET(si->socket, sel_set))){ |
|
681 |
+ /* got a connection on r */ |
|
682 |
+ su_len=sizeof(su); |
|
683 |
+ new_sock=accept(si->socket, &(su.s), &su_len); |
|
684 |
+ *n--; |
|
685 |
+ if (new_sock<0){ |
|
686 |
+ LOG(L_ERR, "WARNING: tcp_main_loop: error while accepting" |
|
687 |
+ " connection(%d): %s\n", errno, strerror(errno)); |
|
688 |
+ return; |
|
689 |
+ } |
|
690 |
+ |
|
691 |
+ /* add socket to list */ |
|
692 |
+ tcpconn=tcpconn_new(new_sock, &su, si, si->proto, S_CONN_ACCEPT); |
|
693 |
+ if (tcpconn){ |
|
694 |
+ tcpconn_add(tcpconn); |
|
695 |
+ DBG("tcp_main_loop: new connection: %p %d\n", |
|
696 |
+ tcpconn, tcpconn->s); |
|
697 |
+ /* pass it to a child */ |
|
698 |
+ if(send2child(tcpconn)<0){ |
|
699 |
+ LOG(L_ERR,"ERROR: tcp_main_loop: no children " |
|
700 |
+ "available\n"); |
|
701 |
+ TCPCONN_LOCK; |
|
702 |
+ if (tcpconn->refcnt==0){ |
|
703 |
+ close(tcpconn->s); |
|
704 |
+ _tcpconn_rm(tcpconn); |
|
705 |
+ }else tcpconn->timeout=0; /* force expire */ |
|
706 |
+ TCPCONN_UNLOCK; |
|
707 |
+ } |
|
708 |
+ } |
|
709 |
+ } |
|
710 |
+} |
|
711 |
+ |
|
712 |
+ |
|
630 | 713 |
void tcp_main_loop() |
631 | 714 |
{ |
632 | 715 |
int r; |
... | ... |
@@ -634,14 +717,11 @@ void tcp_main_loop() |
634 | 717 |
fd_set master_set; |
635 | 718 |
fd_set sel_set; |
636 | 719 |
int maxfd; |
637 |
- int new_sock; |
|
638 |
- union sockaddr_union su; |
|
639 | 720 |
struct tcp_connection* tcpconn; |
640 | 721 |
unsigned h; |
641 | 722 |
long response[2]; |
642 | 723 |
int cmd; |
643 | 724 |
int bytes; |
644 |
- socklen_t su_len; |
|
645 | 725 |
struct timeval timeout; |
646 | 726 |
|
647 | 727 |
/*init */ |
... | ... |
@@ -653,6 +733,13 @@ void tcp_main_loop() |
653 | 733 |
FD_SET(tcp_info[r].socket, &master_set); |
654 | 734 |
if (tcp_info[r].socket>maxfd) maxfd=tcp_info[r].socket; |
655 | 735 |
} |
736 |
+#ifdef USE_TLS |
|
737 |
+ if ((!tls_disable)&&(tls_info[r].proto==PROTO_TLS) && |
|
738 |
+ (tls_info[r].socket!=-1)){ |
|
739 |
+ FD_SET(tls_info[r].socket, &master_set); |
|
740 |
+ if (tls_info[r].socket>maxfd) maxfd=tls_info[r].socket; |
|
741 |
+ } |
|
742 |
+#endif |
|
656 | 743 |
} |
657 | 744 |
/* set all the unix sockets used for child comm */ |
658 | 745 |
for (r=1; r<process_no; r++){ |
... | ... |
@@ -679,36 +766,11 @@ void tcp_main_loop() |
679 | 766 |
} |
680 | 767 |
|
681 | 768 |
for (r=0; r<sock_no && n; r++){ |
682 |
- if ((FD_ISSET(tcp_info[r].socket, &sel_set))){ |
|
683 |
- /* got a connection on r */ |
|
684 |
- su_len=sizeof(su); |
|
685 |
- new_sock=accept(tcp_info[r].socket, &(su.s), &su_len); |
|
686 |
- n--; |
|
687 |
- if (new_sock<0){ |
|
688 |
- LOG(L_ERR, "WARNING: tcp_main_loop: error while accepting" |
|
689 |
- " connection(%d): %s\n", errno, strerror(errno)); |
|
690 |
- continue; |
|
691 |
- } |
|
692 |
- |
|
693 |
- /* add socket to list */ |
|
694 |
- tcpconn=tcpconn_new(new_sock, &su, &tcp_info[r]); |
|
695 |
- if (tcpconn){ |
|
696 |
- tcpconn_add(tcpconn); |
|
697 |
- DBG("tcp_main_loop: new connection: %p %d\n", |
|
698 |
- tcpconn, tcpconn->s); |
|
699 |
- /* pass it to a child */ |
|
700 |
- if(send2child(tcpconn)<0){ |
|
701 |
- LOG(L_ERR,"ERROR: tcp_main_loop: no children " |
|
702 |
- "available\n"); |
|
703 |
- TCPCONN_LOCK; |
|
704 |
- if (tcpconn->refcnt==0){ |
|
705 |
- close(tcpconn->s); |
|
706 |
- _tcpconn_rm(tcpconn); |
|
707 |
- }else tcpconn->timeout=0; /* force expire */ |
|
708 |
- TCPCONN_UNLOCK; |
|
709 |
- } |
|
710 |
- } |
|
711 |
- } |
|
769 |
+ handle_new_connect(&tcp_info[r], &sel_set, &n); |
|
770 |
+#ifdef USE_TLS |
|
771 |
+ if (!tls_disable) |
|
772 |
+ handle_new_connect(&tls_info[r], &sel_set, &n); |
|
773 |
+#endif |
|
712 | 774 |
} |
713 | 775 |
|
714 | 776 |
/* check all the read fds (from the tcpconn_addr_hash ) */ |
... | ... |
@@ -771,7 +833,8 @@ read_again: |
771 | 833 |
} |
772 | 834 |
tcpconn=(struct tcp_connection*)response[0]; |
773 | 835 |
if (tcpconn){ |
774 |
- if (tcpconn->bad) goto tcpconn_destroy; |
|
836 |
+ if (tcpconn->state==S_CONN_BAD) |
|
837 |
+ goto tcpconn_destroy; |
|
775 | 838 |
FD_SET(tcpconn->s, &master_set); |
776 | 839 |
if (maxfd<tcpconn->s) maxfd=tcpconn->s; |
777 | 840 |
/* update the timeout*/ |
... | ... |
@@ -803,7 +866,7 @@ read_again: |
803 | 866 |
}else{ |
804 | 867 |
/* force timeout */ |
805 | 868 |
tcpconn->timeout=0; |
806 |
- tcpconn->bad=1; |
|
869 |
+ tcpconn->state=S_CONN_BAD; |
|
807 | 870 |
DBG("tcp_main_loop: delaying ...\n"); |
808 | 871 |
|
809 | 872 |
} |
... | ... |
@@ -566,13 +566,13 @@ void tcp_receive_loop(int unix_sock) |
566 | 566 |
LOG(L_ERR, "ERROR: tcp_receive_loop: read_fd:" |
567 | 567 |
"no fd read\n"); |
568 | 568 |
resp=CONN_ERROR; |
569 |
- con->bad=1; |
|
569 |
+ con->state=S_CONN_BAD; |
|
570 | 570 |
release_tcpconn(con, resp, unix_sock); |
571 | 571 |
} |
572 | 572 |
if (con==0){ |
573 | 573 |
LOG(L_ERR, "ERROR: tcp_receive_loop: null pointer\n"); |
574 | 574 |
resp=CONN_ERROR; |
575 |
- con->bad=1; |
|
575 |
+ con->state=S_CONN_BAD; |
|
576 | 576 |
release_tcpconn(con, resp, unix_sock); |
577 | 577 |
} |
578 | 578 |
con->timeout=get_ticks()+TCP_CHILD_TIMEOUT; |
... | ... |
@@ -596,7 +596,7 @@ void tcp_receive_loop(int unix_sock) |
596 | 596 |
if (resp<0){ |
597 | 597 |
FD_CLR(con->fd, &master_set); |
598 | 598 |
tcpconn_listrm(list, con, c_next, c_prev); |
599 |
- con->bad=1; |
|
599 |
+ con->state=S_CONN_BAD; |
|
600 | 600 |
release_tcpconn(con, resp, unix_sock); |
601 | 601 |
}else{ |
602 | 602 |
/* update timeout */ |