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 48
 #define TCP_CHILD_SELECT_TIMEOUT 2 /* the same as above but for children */
49 49
 
50 50
 
51
+/* tcp connection flags */
52
+#define F_CONN_NON_BLOCKING 1
53
+
54
+
51 55
 enum tcp_req_errors {	TCP_REQ_INIT, TCP_REQ_OK, TCP_READ_ERROR,
52 56
 						TCP_REQ_OVERRUN, TCP_REQ_BAD_LEN };
53 57
 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 57
 		H_CONT_LEN_BODY, H_CONT_LEN_BODY_PARSE 
58 58
 	};
59 59
 
60
+enum tcp_conn_states { S_CONN_ERROR=-2, S_CONN_BAD=-1, S_CONN_OK=0, 
61
+						S_CONN_INIT, S_CONN_ACCEPT, S_CONN_CONNECT };
62
+
63
+
60 64
 /* fd communication commands */
61 65
 enum conn_cmds { CONN_DESTROY=-3, CONN_ERROR=-2, CONN_EOF=-1, CONN_RELEASE, 
62 66
 					CONN_GET_FD, CONN_NEW };
... ...
@@ -90,7 +99,10 @@ struct tcp_connection{
90 90
 	struct receive_info rcv; /* src & dst ip, ports, proto a.s.o*/
91 91
 	struct tcp_req req; /* request data */
92 92
 	volatile int refcnt;
93
-	int bad; /* if set this is a "bad" connection */
93
+	int type; /* PROTO_TCP or a protocol over it, e.g. TLS */
94
+	int flags; /* connection related flags */
95
+	int state; /* connection state, not used by raw tcp */
96
+	void* extra_data; /* extra data associated to the connection, 0 for tcp*/
94 97
 	int timeout; /* connection timeout, after this it will be removed*/
95 98
 	unsigned addr_hash; /* hash indexes in the 2 tables */
96 99
 	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 114
 
115 115
 
116 116
 struct tcp_connection* tcpconn_new(int sock, union sockaddr_union* su,
117
-									struct socket_info* ba)
117
+									struct socket_info* ba, int type, 
118
+									int state)
118 119
 {
119 120
 	struct tcp_connection *c;
121
+#ifdef USE_TLS
122
+	int flags;
123
+#endif
120 124
 	
121 125
 	c=(struct tcp_connection*)shm_malloc(sizeof(struct tcp_connection));
122 126
 	if (c==0){
123
-		LOG(L_ERR, "ERROR: tcpconn_add: mem. allocation failure\n");
127
+		LOG(L_ERR, "ERROR: tcpconn_new: mem. allocation failure\n");
124 128
 		goto error;
125 129
 	}
126 130
 	c->s=sock;
127 131
 	c->fd=-1; /* not initialized */
128 132
 	if (lock_init(&c->write_lock)==0){
129
-		LOG(L_ERR, "ERROR: tcpconn_add: init lock failed\n");
133
+		LOG(L_ERR, "ERROR: tcpconn_new: init lock failed\n");
130 134
 		goto error;
131 135
 	}
132 136
 	
133 137
 	c->rcv.src_su=*su;
134 138
 	
135 139
 	c->refcnt=0;
136
-	c->bad=0;
137 140
 	su2ip_addr(&c->rcv.src_ip, su);
138 141
 	c->rcv.src_port=su_getport(su);
139 142
 	c->rcv.proto=PROTO_TCP;
... ...
@@ -143,13 +148,42 @@ struct tcp_connection* tcpconn_new(int sock, union sockaddr_union* su,
143 143
 		c->rcv.dst_port=ba->port_no;
144 144
 	}
145 145
 	init_tcp_req(&c->req);
146
-	c->timeout=get_ticks()+TCP_CON_TIMEOUT;
147 146
 	c->id=connection_id++;
148 147
 	c->rcv.proto_reserved1=0; /* this will be filled before receive_message*/
149 148
 	c->rcv.proto_reserved2=0;
149
+	c->state=state;
150
+	c->extra_data=0;
151
+#ifdef USE_TLS
152
+	if (type==PROTO_TLS){
153
+		c->type=PROTO_TLS;
154
+		c->rcv.proto=PROTO_TLS;
155
+		c->flags=F_CONN_NON_BLOCKING;
156
+		flags=fcntl(sock, F_GETFL);
157
+		if (flags==-1){
158
+			LOG(L_ERR, "ERROR: tcpconn_new: fcntl failed :%s\n",
159
+					strerror(errno));
160
+			goto error;
161
+		}
162
+		if (fcntl(sock, F_SETFL, flags|O_NONBLOCK)==-1){
163
+			LOG(L_ERR, "ERROR: tcpconn_new: fcntl: set non blocking failed :"
164
+					" %s\n", strerror(errno));
165
+			goto error;
166
+		}
167
+		c->timeout=get_ticks()+TLS_CON_TIMEOUT;
168
+	}else
169
+#endif /* USE_TLS*/
170
+	{
171
+		c->type=PROTO_TCP;
172
+		c->rcv.proto=PROTO_TCP;
173
+		c->flags=0;
174
+		c->timeout=get_ticks()+TCP_CON_TIMEOUT;
175
+	}
176
+			
177
+		
150 178
 	return c;
151 179
 	
152 180
 error:
181
+	if (c) shm_free(c);
153 182
 	return 0;
154 183
 }
155 184
 
... ...
@@ -171,7 +205,7 @@ struct socket_info* find_tcp_si(union sockaddr_union* s)
171 171
 }
172 172
 
173 173
 
174
-struct tcp_connection* tcpconn_connect(union sockaddr_union* server)
174
+struct tcp_connection* tcpconn_connect(union sockaddr_union* server, int type)
175 175
 {
176 176
 	int s;
177 177
 	struct socket_info* si;
... ...
@@ -224,7 +258,8 @@ struct tcp_connection* tcpconn_connect(union sockaddr_union* server)
224 224
 		else si=sendipv6_tcp;
225 225
 #endif
226 226
 	}
227
-	return tcpconn_new(s, server, si); /*FIXME: set sock idx! */
227
+	return tcpconn_new(s, server, si, type, S_CONN_CONNECT);
228
+	/*FIXME: set sock idx! */
228 229
 error:
229 230
 	return 0;
230 231
 }
... ...
@@ -260,6 +295,9 @@ void _tcpconn_rm(struct tcp_connection* c)
260 260
 	tcpconn_listrm(tcpconn_addr_hash[c->addr_hash], c, next, prev);
261 261
 	tcpconn_listrm(tcpconn_id_hash[c->id_hash], c, id_next, id_prev);
262 262
 	lock_destroy(&c->write_lock);
263
+#ifdef USE_TLS
264
+	if ((c->type==PROTO_TLS)&&(c->extra_data)) tls_tcpconn_clean(c);
265
+#endif
263 266
 	shm_free(c);
264 267
 }
265 268
 
... ...
@@ -272,6 +310,9 @@ void tcpconn_rm(struct tcp_connection* c)
272 272
 	tcpconn_listrm(tcpconn_id_hash[c->id_hash], c, id_next, id_prev);
273 273
 	TCPCONN_UNLOCK;
274 274
 	lock_destroy(&c->write_lock);
275
+#ifdef USE_TLS
276
+	if ((c->type==PROTO_TLS)&&(c->extra_data)) tls_tcpconn_clean(c);
277
+#endif
275 278
 	shm_free(c);
276 279
 }
277 280
 
... ...
@@ -296,7 +337,7 @@ struct tcp_connection* _tcpconn_find(int id, struct ip_addr* ip, int port)
296 296
 			print_ip(&c->rcv.src_ip);
297 297
 			DBG(" port=%d\n", c->rcv.src_port);
298 298
 #endif
299
-			if ((id==c->id)&&(!c->bad)) return c;
299
+			if ((id==c->id)&&(c->state!=S_CONN_BAD)) return c;
300 300
 		}
301 301
 	}else if (ip){
302 302
 		hash=tcp_addr_hash(ip, port);
... ...
@@ -306,7 +347,7 @@ struct tcp_connection* _tcpconn_find(int id, struct ip_addr* ip, int port)
306 306
 			print_ip(&c->rcv.src_ip);
307 307
 			DBG(" port=%d\n", c->rcv.src_port);
308 308
 #endif
309
-			if ( (!c->bad) && (port==c->rcv.src_port) &&
309
+			if ( (c->state!=S_CONN_BAD) && (port==c->rcv.src_port) &&
310 310
 					(ip_addr_cmp(ip, &c->rcv.src_ip)) )
311 311
 				return c;
312 312
 		}
... ...
@@ -379,7 +420,7 @@ no_id:
379 379
 		if (c==0){
380 380
 			DBG("tcp_send: no open tcp connection found, opening new one\n");
381 381
 			/* create tcp connection */
382
-			if ((c=tcpconn_connect(to))==0){
382
+			if ((c=tcpconn_connect(to, PROTO_TCP))==0){
383 383
 				LOG(L_ERR, "ERROR: tcp_send: connect failed\n");
384 384
 				return -1;
385 385
 			}
... ...
@@ -446,7 +487,7 @@ send_it:
446 446
 		LOG(L_ERR, "ERROR: tcpsend: failed to send, n=%d: %s (%d)\n",
447 447
 				n, strerror(errno), errno);
448 448
 		/* error on the connection , mark it as bad and set 0 timeout */
449
-		c->bad=1;
449
+		c->state=S_CONN_BAD;
450 450
 		c->timeout=0;
451 451
 		/* tell "main" it should drop this (optional it will t/o anyway?)*/
452 452
 		response[0]=(long)c;
... ...
@@ -627,6 +668,48 @@ static int send2child(struct tcp_connection* tcpconn)
627 627
 }
628 628
 
629 629
 
630
+/* handle a new connection, called internally by tcp_main_loop */
631
+static inline void handle_new_connect(struct socket_info* si,
632
+										fd_set* sel_set, int* n)
633
+{
634
+	union sockaddr_union su;
635
+	struct tcp_connection* tcpconn;
636
+	socklen_t su_len;
637
+	int new_sock;
638
+	
639
+	if ((FD_ISSET(si->socket, sel_set))){
640
+		/* got a connection on r */
641
+		su_len=sizeof(su);
642
+		new_sock=accept(si->socket, &(su.s), &su_len);
643
+		*n--;
644
+		if (new_sock<0){
645
+			LOG(L_ERR,  "WARNING: tcp_main_loop: error while accepting"
646
+					" connection(%d): %s\n", errno, strerror(errno));
647
+			return;
648
+		}
649
+		
650
+		/* add socket to list */
651
+		tcpconn=tcpconn_new(new_sock, &su, si, si->proto, S_CONN_ACCEPT);
652
+		if (tcpconn){
653
+			tcpconn_add(tcpconn);
654
+			DBG("tcp_main_loop: new connection: %p %d\n",
655
+				tcpconn, tcpconn->s);
656
+			/* pass it to a child */
657
+			if(send2child(tcpconn)<0){
658
+				LOG(L_ERR,"ERROR: tcp_main_loop: no children "
659
+						"available\n");
660
+				TCPCONN_LOCK;
661
+				if (tcpconn->refcnt==0){
662
+					close(tcpconn->s);
663
+					_tcpconn_rm(tcpconn);
664
+				}else tcpconn->timeout=0; /* force expire */
665
+				TCPCONN_UNLOCK;
666
+			}
667
+		}
668
+	}
669
+}
670
+
671
+
630 672
 void tcp_main_loop()
631 673
 {
632 674
 	int r;
... ...
@@ -634,14 +717,11 @@ void tcp_main_loop()
634 634
 	fd_set master_set;
635 635
 	fd_set sel_set;
636 636
 	int maxfd;
637
-	int new_sock;
638
-	union sockaddr_union su;
639 637
 	struct tcp_connection* tcpconn;
640 638
 	unsigned h;
641 639
 	long response[2];
642 640
 	int cmd;
643 641
 	int bytes;
644
-	socklen_t su_len;
645 642
 	struct timeval timeout;
646 643
 
647 644
 	/*init */
... ...
@@ -653,6 +733,13 @@ void tcp_main_loop()
653 653
 			FD_SET(tcp_info[r].socket, &master_set);
654 654
 			if (tcp_info[r].socket>maxfd) maxfd=tcp_info[r].socket;
655 655
 		}
656
+#ifdef USE_TLS
657
+		if ((!tls_disable)&&(tls_info[r].proto==PROTO_TLS) &&
658
+				(tls_info[r].socket!=-1)){
659
+			FD_SET(tls_info[r].socket, &master_set);
660
+			if (tls_info[r].socket>maxfd) maxfd=tls_info[r].socket;
661
+		}
662
+#endif
656 663
 	}
657 664
 	/* set all the unix sockets used for child comm */
658 665
 	for (r=1; r<process_no; r++){
... ...
@@ -679,36 +766,11 @@ void tcp_main_loop()
679 679
 		}
680 680
 		
681 681
 		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
-			}
682
+			handle_new_connect(&tcp_info[r], &sel_set, &n);
683
+#ifdef USE_TLS
684
+			if (!tls_disable)
685
+				handle_new_connect(&tls_info[r], &sel_set, &n);
686
+#endif
712 687
 		}
713 688
 		
714 689
 		/* check all the read fds (from the tcpconn_addr_hash ) */
... ...
@@ -771,7 +833,8 @@ read_again:
771 771
 						}
772 772
 						tcpconn=(struct tcp_connection*)response[0];
773 773
 						if (tcpconn){
774
-								if (tcpconn->bad) goto tcpconn_destroy;
774
+								if (tcpconn->state==S_CONN_BAD) 
775
+									goto tcpconn_destroy;
775 776
 								FD_SET(tcpconn->s, &master_set);
776 777
 								if (maxfd<tcpconn->s) maxfd=tcpconn->s;
777 778
 								/* update the timeout*/
... ...
@@ -803,7 +866,7 @@ read_again:
803 803
 							}else{
804 804
 								/* force timeout */
805 805
 								tcpconn->timeout=0;
806
-								tcpconn->bad=1;
806
+								tcpconn->state=S_CONN_BAD;
807 807
 								DBG("tcp_main_loop: delaying ...\n");
808 808
 								
809 809
 							}
... ...
@@ -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 */