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 774
 	int n;
775 775
 	int ret;
776 776
 	int block_size;
777
-	ticks_t t;
778 777
 	char* buf;
779 778
 	
780 779
 	*empty=0;
781 780
 	ret=0;
782
-	t=get_ticks_raw();
783 781
 	lock_get(&c->write_lock);
784 782
 	q=&c->wbuf_q;
785 783
 	while(q->first){
... ...
@@ -802,7 +803,6 @@ inline static int wbufq_run(int fd, struct tcp_connection* c, int* empty)
802 802
 				atomic_add_int((int*)tcp_total_wq, -n);
803 803
 				break;
804 804
 			}
805
-			q->wr_timeout=t+cfg_get(tcp, tcp_cfg, tcp_wq_timeout);
806 805
 		}else{
807 806
 			if (n<0){
808 807
 				/* 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 1693
 					return -1;
1694 1694
 				}
1695 1695
 				c=tcpconn_new(-1, &dst->to, from, 0, dst->proto,
1696
-								S_CONN_PENDING);
1696
+								S_CONN_CONNECT);
1697 1697
 				if (unlikely(c==0)){
1698 1698
 					LOG(L_ERR, "ERROR: tcp_send %s: could not create new"
1699 1699
 							" connection\n",
... ...
@@ -1738,6 +1741,9 @@ no_id:
1738 1738
 						DBG("tcp_send: pending write on new connection %p "
1739 1739
 								" (%d/%d bytes written)\n", c, n, len);
1740 1740
 						if (n<0) n=0;
1741
+						else 
1742
+							c->state=S_CONN_OK; /* partial write => connect()
1743
+													ended */
1741 1744
 						/* add to the write queue */
1742 1745
 						lock_get(&c->write_lock);
1743 1746
 							if (unlikely(_wbufq_insert(c, buf+n, len-n)<0)){
... ...
@@ -1785,6 +1791,7 @@ no_id:
1785 1785
 					goto conn_wait_error;
1786 1786
 				}
1787 1787
 				LOG(L_INFO, "tcp_send: quick connect for %p\n", c);
1788
+				c->state=S_CONN_OK;
1788 1789
 				/* send to tcp_main */
1789 1790
 				response[0]=(long)c;
1790 1791
 				response[1]=CONN_NEW_COMPLETE;
... ...
@@ -1832,13 +1839,13 @@ get_fd:
1832 1832
 		if (unlikely(cfg_get(tcp, tcp_cfg, async) &&
1833 1833
 						(_wbufq_non_empty(c)
1834 1834
 #ifdef TCP_CONNECT_WAIT
1835
-												|| (c->state==S_CONN_PENDING)
1835
+											|| (c->flags&F_CONN_PENDING)
1836 1836
 #endif /* TCP_CONNECT_WAIT */
1837 1837
 						) )){
1838 1838
 			lock_get(&c->write_lock);
1839 1839
 				if (likely(_wbufq_non_empty(c)
1840 1840
 #ifdef TCP_CONNECT_WAIT
1841
-							|| (c->state==S_CONN_PENDING)
1841
+							|| (c->flags&F_CONN_PENDING)
1842 1842
 #endif /* TCP_CONNECT_WAIT */
1843 1843
 
1844 1844
 							)){
... ...
@@ -1916,7 +1923,7 @@ send_it:
1916 1916
 	if (likely(cfg_get(tcp, tcp_cfg, async))){
1917 1917
 		if (_wbufq_non_empty(c)
1918 1918
 #ifdef TCP_CONNECT_WAIT
1919
-			|| (c->state==S_CONN_PENDING) 
1919
+			|| (c->flags&F_CONN_PENDING) 
1920 1920
 #endif /* TCP_CONNECT_WAIT */
1921 1921
 			){
1922 1922
 			if (unlikely(_wbufq_add(c, buf, len)<0)){
... ...
@@ -1953,6 +1960,9 @@ send_it:
1953 1953
 				((n>=0) || errno==EAGAIN || errno==EWOULDBLOCK)){
1954 1954
 			enable_write_watch=_wbufq_empty(c);
1955 1955
 			if (n<0) n=0;
1956
+			else if (unlikely(c->state==S_CONN_CONNECT ||
1957
+						c->state==S_CONN_ACCEPT))
1958
+				c->state=S_CONN_OK; /* something was written */
1956 1959
 			if (unlikely(_wbufq_add(c, buf+n, len-n)<0)){
1957 1960
 				lock_release(&c->write_lock);
1958 1961
 				n=-1;
... ...
@@ -2026,11 +2036,10 @@ error:
2026 2026
 	
2027 2027
 #ifdef TCP_ASYNC
2028 2028
 	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 2029
 #endif /* TCP_ASYNC */
2030
+	/* in non-async mode here we're either in S_CONN_OK or S_CONN_ACCEPT*/
2031
+	if (unlikely(c->state==S_CONN_CONNECT || c->state==S_CONN_ACCEPT))
2032
+			c->state=S_CONN_OK;
2034 2033
 end:
2035 2034
 #ifdef TCP_FD_CACHE
2036 2035
 	if (unlikely((fd_cache_e==0) && use_fd_cache)){
... ...
@@ -2249,9 +2258,10 @@ inline static int tcpconn_chld_put(struct tcp_connection* tcpconn)
2249 2249
 				tcpconn->s, tcpconn->flags);
2250 2250
 		/* sanity checks */
2251 2251
 		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)) )){
2252
+		if (unlikely(!(tcpconn->flags & F_CONN_FD_CLOSED) ||
2253
+			(tcpconn->flags &
2254
+				(F_CONN_HASHED|F_CONN_MAIN_TIMER|
2255
+				 F_CONN_READ_W|F_CONN_WRITE_W)) )){
2255 2256
 			LOG(L_CRIT, "BUG: tcpconn_chld_put: %p bad flags = %0x\n",
2256 2257
 					tcpconn, tcpconn->flags);
2257 2258
 			abort();
... ...
@@ -2978,8 +2988,8 @@ inline static int handle_ser_child(struct process_table* p, int fd_i)
2978 2978
 		case CONN_NEW_PENDING_WRITE:
2979 2979
 				/* received when a pending connect completes in the same
2980 2980
 				 * 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
2981
+				 * the connection is already in the hash with F_CONN_PENDING
2982
+				 * flag (added by tcp_send()) and refcnt at least 1 (for the
2983 2983
 				 *  hash)*/
2984 2984
 			tcpconn->flags&=~(F_CONN_PENDING|F_CONN_FD_CLOSED);
2985 2985
 			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 3003
 			tcpconn->timeout=t+con_lifetime;
3004 3004
 			nxt_timeout=con_lifetime;
3005 3005
 			if (unlikely(cmd==CONN_NEW_COMPLETE)){
3006
-				tcpconn->state=S_CONN_OK;
3007 3006
 				/* check if needs to be watched for write */
3008 3007
 				lock_get(&tcpconn->write_lock);
3009 3008
 					/* 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 3023
 								F_CONN_WANTS_RD;
3024 3024
 			}else{
3025 3025
 				/* 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 3026
 				/* no need to check, we have something queued for write */
3031 3027
 				flags=POLLOUT;
3032 3028
 				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