Browse code

tcp: diff. connect timeout for async & states cleanup

- async mode will now honour tcp_connect_timeout (up to now it
used tcp_send_timeout also for connects)
- internal states cleanup (dropped S_CONN_PENDING, fixed
S_CONN_ACCEPT->S_CONN_OK transition a.s.o)

Andrei Pelinescu-Onciul authored on 06/03/2009 16:54:10
Showing 3 changed files
... ...
@@ -89,9 +89,12 @@ enum tcp_req_states {	H_SKIP_EMPTY, H_SKIP_EMPTY_CR_FOUND, H_SKIP_EMPTY_CRLF_FOU
89 89
 		H_STUN_MSG, H_STUN_READ_BODY, H_STUN_FP, H_STUN_END, H_PING_CRLF
90 90
 	};
91 91
 
92
-enum tcp_conn_states { S_CONN_ERROR=-2, S_CONN_BAD=-1, S_CONN_OK=0, 
93
-						S_CONN_INIT, S_CONN_EOF, 
94
-						S_CONN_ACCEPT, S_CONN_CONNECT, S_CONN_PENDING };
92
+enum tcp_conn_states { S_CONN_ERROR=-2, S_CONN_BAD=-1,
93
+						S_CONN_OK=0, /* established (write or read) */
94
+						S_CONN_INIT, /* initial state (invalid) */
95
+						S_CONN_EOF,
96
+						S_CONN_ACCEPT, S_CONN_CONNECT
97
+					};
95 98
 
96 99
 
97 100
 /* fd communication commands */
... ...
@@ -652,7 +652,10 @@ inline static int _wbufq_add(struct  tcp_connection* c, char* data,
652 652
 		q->first=wb;
653 653
 		q->last_used=0;
654 654
 		q->offset=0;
655
-		q->wr_timeout=get_ticks_raw()+cfg_get(tcp, tcp_cfg, tcp_wq_timeout);
655
+		q->wr_timeout=get_ticks_raw()+
656
+			((c->state==S_CONN_CONNECT)?
657
+					S_TO_TICKS(cfg_get(tcp, tcp_cfg, connect_timeout_s)):
658
+					cfg_get(tcp, tcp_cfg, tcp_wq_timeout));
656 659
 	}else{
657 660
 		wb=q->last;
658 661
 	}
... ...
@@ -774,12 +777,10 @@ inline static int wbufq_run(int fd, struct tcp_connection* c, int* empty)
774 777
 	int n;
775 778
 	int ret;
776 779
 	int block_size;
777
-	ticks_t t;
778 780
 	char* buf;
779 781
 	
780 782
 	*empty=0;
781 783
 	ret=0;
782
-	t=get_ticks_raw();
783 784
 	lock_get(&c->write_lock);
784 785
 	q=&c->wbuf_q;
785 786
 	while(q->first){
... ...
@@ -802,7 +803,6 @@ inline static int wbufq_run(int fd, struct tcp_connection* c, int* empty)
802 803
 				atomic_add_int((int*)tcp_total_wq, -n);
803 804
 				break;
804 805
 			}
805
-			q->wr_timeout=t+cfg_get(tcp, tcp_cfg, tcp_wq_timeout);
806 806
 		}else{
807 807
 			if (n<0){
808 808
 				/* EINTR is handled inside _tcpconn_write_nb */
... ...
@@ -835,9 +835,12 @@ inline static int wbufq_run(int fd, struct tcp_connection* c, int* empty)
835 835
 		q->offset=0;
836 836
 		*empty=1;
837 837
 	}
838
-	if (unlikely(c->state==S_CONN_CONNECT && (ret>0)))
839
-			c->state=S_CONN_OK;
840 838
 	lock_release(&c->write_lock);
839
+	if (likely(ret>0)){
840
+		q->wr_timeout=get_ticks_raw()+cfg_get(tcp, tcp_cfg, tcp_wq_timeout);
841
+		if (unlikely(c->state==S_CONN_CONNECT || c->state==S_CONN_ACCEPT))
842
+			c->state=S_CONN_OK;
843
+	}
841 844
 	return ret;
842 845
 }
843 846
 
... ...
@@ -1693,7 +1696,7 @@ no_id:
1693 1696
 					return -1;
1694 1697
 				}
1695 1698
 				c=tcpconn_new(-1, &dst->to, from, 0, dst->proto,
1696
-								S_CONN_PENDING);
1699
+								S_CONN_CONNECT);
1697 1700
 				if (unlikely(c==0)){
1698 1701
 					LOG(L_ERR, "ERROR: tcp_send %s: could not create new"
1699 1702
 							" connection\n",
... ...
@@ -1738,6 +1741,9 @@ no_id:
1738 1741
 						DBG("tcp_send: pending write on new connection %p "
1739 1742
 								" (%d/%d bytes written)\n", c, n, len);
1740 1743
 						if (n<0) n=0;
1744
+						else 
1745
+							c->state=S_CONN_OK; /* partial write => connect()
1746
+													ended */
1741 1747
 						/* add to the write queue */
1742 1748
 						lock_get(&c->write_lock);
1743 1749
 							if (unlikely(_wbufq_insert(c, buf+n, len-n)<0)){
... ...
@@ -1785,6 +1791,7 @@ no_id:
1785 1791
 					goto conn_wait_error;
1786 1792
 				}
1787 1793
 				LOG(L_INFO, "tcp_send: quick connect for %p\n", c);
1794
+				c->state=S_CONN_OK;
1788 1795
 				/* send to tcp_main */
1789 1796
 				response[0]=(long)c;
1790 1797
 				response[1]=CONN_NEW_COMPLETE;
... ...
@@ -1832,13 +1839,13 @@ get_fd:
1832 1839
 		if (unlikely(cfg_get(tcp, tcp_cfg, async) &&
1833 1840
 						(_wbufq_non_empty(c)
1834 1841
 #ifdef TCP_CONNECT_WAIT
1835
-												|| (c->state==S_CONN_PENDING)
1842
+											|| (c->flags&F_CONN_PENDING)
1836 1843
 #endif /* TCP_CONNECT_WAIT */
1837 1844
 						) )){
1838 1845
 			lock_get(&c->write_lock);
1839 1846
 				if (likely(_wbufq_non_empty(c)
1840 1847
 #ifdef TCP_CONNECT_WAIT
1841
-							|| (c->state==S_CONN_PENDING)
1848
+							|| (c->flags&F_CONN_PENDING)
1842 1849
 #endif /* TCP_CONNECT_WAIT */
1843 1850
 
1844 1851
 							)){
... ...
@@ -1916,7 +1923,7 @@ send_it:
1916 1923
 	if (likely(cfg_get(tcp, tcp_cfg, async))){
1917 1924
 		if (_wbufq_non_empty(c)
1918 1925
 #ifdef TCP_CONNECT_WAIT
1919
-			|| (c->state==S_CONN_PENDING) 
1926
+			|| (c->flags&F_CONN_PENDING) 
1920 1927
 #endif /* TCP_CONNECT_WAIT */
1921 1928
 			){
1922 1929
 			if (unlikely(_wbufq_add(c, buf, len)<0)){
... ...
@@ -1953,6 +1960,9 @@ send_it:
1953 1960
 				((n>=0) || errno==EAGAIN || errno==EWOULDBLOCK)){
1954 1961
 			enable_write_watch=_wbufq_empty(c);
1955 1962
 			if (n<0) n=0;
1963
+			else if (unlikely(c->state==S_CONN_CONNECT ||
1964
+						c->state==S_CONN_ACCEPT))
1965
+				c->state=S_CONN_OK; /* something was written */
1956 1966
 			if (unlikely(_wbufq_add(c, buf+n, len-n)<0)){
1957 1967
 				lock_release(&c->write_lock);
1958 1968
 				n=-1;
... ...
@@ -2026,11 +2036,10 @@ error:
2026 2036
 	
2027 2037
 #ifdef TCP_ASYNC
2028 2038
 	lock_release(&c->write_lock);
2029
-	if (likely(cfg_get(tcp, tcp_cfg, async))){
2030
-		if (unlikely(c->state==S_CONN_CONNECT))
2031
-			c->state=S_CONN_OK;
2032
-	}
2033 2039
 #endif /* TCP_ASYNC */
2040
+	/* in non-async mode here we're either in S_CONN_OK or S_CONN_ACCEPT*/
2041
+	if (unlikely(c->state==S_CONN_CONNECT || c->state==S_CONN_ACCEPT))
2042
+			c->state=S_CONN_OK;
2034 2043
 end:
2035 2044
 #ifdef TCP_FD_CACHE
2036 2045
 	if (unlikely((fd_cache_e==0) && use_fd_cache)){
... ...
@@ -2249,9 +2258,10 @@ inline static int tcpconn_chld_put(struct tcp_connection* tcpconn)
2249 2258
 				tcpconn->s, tcpconn->flags);
2250 2259
 		/* sanity checks */
2251 2260
 		membar_read_atomic_op(); /* make sure we see the current flags */
2252
-		if (unlikely(!(tcpconn->flags & F_CONN_FD_CLOSED) || 
2253
-			(tcpconn->flags & 
2254
-				(F_CONN_HASHED|F_CONN_MAIN_TIMER|F_CONN_READ_W|F_CONN_WRITE_W)) )){
2261
+		if (unlikely(!(tcpconn->flags & F_CONN_FD_CLOSED) ||
2262
+			(tcpconn->flags &
2263
+				(F_CONN_HASHED|F_CONN_MAIN_TIMER|
2264
+				 F_CONN_READ_W|F_CONN_WRITE_W)) )){
2255 2265
 			LOG(L_CRIT, "BUG: tcpconn_chld_put: %p bad flags = %0x\n",
2256 2266
 					tcpconn, tcpconn->flags);
2257 2267
 			abort();
... ...
@@ -2978,8 +2988,8 @@ inline static int handle_ser_child(struct process_table* p, int fd_i)
2978 2988
 		case CONN_NEW_PENDING_WRITE:
2979 2989
 				/* received when a pending connect completes in the same
2980 2990
 				 * tcp_send() that initiated it
2981
-				 * the connection is already in the hash with S_CONN_PENDING
2982
-				 * state (added by tcp_send()) and refcnt at least 1 (for the
2991
+				 * the connection is already in the hash with F_CONN_PENDING
2992
+				 * flag (added by tcp_send()) and refcnt at least 1 (for the
2983 2993
 				 *  hash)*/
2984 2994
 			tcpconn->flags&=~(F_CONN_PENDING|F_CONN_FD_CLOSED);
2985 2995
 			if (unlikely((tcpconn->state==S_CONN_BAD) || (fd==-1))){
... ...
@@ -3003,7 +3013,6 @@ inline static int handle_ser_child(struct process_table* p, int fd_i)
3003 3013
 			tcpconn->timeout=t+con_lifetime;
3004 3014
 			nxt_timeout=con_lifetime;
3005 3015
 			if (unlikely(cmd==CONN_NEW_COMPLETE)){
3006
-				tcpconn->state=S_CONN_OK;
3007 3016
 				/* check if needs to be watched for write */
3008 3017
 				lock_get(&tcpconn->write_lock);
3009 3018
 					/* if queue non empty watch it for write */
... ...
@@ -3023,10 +3032,6 @@ inline static int handle_ser_child(struct process_table* p, int fd_i)
3023 3032
 								F_CONN_WANTS_RD;
3024 3033
 			}else{
3025 3034
 				/* CONN_NEW_PENDING_WRITE */
3026
-				/* we don't know if we successfully sent anything, but
3027
-				   for sure we haven't sent all what we wanted, so consider
3028
-				   the connection in "connecting" state */
3029
-				tcpconn->state=S_CONN_CONNECT;
3030 3035
 				/* no need to check, we have something queued for write */
3031 3036
 				flags=POLLOUT;
3032 3037
 				if (TICKS_LT(tcpconn->wbuf_q.wr_timeout, tcpconn->timeout)
... ...
@@ -170,13 +170,13 @@ again:
170 170
 			*flags|=RD_CONN_EOF;
171 171
 			DBG("tcp_read: EOF on %p, FD %d\n", c, fd);
172 172
 		}else{
173
-			if (unlikely(c->state==S_CONN_CONNECT))
173
+			if (unlikely(c->state==S_CONN_CONNECT || c->state==S_CONN_ACCEPT))
174 174
 				c->state=S_CONN_OK;
175 175
 		}
176 176
 		/* short read */
177 177
 		*flags|=RD_CONN_SHORT_READ;
178 178
 	}else{ /* else normal full read */
179
-		if (unlikely(c->state==S_CONN_CONNECT))
179
+		if (unlikely(c->state==S_CONN_CONNECT || c->state==S_CONN_ACCEPT))
180 180
 			c->state=S_CONN_OK;
181 181
 	}
182 182
 #ifdef EXTRA_DEBUG
... ...
@@ -615,7 +615,8 @@ int tcp_read_req(struct tcp_connection* con, int* bytes_read, int* read_flags)
615 615
 				resp=CONN_ERROR;
616 616
 				goto end_req;
617 617
 			}
618
-			if(con->state!=S_CONN_OK) goto end_req; /* not enough data */
618
+			if (unlikely(con->state!=S_CONN_OK && con->state!=S_CONN_ACCEPT))
619
+				goto end_req; /* not enough data */
619 620
 		}
620 621
 #endif
621 622