Browse code

- tcp: support for pending connects: add a connection immediately to the connection hash (before even attempting the connect sys call) and just queue possible writes. When the connection completes update the connection info & aliases and send the queued data. This avoids parallel connects when the intial connect takes too long (highly experimental, on by default)

Andrei Pelinescu-Onciul authored on 21/12/2007 17:58:07
Showing 6 changed files
... ...
@@ -78,7 +78,7 @@ MAIN_NAME=ser
78 78
 VERSION = 2
79 79
 PATCHLEVEL = 1
80 80
 SUBLEVEL =  0
81
-EXTRAVERSION = -dev15
81
+EXTRAVERSION = -dev16-tcp
82 82
 
83 83
 SER_VER = $(shell expr $(VERSION) \* 1000000 + $(PATCHLEVEL) \* 1000 + \
84 84
 			$(SUBLEVEL) )
... ...
@@ -562,9 +562,10 @@ static void core_tcp_options(rpc_t* rpc, void* c)
562 562
 	if (!tcp_disable){
563 563
 		tcp_options_get(&t);
564 564
 		rpc->add(c, "{", &handle);
565
-		rpc->struct_add(handle, "ddddddddddddd",
565
+		rpc->struct_add(handle, "dddddddddddddd",
566 566
 			"fd_cache",		t.fd_cache,
567 567
 			"tcp_buf_write",	t.tcp_buf_write,
568
+			"tcp_connect_wait",	t.tcp_connect_wait,
568 569
 			"tcpconn_wq_max",	t.tcpconn_wq_max,
569 570
 			"tcp_wq_max",	t.tcp_wq_max,
570 571
 			"tcp_wq_timeout",	TICKS_TO_S(t.tcp_wq_timeout),
... ...
@@ -72,7 +72,9 @@
72 72
 #define F_CONN_READER       4 /* handled by a tcp reader */
73 73
 #define F_CONN_WRITE_W      8 /* watched for write (main) */
74 74
 #define F_CONN_HASHED      16 /* in tcp_main hash */
75
-#define F_CONN_FD_CLOSED   32 /* in tcp_main hash */
75
+#define F_CONN_FD_CLOSED   32 /* fd was already closed */
76
+#define F_CONN_PENDING     64 /* pending connect  (fd not known yet in main) */
77
+#define F_CONN_MAIN_TIMER 128 /* timer active in the tcp_main process */
76 78
 
77 79
 
78 80
 enum tcp_req_errors {	TCP_REQ_INIT, TCP_REQ_OK, TCP_READ_ERROR,
... ...
@@ -87,12 +89,13 @@ enum tcp_req_states {	H_SKIP_EMPTY, H_SKIP, H_LF, H_LFCR,  H_BODY, H_STARTWS,
87 89
 
88 90
 enum tcp_conn_states { S_CONN_ERROR=-2, S_CONN_BAD=-1, S_CONN_OK=0, 
89 91
 						S_CONN_INIT, S_CONN_EOF, 
90
-						S_CONN_ACCEPT, S_CONN_CONNECT };
92
+						S_CONN_ACCEPT, S_CONN_CONNECT, S_CONN_PENDING };
91 93
 
92 94
 
93 95
 /* fd communication commands */
94 96
 enum conn_cmds { CONN_DESTROY=-3, CONN_ERROR=-2, CONN_EOF=-1, CONN_RELEASE, 
95
-					CONN_GET_FD, CONN_NEW, CONN_QUEUED_WRITE };
97
+					CONN_GET_FD, CONN_NEW, CONN_QUEUED_WRITE,
98
+					CONN_NEW_PENDING_WRITE, CONN_NEW_COMPLETE };
96 99
 /* CONN_RELEASE, EOF, ERROR, DESTROY can be used by "reader" processes
97 100
  * CONN_GET_FD, NEW, ERROR only by writers */
98 101
 
... ...
@@ -91,6 +91,8 @@
91 91
  *  2007-12-12  destroy connection asap on wbuf. timeout (andrei)
92 92
  *  2007-12-13  changed the refcnt and destroy scheme, now refcnt is 1 if
93 93
  *                linked into the hash tables (was 0) (andrei)
94
+ *  2007-12-21  support for pending connects (connections are added to the
95
+ *               hash immediately and writes on them are buffered) (andrei)
94 96
  */
95 97
 
96 98
 
... ...
@@ -864,61 +866,60 @@ error:
864 866
 
865 867
 
866 868
 
867
-struct tcp_connection* tcpconn_connect( union sockaddr_union* server, 
868
-										union sockaddr_union* from,
869
-										int type)
869
+/* do the actual connect, set sock. options a.s.o
870
+ * returns socket on success, -1 on error
871
+ * sets also *res_local_addr, res_si and state (S_CONN_CONNECT for an
872
+ * unfinished connect and S_CONN_OK for a finished one)*/
873
+inline static int tcp_do_connect(	union sockaddr_union* server,
874
+									union sockaddr_union* from,
875
+									int type,
876
+									union sockaddr_union* res_local_addr,
877
+									struct socket_info** res_si,
878
+									enum tcp_conn_states *state
879
+									)
870 880
 {
871 881
 	int s;
872
-	struct socket_info* si;
873 882
 	union sockaddr_union my_name;
874 883
 	socklen_t my_name_len;
875
-	struct tcp_connection* con;
876 884
 	struct ip_addr ip;
877
-	enum tcp_conn_states state;
878 885
 #ifdef TCP_BUF_WRITE
879 886
 	int n;
880 887
 #endif /* TCP_BUF_WRITE */
881 888
 
882
-	s=-1;
883
-	
884
-	if (*tcp_connections_no >= tcp_max_connections){
885
-		LOG(L_ERR, "ERROR: tcpconn_connect: maximum number of connections"
886
-					" exceeded (%d/%d)\n",
887
-					*tcp_connections_no, tcp_max_connections);
888
-		goto error;
889
-	}
890 889
 	s=socket(AF2PF(server->s.sa_family), SOCK_STREAM, 0);
891
-	if (s==-1){
892
-		LOG(L_ERR, "ERROR: tcpconn_connect: socket: (%d) %s\n",
890
+	if (unlikely(s==-1)){
891
+		LOG(L_ERR, "ERROR: tcp_do_connect: socket: (%d) %s\n",
893 892
 				errno, strerror(errno));
894 893
 		goto error;
895 894
 	}
896 895
 	if (init_sock_opt(s)<0){
897
-		LOG(L_ERR, "ERROR: tcpconn_connect: init_sock_opt failed\n");
896
+		LOG(L_ERR, "ERROR: tcp_do_connect: init_sock_opt failed\n");
898 897
 		goto error;
899 898
 	}
900 899
 	
901
-	if (from && bind(s, &from->s, sockaddru_len(*from)) != 0)
902
-		LOG(L_WARN, "WARNING: tcpconn_connect: binding to source address"
900
+	if (unlikely(from && bind(s, &from->s, sockaddru_len(*from)) != 0)){
901
+		LOG(L_WARN, "WARNING: tcp_do_connect: binding to source address"
903 902
 					" failed: %s [%d]\n", strerror(errno), errno);
904
-	state=S_CONN_OK;
903
+	}
904
+	*state=S_CONN_OK;
905 905
 #ifdef TCP_BUF_WRITE
906 906
 	if (likely(tcp_options.tcp_buf_write)){
907 907
 again:
908 908
 		n=connect(s, &server->s, sockaddru_len(*server));
909 909
 		if (unlikely(n==-1)){
910 910
 			if (errno==EINTR) goto again;
911
-			if (errno!=EINPROGRESS && errno!=EALREADY){
912
-				LOG(L_ERR, "ERROR: tcpconn_connect: connect: (%d) %s\n",
911
+			if (likely(errno==EINPROGRESS))
912
+				*state=S_CONN_CONNECT;
913
+			else if (errno!=EALREADY){
914
+				LOG(L_ERR, "ERROR: tcp_do_connect: connect: (%d) %s\n",
913 915
 						errno, strerror(errno));
914 916
 				goto error;
915 917
 			}
916
-			state=S_CONN_CONNECT;
917 918
 		}
918 919
 	}else{
919 920
 #endif /* TCP_BUF_WRITE */
920 921
 		if (tcp_blocking_connect(s, &server->s, sockaddru_len(*server))<0){
921
-			LOG(L_ERR, "ERROR: tcpconn_connect: tcp_blocking_connect"
922
+			LOG(L_ERR, "ERROR: tcp_do_connect: tcp_blocking_connect"
922 923
 						" failed\n");
923 924
 			goto error;
924 925
 		}
... ...
@@ -932,31 +933,64 @@ again:
932 933
 			goto find_socket;
933 934
 	}
934 935
 	my_name_len=sizeof(my_name);
935
-	if (getsockname(s, &my_name.s, &my_name_len)!=0){
936
-		LOG(L_ERR, "ERROR: tcp_connect: getsockname failed: %s(%d)\n",
936
+	if (unlikely(getsockname(s, &my_name.s, &my_name_len)!=0)){
937
+		LOG(L_ERR, "ERROR: tcp_do_connect: getsockname failed: %s(%d)\n",
937 938
 				strerror(errno), errno);
938
-		si=0; /* try to go on */
939
-		goto skip;
939
+		*res_si=0;
940
+		goto error;
940 941
 	}
941 942
 	from=&my_name; /* update from with the real "from" address */
942 943
 	su2ip_addr(&ip, &my_name);
943 944
 find_socket:
944 945
 #ifdef USE_TLS
945
-	if (type==PROTO_TLS)
946
-		si=find_si(&ip, 0, PROTO_TLS);
946
+	if (unlikely(type==PROTO_TLS))
947
+		*res_si=find_si(&ip, 0, PROTO_TLS);
947 948
 	else
948 949
 #endif
949
-		si=find_si(&ip, 0, PROTO_TCP);
950
-skip:
951
-	if (si==0){
952
-		LOG(L_WARN, "WARNING: tcp_connect: could not find corresponding"
950
+		*res_si=find_si(&ip, 0, PROTO_TCP);
951
+	
952
+	if (unlikely(*res_si==0)){
953
+		LOG(L_WARN, "WARNING: tcp_do_connect: could not find corresponding"
953 954
 				" listening socket, using default...\n");
954
-		if (server->s.sa_family==AF_INET) si=sendipv4_tcp;
955
+		if (server->s.sa_family==AF_INET) *res_si=sendipv4_tcp;
955 956
 #ifdef USE_IPV6
956
-		else si=sendipv6_tcp;
957
+		else *res_si=sendipv6_tcp;
957 958
 #endif
958 959
 	}
959
-	con=tcpconn_new(s, server, from, si,  type, state);
960
+	*res_local_addr=*from;
961
+	return s;
962
+error:
963
+	if (s!=-1) close(s);
964
+	return -1;
965
+}
966
+
967
+
968
+
969
+struct tcp_connection* tcpconn_connect( union sockaddr_union* server, 
970
+										union sockaddr_union* from,
971
+										int type)
972
+{
973
+	int s;
974
+	struct socket_info* si;
975
+	union sockaddr_union my_name;
976
+	struct tcp_connection* con;
977
+	enum tcp_conn_states state;
978
+
979
+	s=-1;
980
+	
981
+	if (*tcp_connections_no >= tcp_max_connections){
982
+		LOG(L_ERR, "ERROR: tcpconn_connect: maximum number of connections"
983
+					" exceeded (%d/%d)\n",
984
+					*tcp_connections_no, tcp_max_connections);
985
+		goto error;
986
+	}
987
+	s=tcp_do_connect(server, from, type, &my_name, &si, &state);
988
+	if (s==-1){
989
+		LOG(L_ERR, "ERROR: tcp_do_connect: failed (%d) %s\n",
990
+				errno, strerror(errno));
991
+		goto error;
992
+	}
993
+	con=tcpconn_new(s, server, &my_name, si, type, state);
960 994
 	if (con==0){
961 995
 		LOG(L_ERR, "ERROR: tcp_connect: tcpconn_new failed, closing the "
962 996
 				 " socket\n");
... ...
@@ -971,6 +1005,59 @@ error:
971 1005
 
972 1006
 
973 1007
 
1008
+#ifdef TCP_CONNECT_WAIT
1009
+int tcpconn_finish_connect( struct tcp_connection* c,
1010
+												union sockaddr_union* from)
1011
+{
1012
+	int s;
1013
+	int r;
1014
+	union sockaddr_union local_addr;
1015
+	struct socket_info* si;
1016
+	enum tcp_conn_states state;
1017
+	struct tcp_conn_alias* a;
1018
+	
1019
+	s=tcp_do_connect(&c->rcv.src_su, from, c->type, &local_addr, &si, &state);
1020
+	if (unlikely(s==-1)){
1021
+		LOG(L_ERR, "ERROR: tcpconn_finish_connect: tcp_do_connect for %p"
1022
+						" failed\n", c);
1023
+		return -1;
1024
+	}
1025
+	c->rcv.bind_address=si;
1026
+	su2ip_addr(&c->rcv.dst_ip, &local_addr);
1027
+	c->rcv.dst_port=su_getport(&local_addr);
1028
+	/* update aliases if needed */
1029
+	if (likely(from==0)){
1030
+		/* add aliases */
1031
+		TCPCONN_LOCK;
1032
+		_tcpconn_add_alias_unsafe(c, c->rcv.src_port, &c->rcv.dst_ip, 0,
1033
+													tcp_new_conn_alias_flags);
1034
+		_tcpconn_add_alias_unsafe(c, c->rcv.src_port, &c->rcv.dst_ip,
1035
+									c->rcv.dst_port, tcp_new_conn_alias_flags);
1036
+		TCPCONN_UNLOCK;
1037
+	}else if (su_cmp(from, &local_addr)!=1){
1038
+		TCPCONN_LOCK;
1039
+			/* remove all the aliases except the first one and re-add them
1040
+			 * (there shouldn't be more then the 3 default aliases at this 
1041
+			 * stage) */
1042
+			for (r=1; r<c->aliases; r++){
1043
+				a=&c->con_aliases[r];
1044
+				tcpconn_listrm(tcpconn_aliases_hash[a->hash], a, next, prev);
1045
+			}
1046
+			c->aliases=1;
1047
+			/* add the local_ip:0 and local_ip:local_port aliases */
1048
+			_tcpconn_add_alias_unsafe(c, c->rcv.src_port, &c->rcv.dst_ip,
1049
+												0, tcp_new_conn_alias_flags);
1050
+			_tcpconn_add_alias_unsafe(c, c->rcv.src_port, &c->rcv.dst_ip,
1051
+									c->rcv.dst_port, tcp_new_conn_alias_flags);
1052
+		TCPCONN_UNLOCK;
1053
+	}
1054
+	
1055
+	return s;
1056
+}
1057
+#endif /* TCP_CONNECT_WAIT */
1058
+
1059
+
1060
+
974 1061
 /* adds a tcp connection to the tcpconn hashes
975 1062
  * Note: it's called _only_ from the tcp_main process */
976 1063
 inline static struct tcp_connection*  tcpconn_add(struct tcp_connection *c)
... ...
@@ -994,10 +1081,12 @@ inline static struct tcp_connection*  tcpconn_add(struct tcp_connection *c)
994 1081
 		 *   -- for finding if a fully specified connection exists */
995 1082
 		_tcpconn_add_alias_unsafe(c, c->rcv.src_port, &zero_ip, 0,
996 1083
 													tcp_new_conn_alias_flags);
997
-		_tcpconn_add_alias_unsafe(c, c->rcv.src_port, &c->rcv.dst_ip, 0,
1084
+		if (likely(c->rcv.dst_ip.af && ! ip_addr_any(&c->rcv.dst_ip))){
1085
+			_tcpconn_add_alias_unsafe(c, c->rcv.src_port, &c->rcv.dst_ip, 0,
998 1086
 													tcp_new_conn_alias_flags);
999
-		_tcpconn_add_alias_unsafe(c, c->rcv.src_port, &c->rcv.dst_ip,
1087
+			_tcpconn_add_alias_unsafe(c, c->rcv.src_port, &c->rcv.dst_ip,
1000 1088
 									c->rcv.dst_port, tcp_new_conn_alias_flags);
1089
+		}
1001 1090
 		/* ignore add_alias errors, there are some valid cases when one
1002 1091
 		 *  of the add_alias would fail (e.g. first add_alias for 2 connections
1003 1092
 		 *   with the same destination but different src. ip*/
... ...
@@ -1407,6 +1496,98 @@ no_id:
1407 1496
 						break;
1408 1497
 				}
1409 1498
 			}
1499
+#if defined(TCP_CONNECT_WAIT) && defined(TCP_BUF_WRITE)
1500
+			if (likely(tcp_options.tcp_connect_wait && 
1501
+						tcp_options.tcp_buf_write )){
1502
+				/* FIXME: flag for timer? + check again */
1503
+				if (unlikely(*tcp_connections_no >= tcp_max_connections)){
1504
+					LOG(L_ERR, "ERROR: tcp_send: maximum number of connections"
1505
+								" exceeded (%d/%d)\n",
1506
+								*tcp_connections_no, tcp_max_connections);
1507
+					return -1;
1508
+				}
1509
+				c=tcpconn_new(-1, &dst->to, from, 0, dst->proto,
1510
+								S_CONN_PENDING);
1511
+				if (unlikely(c==0)){
1512
+					LOG(L_ERR, "ERROR: tcp_send: could not create new"
1513
+							" connection\n");
1514
+					return -1;
1515
+				}
1516
+				c->flags|=F_CONN_PENDING|F_CONN_FD_CLOSED;
1517
+				atomic_set(&c->refcnt, 2); /* ref from here and from main hash
1518
+											 table */
1519
+				/* add it to id hash and aliases */
1520
+				if (unlikely(tcpconn_add(c)==0)){
1521
+					LOG(L_ERR, "ERROR: tcp_send: could not add "
1522
+									"connection %p\n", c);
1523
+					_tcpconn_free(c);
1524
+					n=-1;
1525
+					goto end_no_conn;
1526
+				}
1527
+				/* do connect and if src ip or port changed, update the 
1528
+				 * aliases */
1529
+				if (unlikely((fd=tcpconn_finish_connect(c, from))<0)){
1530
+					LOG(L_ERR, "ERROR: tcp_send: tcpconn_finsish_connect(%p)"
1531
+							" failed\n", c);
1532
+					goto conn_wait_error;
1533
+				}
1534
+				/* ? TODO: it might be faster just to queue the write directly
1535
+				 *  and send to main CONN_NEW_PENDING_WRITE */
1536
+				/* delay sending the fd to main after the send */
1537
+				
1538
+				/* NOTE: no lock here, because the connection is marked as
1539
+				 * pending and nobody else will try to write on it. However
1540
+				 * this might produce out-of-order writes. If this is not
1541
+				 * desired either lock before the write or use 
1542
+				 * _wbufq_insert(...) */
1543
+				n=_tcpconn_write_nb(fd, c, buf, len);
1544
+				if (unlikely(n<0)){
1545
+					if (errno==EAGAIN|| errno==EWOULDBLOCK){
1546
+						DBG("tcp_send: pending write on new connection (%p)\n",
1547
+								c);
1548
+						/* add to the write queue */
1549
+						lock_get(&c->write_lock);
1550
+							if (unlikely(_wbufq_add(c, buf, len)<0)){
1551
+								lock_release(&c->write_lock);
1552
+								n=-1;
1553
+								LOG(L_ERR, "ERROR: tcp_send: EAGAIN and"
1554
+										" write queue full or failed for %p\n",
1555
+										c);
1556
+								goto conn_wait_error;
1557
+							}
1558
+						lock_release(&c->write_lock);
1559
+						/* send to tcp_main */
1560
+						response[0]=(long)c;
1561
+						response[1]=CONN_NEW_PENDING_WRITE;
1562
+						if (unlikely(send_fd(unix_tcp_sock, response, 
1563
+												sizeof(response), fd) <= 0)){
1564
+							LOG(L_ERR, "BUG: tcp_send: CONN_NEW_PENDING_WRITE"
1565
+										" for %p failed:" " %s (%d)\n",
1566
+										c, strerror(errno), errno);
1567
+							goto conn_wait_error;
1568
+						}
1569
+						goto end;
1570
+					}
1571
+					/* error: destroy it directly */
1572
+					LOG(L_ERR, "ERROR: tcp_send: connect & send "
1573
+										" for %p failed:" " %s (%d)\n",
1574
+										c, strerror(errno), errno);
1575
+					goto conn_wait_error;
1576
+				}
1577
+				LOG(L_INFO, "tcp_send: quick connect for %p\n", c);
1578
+				/* send to tcp_main */
1579
+				response[0]=(long)c;
1580
+				response[1]=CONN_NEW_COMPLETE;
1581
+				if (unlikely(send_fd(unix_tcp_sock, response, 
1582
+										sizeof(response), fd) <= 0)){
1583
+					LOG(L_ERR, "BUG: tcp_send: CONN_NEW_COMPLETE  for %p"
1584
+								" failed:" " %s (%d)\n",
1585
+								c, strerror(errno), errno);
1586
+					goto conn_wait_error;
1587
+				}
1588
+				goto end;
1589
+			}
1590
+#endif /* TCP_CONNECT_WAIT  && TCP_BUF_WRITE */
1410 1591
 			if (unlikely((c=tcpconn_connect(&dst->to, from, dst->proto))==0)){
1411 1592
 				LOG(L_ERR, "ERROR: tcp_send: connect failed\n");
1412 1593
 				return -1;
... ...
@@ -1414,6 +1595,9 @@ no_id:
1414 1595
 			atomic_set(&c->refcnt, 2); /* ref. from here and it will also
1415 1596
 			                              be added in the tcp_main hash */
1416 1597
 			fd=c->s;
1598
+			c->flags|=F_CONN_FD_CLOSED; /* not yet opened in main */
1599
+			/* ? TODO: it might be faster just to queue the write and
1600
+			 * send to main a CONN_NEW_PENDING_WRITE */
1417 1601
 			
1418 1602
 			/* send the new tcpconn to "tcp main" */
1419 1603
 			response[0]=(long)c;
... ...
@@ -1432,9 +1616,18 @@ no_id:
1432 1616
 get_fd:
1433 1617
 #ifdef TCP_BUF_WRITE
1434 1618
 		/* if data is already queued, we don't need the fd any more */
1435
-		if (unlikely(tcp_options.tcp_buf_write && _wbufq_non_empty(c))){
1619
+		if (unlikely(tcp_options.tcp_buf_write && (_wbufq_non_empty(c)
1620
+#ifdef TCP_CONNECT_WAIT
1621
+												|| (c->state==S_CONN_PENDING)
1622
+#endif /* TCP_CONNECT_WAIT */
1623
+						) )){
1436 1624
 			lock_get(&c->write_lock);
1437
-				if (likely(_wbufq_non_empty(c))){
1625
+				if (likely(_wbufq_non_empty(c)
1626
+#ifdef TCP_CONNECT_WAIT
1627
+							|| (c->state==S_CONN_PENDING)
1628
+#endif /* TCP_CONNECT_WAIT */
1629
+
1630
+							)){
1438 1631
 					do_close_fd=0;
1439 1632
 					if (unlikely(_wbufq_add(c, buf, len)<0)){
1440 1633
 						lock_release(&c->write_lock);
... ...
@@ -1503,7 +1696,11 @@ send_it:
1503 1696
 	lock_get(&c->write_lock);
1504 1697
 #ifdef TCP_BUF_WRITE
1505 1698
 	if (likely(tcp_options.tcp_buf_write)){
1506
-		if (_wbufq_non_empty(c)){
1699
+		if (_wbufq_non_empty(c)
1700
+#ifdef TCP_CONNECT_WAIT
1701
+			|| (c->state==S_CONN_PENDING) 
1702
+#endif /* TCP_CONNECT_WAIT */
1703
+			){
1507 1704
 			if (unlikely(_wbufq_add(c, buf, len)<0)){
1508 1705
 				lock_release(&c->write_lock);
1509 1706
 				n=-1;
... ...
@@ -1528,7 +1725,8 @@ send_it:
1528 1725
 #else /* ! TCP_BUF_WRITE */
1529 1726
 	lock_release(&c->write_lock);
1530 1727
 #endif /* TCP_BUF_WRITE */
1531
-	DBG("tcp_send: after write: c= %p n=%d fd=%d\n",c, n, fd);
1728
+	
1729
+	DBG("tcp_send: after real write: c= %p n=%d fd=%d\n",c, n, fd);
1532 1730
 	DBG("tcp_send: buf=\n%.*s\n", (int)len, buf);
1533 1731
 	if (unlikely(n<0)){
1534 1732
 #ifdef TCP_BUF_WRITE
... ...
@@ -1542,12 +1740,12 @@ send_it:
1542 1740
 			}
1543 1741
 			lock_release(&c->write_lock);
1544 1742
 			n=len;
1545
-			if (enable_write_watch){
1743
+			if (likely(enable_write_watch)){
1546 1744
 				response[0]=(long)c;
1547 1745
 				response[1]=CONN_QUEUED_WRITE;
1548
-				if (send_all(unix_tcp_sock, response, sizeof(response))<=0){
1746
+				if (send_all(unix_tcp_sock, response, sizeof(response)) <= 0){
1549 1747
 					LOG(L_ERR, "BUG: tcp_send: error return failed "
1550
-							"(write):%s (%d)\n", strerror(errno), errno);
1748
+								"(write):%s (%d)\n", strerror(errno), errno);
1551 1749
 					n=-1;
1552 1750
 					goto error;
1553 1751
 				}
... ...
@@ -1556,9 +1754,12 @@ send_it:
1556 1754
 		}else{
1557 1755
 			lock_release(&c->write_lock);
1558 1756
 		}
1757
+#endif /* TCP_BUF_WRITE */
1758
+		LOG(L_ERR, "ERROR: tcp_send: failed to send on %p: %s (%d)\n",
1759
+					c, strerror(errno), errno);
1760
+#ifdef TCP_BUF_WRITE
1559 1761
 error:
1560 1762
 #endif /* TCP_BUF_WRITE */
1561
-		LOG(L_ERR, "ERROR: tcp_send: failed to send\n");
1562 1763
 		/* error on the connection , mark it as bad and set 0 timeout */
1563 1764
 		c->state=S_CONN_BAD;
1564 1765
 		c->timeout=get_ticks_raw();
... ...
@@ -1566,9 +1767,9 @@ error:
1566 1767
 		response[0]=(long)c;
1567 1768
 		response[1]=CONN_ERROR;
1568 1769
 		if (send_all(unix_tcp_sock, response, sizeof(response))<=0){
1569
-			LOG(L_ERR, "BUG: tcp_send: error return failed (write):%s (%d)\n",
1770
+			LOG(L_CRIT, "BUG: tcp_send: error return failed (write):%s (%d)\n",
1570 1771
 					strerror(errno), errno);
1571
-			tcpconn_chld_put(c); /* deref. it manually & free on 0 */
1772
+			tcpconn_chld_put(c); /* deref. it manually */
1572 1773
 			n=-1;
1573 1774
 		}
1574 1775
 		/* CONN_ERROR will auto-dec refcnt => we must not call tcpconn_put 
... ...
@@ -1604,6 +1805,30 @@ release_c:
1604 1805
 	tcpconn_chld_put(c); /* release c (dec refcnt & free on 0) */
1605 1806
 end_no_conn:
1606 1807
 	return n;
1808
+#ifdef TCP_CONNECT_WAIT
1809
+conn_wait_error:
1810
+	/* connect or send failed on newly created connection which was not
1811
+	 * yet sent to tcp_main (but was already hashed) => don't send to main,
1812
+	 * unhash and destroy directly (if refcnt>2 it will be destroyed when the 
1813
+	 * last sender releases the connection (tcpconn_chld_put(c))) or when
1814
+	 * tcp_main receives a CONN_ERROR it*/
1815
+	c->state=S_CONN_BAD;
1816
+	TCPCONN_LOCK;
1817
+		/* FIXME: race: what if CONN_ERROR is sent by another tcp_send() to
1818
+		 * tcp_main ? */
1819
+		if (c->flags & F_CONN_HASHED){
1820
+			/* if some other parallel tcp_send did send CONN_ERROR to
1821
+			 * tcp_main, the connection might be already detached */
1822
+			_tcpconn_detach(c);
1823
+			c->flags&=~F_CONN_HASHED;
1824
+			TCPCONN_UNLOCK;
1825
+			tcpconn_put(c);
1826
+		}else
1827
+			TCPCONN_UNLOCK;
1828
+	/* dec refcnt -> mark it for destruction */
1829
+	tcpconn_chld_put(c);
1830
+	return -1;
1831
+#endif /* TCP_CONNET_WAIT */
1607 1832
 }
1608 1833
 
1609 1834
 
... ...
@@ -1752,77 +1977,6 @@ error:
1752 1977
 
1753 1978
 
1754 1979
 
1755
-#if 0
1756
-/* used internally by tcp_main_loop()
1757
- * tries to destroy a tcp connection (if it cannot it will force a timeout)
1758
- * Note: it's called _only_ from the tcp_main process */
1759
-static void tcpconn_destroy(struct tcp_connection* tcpconn)
1760
-{
1761
-	int fd;
1762
-	ticks_t t;
1763
-
1764
-	/* always try to remove the timer to protect against tcpconn_destroy
1765
-	 *  being called several times for the same connection 
1766
-	 *  (if the timer is already removed, nothing happens) */
1767
-	if (likely(!(tcpconn->flags & F_CONN_READER)))
1768
-		local_timer_del(&tcp_main_ltimer, &tcpconn->timer);
1769
-#ifdef TCP_BUF_WRITE
1770
-	if (unlikely((tcpconn->flags & F_CONN_WRITE_W) ||
1771
-				!(tcpconn->flags & F_CONN_REMOVED))){
1772
-		LOG(L_CRIT, "tcpconn_destroy: possible BUG: flags = %0x\n",
1773
-					tcpconn->flags);
1774
-	}
1775
-	if (unlikely(_wbufq_non_empty(tcpconn))){
1776
-		lock_get(&tcpconn->write_lock);
1777
-			/* check again, while holding the lock */
1778
-			if (likely(_wbufq_non_empty(tcpconn)))
1779
-				_wbufq_destroy(&tcpconn->wbuf_q);
1780
-		lock_release(&tcpconn->write_lock);
1781
-	}
1782
-#endif /* TCP_BUF_WRITE */
1783
-	TCPCONN_LOCK; /*avoid races w/ tcp_send*/
1784
-	if (likely(atomic_dec_and_test(&tcpconn->refcnt))){ 
1785
-		_tcpconn_detach(tcpconn);
1786
-		TCPCONN_UNLOCK;
1787
-		DBG("tcpconn_destroy: destroying connection %p (%d, %d) flags %04x\n",
1788
-				tcpconn, tcpconn->id, tcpconn->s, tcpconn->flags);
1789
-		fd=tcpconn->s;
1790
-#ifdef USE_TLS
1791
-		/*FIXME: lock ->writelock ? */
1792
-		if (tcpconn->type==PROTO_TLS)
1793
-			tls_close(tcpconn, fd);
1794
-#endif
1795
-		_tcpconn_free(tcpconn); /* destroys also the wbuf_q if still present*/
1796
-#ifdef TCP_FD_CACHE
1797
-		if (likely(tcp_options.fd_cache)) shutdown(fd, SHUT_RDWR);
1798
-#endif /* TCP_FD_CACHE */
1799
-		if (unlikely(close(fd)<0)){
1800
-			LOG(L_ERR, "ERROR: tcpconn_destroy; close() failed: %s (%d)\n",
1801
-					strerror(errno), errno);
1802
-		}
1803
-		(*tcp_connections_no)--;
1804
-	}else{
1805
-		TCPCONN_UNLOCK;
1806
-		/* force timeout */
1807
-		t=get_ticks_raw();
1808
-		tcpconn->timeout=t+TCPCONN_WAIT_TIMEOUT;
1809
-		tcpconn->state=S_CONN_BAD;
1810
-		if (!(tcpconn->flags & F_CONN_READER)){
1811
-			/* re-activate the timer only if the connection is handled
1812
-			 * by tcp_main (and not by a tcp reader)*/
1813
-			tcpconn->timer.f=tcpconn_main_timeout;
1814
-			local_timer_reinit(&tcpconn->timer);
1815
-			local_timer_add(&tcp_main_ltimer, &tcpconn->timer, 
1816
-									TCPCONN_WAIT_TIMEOUT, t);
1817
-		}
1818
-		DBG("tcpconn_destroy: delaying (%p, flags %04x) ...\n",
1819
-				tcpconn, tcpconn->flags);
1820
-	}
1821
-}
1822
-#endif
1823
-
1824
-
1825
-
1826 1980
 /* close tcp_main's fd from a tcpconn
1827 1981
  * WARNING: call only in tcp_main context */
1828 1982
 inline static void tcpconn_close_main_fd(struct tcp_connection* tcpconn)
... ...
@@ -1857,7 +2011,7 @@ close_again:
1857 2011
 inline static int tcpconn_chld_put(struct tcp_connection* tcpconn)
1858 2012
 {
1859 2013
 	if (unlikely(atomic_dec_and_test(&tcpconn->refcnt))){
1860
-		DBG("tcpconn_put_chld: destroying connection %p (%d, %d) "
2014
+		DBG("tcpconn_chld_put: destroying connection %p (%d, %d) "
1861 2015
 				"flags %04x\n", tcpconn, tcpconn->id,
1862 2016
 				tcpconn->s, tcpconn->flags);
1863 2017
 		/* sanity checks */
... ...
@@ -1865,7 +2019,7 @@ inline static int tcpconn_chld_put(struct tcp_connection* tcpconn)
1865 2019
 					 !(tcpconn->flags & F_CONN_REMOVED) || 
1866 2020
 					(tcpconn->flags & 
1867 2021
 					 		(F_CONN_HASHED| F_CONN_WRITE_W)) )){
1868
-			LOG(L_CRIT, "BUG: tcpconn_put_chld: %p bad flags = %0x\n",
2022
+			LOG(L_CRIT, "BUG: tcpconn_chld_put: %p bad flags = %0x\n",
1869 2023
 					tcpconn, tcpconn->flags);
1870 2024
 			abort();
1871 2025
 		}
... ...
@@ -1889,7 +2043,8 @@ inline static void tcpconn_destroy(struct tcp_connection* tcpconn)
1889 2043
 			LOG(L_CRIT, "BUG: tcpconn_destroy: called with hashed"
1890 2044
 						" connection (%p)\n", tcpconn);
1891 2045
 			/* try to continue */
1892
-			local_timer_del(&tcp_main_ltimer, &tcpconn->timer);
2046
+			if (likely(tcpconn->flags & F_CONN_MAIN_TIMER))
2047
+				local_timer_del(&tcp_main_ltimer, &tcpconn->timer);
1893 2048
 			TCPCONN_LOCK;
1894 2049
 				_tcpconn_detach(tcpconn);
1895 2050
 			TCPCONN_UNLOCK;
... ...
@@ -1949,23 +2104,24 @@ inline static int tcpconn_put_destroy(struct tcp_connection* tcpconn)
1949 2104
  */
1950 2105
 inline static int tcpconn_try_unhash(struct tcp_connection* tcpconn)
1951 2106
 {
1952
-	if (unlikely((tcpconn->flags & F_CONN_WRITE_W) ||
1953
-				!(tcpconn->flags & F_CONN_REMOVED))){
1954
-		/* sanity check */
1955
-		LOG(L_CRIT, "BUG: tcpconn_put_destroy: %p flags = %0x\n",
1956
-					tcpconn, tcpconn->flags);
1957
-	}
1958 2107
 	if (likely(tcpconn->flags & F_CONN_HASHED)){
1959
-		tcpconn->flags&=~F_CONN_HASHED;
1960 2108
 		tcpconn->state=S_CONN_BAD;
1961
-		if (likely(!(tcpconn->flags & F_CONN_READER)))
2109
+		if (likely(tcpconn->flags & F_CONN_MAIN_TIMER)){
1962 2110
 			local_timer_del(&tcp_main_ltimer, &tcpconn->timer);
1963
-		else
2111
+			tcpconn->flags&=~F_CONN_MAIN_TIMER;
2112
+		}else
1964 2113
 			/* in case it's still in a reader timer */
1965 2114
 			tcpconn->timeout=get_ticks_raw();
1966 2115
 		TCPCONN_LOCK;
1967
-			_tcpconn_detach(tcpconn);
1968
-		TCPCONN_UNLOCK;
2116
+			if (tcpconn->flags & F_CONN_HASHED){
2117
+				tcpconn->flags&=~F_CONN_HASHED;
2118
+				_tcpconn_detach(tcpconn);
2119
+				TCPCONN_UNLOCK;
2120
+			}else{
2121
+				/* tcp_send was faster and did unhash it itself */
2122
+				TCPCONN_UNLOCK;
2123
+				return 0;
2124
+			}
1969 2125
 #ifdef TCP_BUF_WRITE
1970 2126
 		/* empty possible write buffers (optional) */
1971 2127
 		if (unlikely(_wbufq_non_empty(tcpconn))){
... ...
@@ -2279,6 +2435,7 @@ inline static int handle_tcp_child(struct tcp_child* tcp_c, int fd_i)
2279 2435
 			local_timer_reinit(&tcpconn->timer);
2280 2436
 			local_timer_add(&tcp_main_ltimer, &tcpconn->timer, crt_timeout, t);
2281 2437
 			/* must be after the de-ref*/
2438
+			tcpconn->flags|=F_CONN_MAIN_TIMER;
2282 2439
 			tcpconn->flags&=~(F_CONN_REMOVED|F_CONN_READER);
2283 2440
 #ifdef TCP_BUF_WRITE
2284 2441
 			if (unlikely(tcpconn->flags & F_CONN_WRITE_W))
... ...
@@ -2416,17 +2573,26 @@ inline static int handle_ser_child(struct process_table* p, int fd_i)
2416 2573
 	}
2417 2574
 	switch(cmd){
2418 2575
 		case CONN_ERROR:
2576
+			LOG(L_ERR, "handle_ser_child: ERROR: received CON_ERROR for %p"
2577
+					" (id %d), refcnt %d\n", 
2578
+					tcpconn, tcpconn->id, atomic_get(&tcpconn->refcnt));
2579
+#ifdef TCP_CONNECT_WAIT
2580
+			/* if the connection is pending => it might be on the way of
2581
+			 * reaching tcp_main (e.g. CONN_NEW_COMPLETE or 
2582
+			 *  CONN_NEW_PENDING_WRITE) =>  it cannot be destroyed here */
2583
+			if ( !(tcpconn->flags & F_CONN_PENDING) && 
2584
+					tcpconn_try_unhash(tcpconn) )
2585
+				tcpconn_put(tcpconn);
2586
+#else /* ! TCP_CONNECT_WAIT */
2587
+			if ( tcpconn_try_unhash(tcpconn) )
2588
+				tcpconn_put(tcpconn);
2589
+#endif /* TCP_CONNECT_WAIT */
2419 2590
 			if ( (!(tcpconn->flags & F_CONN_REMOVED) ||
2420 2591
 					(tcpconn->flags & F_CONN_WRITE_W) ) && (tcpconn->s!=-1)){
2421 2592
 				io_watch_del(&io_h, tcpconn->s, -1, IO_FD_CLOSING);
2422 2593
 				tcpconn->flags|=F_CONN_REMOVED;
2423 2594
 				tcpconn->flags&=~F_CONN_WRITE_W;
2424 2595
 			}
2425
-			LOG(L_ERR, "handle_ser_child: ERROR: received CON_ERROR for %p"
2426
-					" (id %d), refcnt %d\n", 
2427
-					tcpconn, tcpconn->id, atomic_get(&tcpconn->refcnt));
2428
-			if (tcpconn_try_unhash(tcpconn))
2429
-				tcpconn_put(tcpconn);
2430 2596
 			tcpconn_put_destroy(tcpconn); /* dec refcnt & destroy on 0 */
2431 2597
 			break;
2432 2598
 		case CONN_GET_FD:
... ...
@@ -2460,7 +2626,8 @@ inline static int handle_ser_child(struct process_table* p, int fd_i)
2460 2626
 			 * no need for reinit */
2461 2627
 			local_timer_add(&tcp_main_ltimer, &tcpconn->timer, 
2462 2628
 								tcp_con_lifetime, t);
2463
-			tcpconn->flags&=~F_CONN_REMOVED;
2629
+			tcpconn->flags|=F_CONN_MAIN_TIMER;
2630
+			tcpconn->flags&=~(F_CONN_REMOVED|F_CONN_FD_CLOSED);
2464 2631
 			flags=POLLIN 
2465 2632
 #ifdef TCP_BUF_WRITE
2466 2633
 					/* not used for now, the connection is sent to tcp_main
... ...
@@ -2482,6 +2649,11 @@ inline static int handle_ser_child(struct process_table* p, int fd_i)
2482 2649
 			break;
2483 2650
 #ifdef TCP_BUF_WRITE
2484 2651
 		case CONN_QUEUED_WRITE:
2652
+			/* received only if the wr. queue is empty and a write finishes
2653
+			 * with EAGAIN (common after connect())
2654
+			 * it should only enable write watching on the fd. The connection
2655
+			 * should be  already in the hash. The refcnt is not changed.
2656
+			 */
2485 2657
 			if (unlikely((tcpconn->state==S_CONN_BAD) || 
2486 2658
 							!(tcpconn->flags & F_CONN_HASHED) ))
2487 2659
 				break;
... ...
@@ -2509,7 +2681,7 @@ inline static int handle_ser_child(struct process_table* p, int fd_i)
2509 2681
 				}
2510 2682
 				tcpconn->flags|=F_CONN_WRITE_W;
2511 2683
 				t=get_ticks_raw();
2512
-				if (likely(!(tcpconn->flags & F_CONN_READER) && 
2684
+				if (likely((tcpconn->flags & F_CONN_MAIN_TIMER) && 
2513 2685
 					(TICKS_LT(tcpconn->wbuf_q.wr_timeout, tcpconn->timeout)) &&
2514 2686
 						TICKS_LT(t, tcpconn->wbuf_q.wr_timeout) )){
2515 2687
 					/* _wbufq_nonempty() is guaranteed here */
... ...
@@ -2527,6 +2699,65 @@ inline static int handle_ser_child(struct process_table* p, int fd_i)
2527 2699
 							" already watched for write\n", tcpconn);
2528 2700
 			}
2529 2701
 			break;
2702
+#ifdef TCP_CONNECT_WAIT
2703
+		case CONN_NEW_COMPLETE:
2704
+		case CONN_NEW_PENDING_WRITE:
2705
+				/* received when a pending connect completes in the same
2706
+				 * tcp_send() that initiated it
2707
+				 * the connection is already in the hash with S_CONN_PENDING
2708
+				 * state (added by tcp_send()) and refcnt at least 1 (for the
2709
+				 *  hash)*/
2710
+			tcpconn->flags&=~(F_CONN_PENDING|F_CONN_FD_CLOSED|F_CONN_REMOVED);
2711
+			if (unlikely((tcpconn->state==S_CONN_BAD) || (fd==-1))){
2712
+				if (unlikely(fd==-1))
2713
+					LOG(L_CRIT, "BUG: handle_ser_child: CONN_NEW_COMPLETE:"
2714
+								" no fd received\n");
2715
+				else
2716
+					LOG(L_WARN, "WARNING: handle_ser_child: CONN_NEW_COMPLETE:"
2717
+							" received connection with error\n");
2718
+				tcpconn->flags|=F_CONN_FD_CLOSED;
2719
+				tcpconn->state=S_CONN_BAD;
2720
+				tcpconn_try_unhash(tcpconn);
2721
+				tcpconn_put_destroy(tcpconn);
2722
+				break;
2723
+			}
2724
+			tcpconn->state=S_CONN_OK;
2725
+			(*tcp_connections_no)++;
2726
+			tcpconn->s=fd;
2727
+			/* update the timeout*/
2728
+			t=get_ticks_raw();
2729
+			tcpconn->timeout=t+tcp_con_lifetime;
2730
+			/* activate the timer (already properly init. in tcpconn_new())
2731
+			 * no need for reinit */
2732
+			local_timer_add(&tcp_main_ltimer, &tcpconn->timer, 
2733
+								tcp_con_lifetime, t);
2734
+			tcpconn->flags|=F_CONN_MAIN_TIMER;
2735
+			if (unlikely(cmd==CONN_NEW_COMPLETE)){
2736
+				/* check if needs to be watched for write */
2737
+				lock_get(&tcpconn->write_lock);
2738
+					/* if queue non empty watch it for write */
2739
+					flags=(_wbufq_empty(tcpconn)-1)&POLLOUT;
2740
+				lock_release(&tcpconn->write_lock);
2741
+				tcpconn->flags|=(!(flags&POLLOUT)-1)&F_CONN_WRITE_W;
2742
+			}else{
2743
+				/* CONN_NEW_PENDING_WRITE */
2744
+				/* no need to check, we have something queued for write */
2745
+				flags=POLLOUT;
2746
+				tcpconn->flags|=F_CONN_WRITE_W;
2747
+			}
2748
+			flags|=POLLIN;
2749
+			if (unlikely(
2750
+					io_watch_add(&io_h, tcpconn->s, flags,
2751
+												F_TCPCONN, tcpconn)<0)){
2752
+				LOG(L_CRIT, "ERROR: tcp_main: handle_ser_child: failed to add"
2753
+						" new socket to the fd list\n");
2754
+				tcpconn->flags|=F_CONN_REMOVED;
2755
+				tcpconn->flags&=~F_CONN_WRITE_W;
2756
+				tcpconn_try_unhash(tcpconn); /*  unhash & dec refcnt */
2757
+				tcpconn_put_destroy(tcpconn);
2758
+			}
2759
+			break;
2760
+#endif /* TCP_CONNECT_WAIT */
2530 2761
 #endif /* TCP_BUF_WRITE */
2531 2762
 		default:
2532 2763
 			LOG(L_CRIT, "BUG: handle_ser_child: unknown cmd %d\n", cmd);
... ...
@@ -2679,6 +2910,7 @@ static inline int handle_new_connect(struct socket_info* si)
2679 2910
 		/* activate the timer */
2680 2911
 		local_timer_add(&tcp_main_ltimer, &tcpconn->timer, 
2681 2912
 								tcp_con_lifetime, get_ticks_raw());
2913
+		tcpconn->flags|=F_CONN_MAIN_TIMER;
2682 2914
 		tcpconn->flags&=~F_CONN_REMOVED;
2683 2915
 		if (unlikely(io_watch_add(&io_h, tcpconn->s, POLLIN, 
2684 2916
 													F_TCPCONN, tcpconn)<0)){
... ...
@@ -2794,6 +3026,7 @@ inline static int handle_tcpconn_ev(struct tcp_connection* tcpconn, short ev,
2794 3026
 				goto error;
2795 3027
 		tcpconn->flags|=F_CONN_REMOVED|F_CONN_READER;
2796 3028
 		local_timer_del(&tcp_main_ltimer, &tcpconn->timer);
3029
+		tcpconn->flags&=~F_CONN_MAIN_TIMER;
2797 3030
 		tcpconn_ref(tcpconn); /* refcnt ++ */
2798 3031
 		if (unlikely(send2child(tcpconn)<0)){
2799 3032
 			LOG(L_ERR,"ERROR: handle_tcpconn_ev: no children available\n");
... ...
@@ -2962,9 +3195,10 @@ static inline void tcpconn_destroy_all()
2962 3195
 				if (is_tcp_main){
2963 3196
 					/* we cannot close or remove the fd if we are not in the
2964 3197
 					 * tcp main proc.*/
2965
-					if (!(c->flags & F_CONN_READER))
3198
+					if ((c->flags & F_CONN_MAIN_TIMER)){
2966 3199
 						local_timer_del(&tcp_main_ltimer, &c->timer);
2967
-					/* else still in some reader */
3200
+						c->flags&=~F_CONN_MAIN_TIMER;
3201
+					} /* else still in some reader */
2968 3202
 					fd=c->s;
2969 3203
 					if (fd>0 && (!(c->flags & F_CONN_REMOVED)
2970 3204
 #ifdef TCP_BUF_WRITE
... ...
@@ -40,7 +40,10 @@ void init_tcp_options()
40 40
 	tcp_options.tcpconn_wq_max=32*1024; /* 32 k */
41 41
 	tcp_options.tcp_wq_max=10*1024*1024; /* 10 MB */
42 42
 	tcp_options.tcp_wq_timeout=S_TO_TICKS(tcp_send_timeout);
43
-#endif
43
+#ifdef TCP_CONNECT_WAIT
44
+	tcp_options.tcp_connect_wait=1;
45
+#endif /* TCP_CONNECT_WAIT */
46
+#endif /* TCP_BUF_WRITE */
44 47
 #ifdef TCP_FD_CACHE
45 48
 	tcp_options.fd_cache=1;
46 49
 #endif
... ...
@@ -89,7 +92,16 @@ void tcp_options_check()
89 92
 	W_OPT_NC(tcp_wq_max);
90 93
 	W_OPT_NC(tcp_wq_timeout);
91 94
 #endif /* TCP_BUF_WRITE */
92
-
95
+#ifndef TCP_CONNECT_WAIT
96
+	W_OPT_NC(tcp_connect_wait);
97
+#endif /* TCP_CONNECT_WAIT */
98
+	
99
+	if (tcp_options.tcp_connect_wait && !tcp_options.tcp_buf_write){
100
+		WARN("tcp_options: tcp_connect_wait depends on tcp_buf_write, "
101
+				" disabling...\n");
102
+		tcp_options.tcp_connect_wait=0;
103
+	}
104
+	
93 105
 #if ! defined HAVE_TCP_DEFER_ACCEPT && ! defined HAVE_TCP_ACCEPT_FILTER
94 106
 	W_OPT_NS(defer_accept);
95 107
 #endif
... ...
@@ -31,6 +31,16 @@
31 31
 #define TCP_BUF_WRITE /* enabled buffered writing */
32 32
 #endif 
33 33
 
34
+#if !defined(NO_TCP_CONNECT_WAIT) && defined(TCP_BUF_WRITE)
35
+#define TCP_CONNECT_WAIT /* enable pending connects support */
36
+#endif
37
+
38
+#if defined(TCP_CONNECT_WAIT) && !defined(TCP_BUF_WRITE)
39
+/* check for impossible configuration: TCP_CONNECT_WAIT w/o TCP_BUF_WRITE */
40
+#warning "disabling TCP_CONNECT_WAIT because TCP_BUF_WRITE is not defined"
41
+#undef TCP_CONNECT_WAIT
42
+#endif
43
+
34 44
 #ifndef NO_TCP_FD_CACHE
35 45
 #define TCP_FD_CACHE /* enable fd caching */
36 46
 #endif
... ...
@@ -102,6 +112,7 @@ struct tcp_cfg_options{
102 112
 	int fd_cache; /* on /off */
103 113
 	/* tcp buf. write options */
104 114
 	int tcp_buf_write; /* on / off */
115
+	int tcp_connect_wait; /* on / off, depends on tcp_buf_write */
105 116
 	unsigned int tcpconn_wq_max; /* maximum queue len per connection */
106 117
 	unsigned int tcp_wq_max; /* maximum overall queued bytes */
107 118
 	unsigned int tcp_wq_timeout;      /* timeout for queue writes */