Преглед на файлове

- various tcp changes (tls helpers)

Andrei Pelinescu-Onciul преди 22 години
родител
ревизия
f6e50f0838
променени са 3 файла, в които са добавени 127 реда и са изтрити 52 реда
  1. 15 3
      tcp_conn.h
  2. 109 46
      tcp_main.c
  3. 3 3
      tcp_read.c

+ 15 - 3
tcp_conn.h

@@ -25,9 +25,10 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
  *
- * history:
+ * History:
  * --------
- * 2003-01-29 tcp buffer size ++-ed to allow for 0-terminator
+ *  2003-01-29  tcp buffer size ++-ed to allow for 0-terminator
+ *  2003-06-30  added tcp_connection flags & state (andrei) 
  */
 
 
@@ -48,6 +49,10 @@
 #define TCP_CHILD_SELECT_TIMEOUT 2 /* the same as above but for children */
 
 
+/* tcp connection flags */
+#define F_CONN_NON_BLOCKING 1
+
+
 enum tcp_req_errors {	TCP_REQ_INIT, TCP_REQ_OK, TCP_READ_ERROR,
 						TCP_REQ_OVERRUN, TCP_REQ_BAD_LEN };
 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,
 		H_CONT_LEN_BODY, H_CONT_LEN_BODY_PARSE 
 	};
 
+enum tcp_conn_states { S_CONN_ERROR=-2, S_CONN_BAD=-1, S_CONN_OK=0, 
+						S_CONN_INIT, S_CONN_ACCEPT, S_CONN_CONNECT };
+
+
 /* fd communication commands */
 enum conn_cmds { CONN_DESTROY=-3, CONN_ERROR=-2, CONN_EOF=-1, CONN_RELEASE, 
 					CONN_GET_FD, CONN_NEW };
@@ -90,7 +99,10 @@ struct tcp_connection{
 	struct receive_info rcv; /* src & dst ip, ports, proto a.s.o*/
 	struct tcp_req req; /* request data */
 	volatile int refcnt;
-	int bad; /* if set this is a "bad" connection */
+	int type; /* PROTO_TCP or a protocol over it, e.g. TLS */
+	int flags; /* connection related flags */
+	int state; /* connection state, not used by raw tcp */
+	void* extra_data; /* extra data associated to the connection, 0 for tcp*/
 	int timeout; /* connection timeout, after this it will be removed*/
 	unsigned addr_hash; /* hash indexes in the 2 tables */
 	unsigned id_hash;

+ 109 - 46
tcp_main.c

@@ -39,6 +39,8 @@
  *               a temp. socket and store in in *->bind_address: added
  *               find_tcp_si, modified tcpconn_connect (andrei)
  *  2003-04-14  set sockopts to TOS low delay (andrei)
+ *  2003-06-30  moved tcp new connect checking & handling to
+ *               handle_new_connect (andrei)
  */
 
 
@@ -114,26 +116,29 @@ int tcp_proto_no=-1; /* tcp protocol number as returned by getprotobyname */
 
 
 struct tcp_connection* tcpconn_new(int sock, union sockaddr_union* su,
-									struct socket_info* ba)
+									struct socket_info* ba, int type, 
+									int state)
 {
 	struct tcp_connection *c;
+#ifdef USE_TLS
+	int flags;
+#endif
 	
 	c=(struct tcp_connection*)shm_malloc(sizeof(struct tcp_connection));
 	if (c==0){
-		LOG(L_ERR, "ERROR: tcpconn_add: mem. allocation failure\n");
+		LOG(L_ERR, "ERROR: tcpconn_new: mem. allocation failure\n");
 		goto error;
 	}
 	c->s=sock;
 	c->fd=-1; /* not initialized */
 	if (lock_init(&c->write_lock)==0){
-		LOG(L_ERR, "ERROR: tcpconn_add: init lock failed\n");
+		LOG(L_ERR, "ERROR: tcpconn_new: init lock failed\n");
 		goto error;
 	}
 	
 	c->rcv.src_su=*su;
 	
 	c->refcnt=0;
-	c->bad=0;
 	su2ip_addr(&c->rcv.src_ip, su);
 	c->rcv.src_port=su_getport(su);
 	c->rcv.proto=PROTO_TCP;
@@ -143,13 +148,42 @@ struct tcp_connection* tcpconn_new(int sock, union sockaddr_union* su,
 		c->rcv.dst_port=ba->port_no;
 	}
 	init_tcp_req(&c->req);
-	c->timeout=get_ticks()+TCP_CON_TIMEOUT;
 	c->id=connection_id++;
 	c->rcv.proto_reserved1=0; /* this will be filled before receive_message*/
 	c->rcv.proto_reserved2=0;
+	c->state=state;
+	c->extra_data=0;
+#ifdef USE_TLS
+	if (type==PROTO_TLS){
+		c->type=PROTO_TLS;
+		c->rcv.proto=PROTO_TLS;
+		c->flags=F_CONN_NON_BLOCKING;
+		flags=fcntl(sock, F_GETFL);
+		if (flags==-1){
+			LOG(L_ERR, "ERROR: tcpconn_new: fcntl failed :%s\n",
+					strerror(errno));
+			goto error;
+		}
+		if (fcntl(sock, F_SETFL, flags|O_NONBLOCK)==-1){
+			LOG(L_ERR, "ERROR: tcpconn_new: fcntl: set non blocking failed :"
+					" %s\n", strerror(errno));
+			goto error;
+		}
+		c->timeout=get_ticks()+TLS_CON_TIMEOUT;
+	}else
+#endif /* USE_TLS*/
+	{
+		c->type=PROTO_TCP;
+		c->rcv.proto=PROTO_TCP;
+		c->flags=0;
+		c->timeout=get_ticks()+TCP_CON_TIMEOUT;
+	}
+			
+		
 	return c;
 	
 error:
+	if (c) shm_free(c);
 	return 0;
 }
 
@@ -171,7 +205,7 @@ struct socket_info* find_tcp_si(union sockaddr_union* s)
 }
 
 
-struct tcp_connection* tcpconn_connect(union sockaddr_union* server)
+struct tcp_connection* tcpconn_connect(union sockaddr_union* server, int type)
 {
 	int s;
 	struct socket_info* si;
@@ -224,7 +258,8 @@ struct tcp_connection* tcpconn_connect(union sockaddr_union* server)
 		else si=sendipv6_tcp;
 #endif
 	}
-	return tcpconn_new(s, server, si); /*FIXME: set sock idx! */
+	return tcpconn_new(s, server, si, type, S_CONN_CONNECT);
+	/*FIXME: set sock idx! */
 error:
 	return 0;
 }
@@ -260,6 +295,9 @@ void _tcpconn_rm(struct tcp_connection* c)
 	tcpconn_listrm(tcpconn_addr_hash[c->addr_hash], c, next, prev);
 	tcpconn_listrm(tcpconn_id_hash[c->id_hash], c, id_next, id_prev);
 	lock_destroy(&c->write_lock);
+#ifdef USE_TLS
+	if ((c->type==PROTO_TLS)&&(c->extra_data)) tls_tcpconn_clean(c);
+#endif
 	shm_free(c);
 }
 
@@ -272,6 +310,9 @@ void tcpconn_rm(struct tcp_connection* c)
 	tcpconn_listrm(tcpconn_id_hash[c->id_hash], c, id_next, id_prev);
 	TCPCONN_UNLOCK;
 	lock_destroy(&c->write_lock);
+#ifdef USE_TLS
+	if ((c->type==PROTO_TLS)&&(c->extra_data)) tls_tcpconn_clean(c);
+#endif
 	shm_free(c);
 }
 
@@ -296,7 +337,7 @@ struct tcp_connection* _tcpconn_find(int id, struct ip_addr* ip, int port)
 			print_ip(&c->rcv.src_ip);
 			DBG(" port=%d\n", c->rcv.src_port);
 #endif
-			if ((id==c->id)&&(!c->bad)) return c;
+			if ((id==c->id)&&(c->state!=S_CONN_BAD)) return c;
 		}
 	}else if (ip){
 		hash=tcp_addr_hash(ip, port);
@@ -306,7 +347,7 @@ struct tcp_connection* _tcpconn_find(int id, struct ip_addr* ip, int port)
 			print_ip(&c->rcv.src_ip);
 			DBG(" port=%d\n", c->rcv.src_port);
 #endif
-			if ( (!c->bad) && (port==c->rcv.src_port) &&
+			if ( (c->state!=S_CONN_BAD) && (port==c->rcv.src_port) &&
 					(ip_addr_cmp(ip, &c->rcv.src_ip)) )
 				return c;
 		}
@@ -379,7 +420,7 @@ no_id:
 		if (c==0){
 			DBG("tcp_send: no open tcp connection found, opening new one\n");
 			/* create tcp connection */
-			if ((c=tcpconn_connect(to))==0){
+			if ((c=tcpconn_connect(to, PROTO_TCP))==0){
 				LOG(L_ERR, "ERROR: tcp_send: connect failed\n");
 				return -1;
 			}
@@ -446,7 +487,7 @@ send_it:
 		LOG(L_ERR, "ERROR: tcpsend: failed to send, n=%d: %s (%d)\n",
 				n, strerror(errno), errno);
 		/* error on the connection , mark it as bad and set 0 timeout */
-		c->bad=1;
+		c->state=S_CONN_BAD;
 		c->timeout=0;
 		/* tell "main" it should drop this (optional it will t/o anyway?)*/
 		response[0]=(long)c;
@@ -627,6 +668,48 @@ static int send2child(struct tcp_connection* tcpconn)
 }
 
 
+/* handle a new connection, called internally by tcp_main_loop */
+static inline void handle_new_connect(struct socket_info* si,
+										fd_set* sel_set, int* n)
+{
+	union sockaddr_union su;
+	struct tcp_connection* tcpconn;
+	socklen_t su_len;
+	int new_sock;
+	
+	if ((FD_ISSET(si->socket, sel_set))){
+		/* got a connection on r */
+		su_len=sizeof(su);
+		new_sock=accept(si->socket, &(su.s), &su_len);
+		*n--;
+		if (new_sock<0){
+			LOG(L_ERR,  "WARNING: tcp_main_loop: error while accepting"
+					" connection(%d): %s\n", errno, strerror(errno));
+			return;
+		}
+		
+		/* add socket to list */
+		tcpconn=tcpconn_new(new_sock, &su, si, si->proto, S_CONN_ACCEPT);
+		if (tcpconn){
+			tcpconn_add(tcpconn);
+			DBG("tcp_main_loop: new connection: %p %d\n",
+				tcpconn, tcpconn->s);
+			/* pass it to a child */
+			if(send2child(tcpconn)<0){
+				LOG(L_ERR,"ERROR: tcp_main_loop: no children "
+						"available\n");
+				TCPCONN_LOCK;
+				if (tcpconn->refcnt==0){
+					close(tcpconn->s);
+					_tcpconn_rm(tcpconn);
+				}else tcpconn->timeout=0; /* force expire */
+				TCPCONN_UNLOCK;
+			}
+		}
+	}
+}
+
+
 void tcp_main_loop()
 {
 	int r;
@@ -634,14 +717,11 @@ void tcp_main_loop()
 	fd_set master_set;
 	fd_set sel_set;
 	int maxfd;
-	int new_sock;
-	union sockaddr_union su;
 	struct tcp_connection* tcpconn;
 	unsigned h;
 	long response[2];
 	int cmd;
 	int bytes;
-	socklen_t su_len;
 	struct timeval timeout;
 
 	/*init */
@@ -653,6 +733,13 @@ void tcp_main_loop()
 			FD_SET(tcp_info[r].socket, &master_set);
 			if (tcp_info[r].socket>maxfd) maxfd=tcp_info[r].socket;
 		}
+#ifdef USE_TLS
+		if ((!tls_disable)&&(tls_info[r].proto==PROTO_TLS) &&
+				(tls_info[r].socket!=-1)){
+			FD_SET(tls_info[r].socket, &master_set);
+			if (tls_info[r].socket>maxfd) maxfd=tls_info[r].socket;
+		}
+#endif
 	}
 	/* set all the unix sockets used for child comm */
 	for (r=1; r<process_no; r++){
@@ -679,36 +766,11 @@ void tcp_main_loop()
 		}
 		
 		for (r=0; r<sock_no && n; r++){
-			if ((FD_ISSET(tcp_info[r].socket, &sel_set))){
-				/* got a connection on r */
-				su_len=sizeof(su);
-				new_sock=accept(tcp_info[r].socket, &(su.s), &su_len);
-				n--;
-				if (new_sock<0){
-					LOG(L_ERR,  "WARNING: tcp_main_loop: error while accepting"
-							" connection(%d): %s\n", errno, strerror(errno));
-					continue;
-				}
-				
-				/* add socket to list */
-				tcpconn=tcpconn_new(new_sock, &su, &tcp_info[r]);
-				if (tcpconn){
-					tcpconn_add(tcpconn);
-					DBG("tcp_main_loop: new connection: %p %d\n",
-						tcpconn, tcpconn->s);
-					/* pass it to a child */
-					if(send2child(tcpconn)<0){
-						LOG(L_ERR,"ERROR: tcp_main_loop: no children "
-								"available\n");
-						TCPCONN_LOCK;
-						if (tcpconn->refcnt==0){
-							close(tcpconn->s);
-							_tcpconn_rm(tcpconn);
-						}else tcpconn->timeout=0; /* force expire */
-						TCPCONN_UNLOCK;
-					}
-				}
-			}
+			handle_new_connect(&tcp_info[r], &sel_set, &n);
+#ifdef USE_TLS
+			if (!tls_disable)
+				handle_new_connect(&tls_info[r], &sel_set, &n);
+#endif
 		}
 		
 		/* check all the read fds (from the tcpconn_addr_hash ) */
@@ -771,7 +833,8 @@ read_again:
 						}
 						tcpconn=(struct tcp_connection*)response[0];
 						if (tcpconn){
-								if (tcpconn->bad) goto tcpconn_destroy;
+								if (tcpconn->state==S_CONN_BAD) 
+									goto tcpconn_destroy;
 								FD_SET(tcpconn->s, &master_set);
 								if (maxfd<tcpconn->s) maxfd=tcpconn->s;
 								/* update the timeout*/
@@ -803,7 +866,7 @@ read_again:
 							}else{
 								/* force timeout */
 								tcpconn->timeout=0;
-								tcpconn->bad=1;
+								tcpconn->state=S_CONN_BAD;
 								DBG("tcp_main_loop: delaying ...\n");
 								
 							}

+ 3 - 3
tcp_read.c

@@ -566,13 +566,13 @@ void tcp_receive_loop(int unix_sock)
 					LOG(L_ERR, "ERROR: tcp_receive_loop: read_fd:"
 									"no fd read\n");
 					resp=CONN_ERROR;
-					con->bad=1;
+					con->state=S_CONN_BAD;
 					release_tcpconn(con, resp, unix_sock);
 				}
 				if (con==0){
 					LOG(L_ERR, "ERROR: tcp_receive_loop: null pointer\n");
 					resp=CONN_ERROR;
-					con->bad=1;
+					con->state=S_CONN_BAD;
 					release_tcpconn(con, resp, unix_sock);
 				}
 				con->timeout=get_ticks()+TCP_CHILD_TIMEOUT;
@@ -596,7 +596,7 @@ void tcp_receive_loop(int unix_sock)
 					if (resp<0){
 						FD_CLR(con->fd, &master_set);
 						tcpconn_listrm(list, con, c_next, c_prev);
-						con->bad=1;
+						con->state=S_CONN_BAD;
 						release_tcpconn(con, resp, unix_sock);
 					}else{
 						/* update timeout */