Browse code

- various tcp changes (tls helpers)

Andrei Pelinescu-Onciul authored on 30/06/2003 18:50:00
Showing 3 changed files
... ...
@@ -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 */