Browse code

tcp: tcp_send() split in 3 smaller functions

- tcp_send() split into 3 smaller internal functions (needed for
future tls use) + minor cleanups.
- CONN_QUEUED_WRITE now auto-decrements the connection refcnt.

Andrei Pelinescu-Onciul authored on 23/03/2010 16:58:30
Showing 1 changed files
... ...
@@ -1717,7 +1717,12 @@ inline static void tcp_fd_cache_add(struct tcp_connection *c, int fd)
1717 1717
 
1718 1718
 inline static int tcpconn_chld_put(struct tcp_connection* tcpconn);
1719 1719
 
1720
+static int tcpconn_do_send(int fd, struct tcp_connection* c,
1721
+							char* buf, unsigned len,
1722
+							snd_flags_t send_flags, long* resp);
1720 1723
 
1724
+static int tcpconn_send_put(struct tcp_connection* c, char* buf, unsigned len,
1725
+							snd_flags_t send_flags);
1721 1726
 
1722 1727
 /* finds a tcpconn & sends on it
1723 1728
  * uses the dst members to, proto (TCP|TLS) and id and tries to send
... ...
@@ -1728,7 +1733,6 @@ int tcp_send(struct dest_info* dst, union sockaddr_union* from,
1728 1733
 					char* buf, unsigned len)
1729 1734
 {
1730 1735
 	struct tcp_connection *c;
1731
-	struct tcp_connection *tmp;
1732 1736
 	struct ip_addr ip;
1733 1737
 	int port;
1734 1738
 	int fd;
... ...
@@ -1736,16 +1740,7 @@ int tcp_send(struct dest_info* dst, union sockaddr_union* from,
1736 1740
 	int n;
1737 1741
 	int do_close_fd;
1738 1742
 	ticks_t con_lifetime;
1739
-#ifdef TCP_ASYNC
1740
-	int enable_write_watch;
1741
-#endif /* TCP_ASYNC */
1742
-#ifdef TCP_FD_CACHE
1743
-	struct fd_cache_entry* fd_cache_e;
1744
-	int use_fd_cache;
1745 1743
 	
1746
-	use_fd_cache=cfg_get(tcp, tcp_cfg, fd_cache);
1747
-	fd_cache_e=0;
1748
-#endif /* TCP_FD_CACHE */
1749 1744
 	do_close_fd=1; /* close the fd on exit */
1750 1745
 	port=su_getport(&dst->to);
1751 1746
 	con_lifetime=cfg_get(tcp, tcp_cfg, con_lifetime);
... ...
@@ -1890,7 +1885,7 @@ int tcp_send(struct dest_info* dst, union sockaddr_union* from,
1890 1885
 							goto conn_wait_error;
1891 1886
 						}
1892 1887
 						n=len;
1893
-						goto end;
1888
+						goto conn_wait_success;
1894 1889
 					}
1895 1890
 					/* if first write failed it's most likely a
1896 1891
 					   connect error */
... ...
@@ -1945,7 +1940,7 @@ int tcp_send(struct dest_info* dst, union sockaddr_union* from,
1945 1940
 								c, strerror(errno), errno);
1946 1941
 					goto conn_wait_error;
1947 1942
 				}
1948
-				goto end;
1943
+				goto conn_wait_success;
1949 1944
 			}
1950 1945
 #endif /* TCP_CONNECT_WAIT  && TCP_ASYNC */
1951 1946
 			if (unlikely((c=tcpconn_connect(&dst->to, from, dst->proto,
... ...
@@ -1977,11 +1972,129 @@ int tcp_send(struct dest_info* dst, union sockaddr_union* from,
1977 1972
 				n=-1;
1978 1973
 				goto end_no_conn;
1979 1974
 			}
1980
-			goto send_it;
1975
+			/* new connection => send on it directly */
1976
+			n = tcpconn_do_send(fd, c, buf, len, dst->send_flags,
1977
+									&response[1]);
1978
+			if (unlikely(response[1] != CONN_NOP)) {
1979
+				response[0]=(long)c;
1980
+				if (send_all(unix_tcp_sock, response, sizeof(response)) <= 0) {
1981
+					BUG("tcp_main command %ld sending failed (write):"
1982
+							"%s (%d)\n", response[1], strerror(errno), errno);
1983
+					/* all commands != CONN_NOP returned by tcpconn_do_send()
1984
+					   (CONN_EOF, CONN_ERROR, CONN_QUEUED_WRITE) will auto-dec
1985
+					   refcnt => if sending the command fails we have to
1986
+					   dec. refcnt by hand */
1987
+					tcpconn_chld_put(c); /* deref. it manually */
1988
+					n=-1;
1989
+				}
1990
+				/* here refcnt for c is already decremented => c contents can
1991
+				   no longer be used and refcnt _must_ _not_ be decremented
1992
+				   again on exit */
1993
+				if (unlikely(n < 0 || response[1] == CONN_EOF)) {
1994
+					/* on error or eof, close fd */
1995
+					close(fd);
1996
+				} else if (response[1] == CONN_QUEUED_WRITE) {
1997
+#ifdef TCP_FD_CACHE
1998
+					if (cfg_get(tcp, tcp_cfg, fd_cache)) {
1999
+						tcp_fd_cache_add(c, fd);
2000
+					} else
2001
+#endif /* TCP_FD_CACHE */
2002
+						close(fd);
2003
+				} else {
2004
+					BUG("unexpected tcpconn_do_send() return & response:"
2005
+							" %d, %ld\n", n, response[1]);
2006
+				}
2007
+				goto end_no_deref;
2008
+			}
2009
+#ifdef TCP_FD_CACHE
2010
+			if (cfg_get(tcp, tcp_cfg, fd_cache)) {
2011
+				tcp_fd_cache_add(c, fd);
2012
+			}else
2013
+#endif /* TCP_FD_CACHE */
2014
+				close(fd);
2015
+		/* here we can have only commands that _do_ _not_ dec refcnt.
2016
+		   (CONN_EOF, CON_ERROR, CON_QUEUED_WRITE are all treated above) */
2017
+			goto release_c;
1981 2018
 		}
1982 2019
 /* get_fd: */
2020
+	/* existing connection, send on it */
2021
+	n = tcpconn_send_put(c, buf, len, dst->send_flags);
2022
+	/* no deref needed (automatically done inside tcpconn_send_put() */
2023
+	return n;
2024
+#ifdef TCP_CONNECT_WAIT
2025
+conn_wait_success:
2026
+#ifdef TCP_FD_CACHE
2027
+	if (cfg_get(tcp, tcp_cfg, fd_cache)) {
2028
+		tcp_fd_cache_add(c, fd);
2029
+	} else
2030
+#endif /* TCP_FD_CACHE */
2031
+		close(fd);
2032
+	tcpconn_chld_put(c); /* release c (dec refcnt & free on 0) */
2033
+	return n;
2034
+conn_wait_error:
2035
+	n=-1;
2036
+conn_wait_close:
2037
+	/* connect or send failed or immediate close-after-send was requested on
2038
+	 * newly created connection which was not yet sent to tcp_main (but was
2039
+	 * already hashed) => don't send to main, unhash and destroy directly
2040
+	 * (if refcnt>2 it will be destroyed when the last sender releases the
2041
+	 * connection (tcpconn_chld_put(c))) or when tcp_main receives a
2042
+	 * CONN_ERROR it*/
2043
+	c->state=S_CONN_BAD;
2044
+	/* we are here only if we opened a new fd (and not reused a cached or
2045
+	   a reader one) => if the connect was successful close the fd */
2046
+	if (fd>=0) close(fd);
2047
+	TCPCONN_LOCK;
2048
+		if (c->flags & F_CONN_HASHED){
2049
+			/* if some other parallel tcp_send did send CONN_ERROR to
2050
+			 * tcp_main, the connection might be already detached */
2051
+			_tcpconn_detach(c);
2052
+			c->flags&=~F_CONN_HASHED;
2053
+			TCPCONN_UNLOCK;
2054
+			tcpconn_put(c);
2055
+		}else
2056
+			TCPCONN_UNLOCK;
2057
+	/* dec refcnt -> mark it for destruction */
2058
+	tcpconn_chld_put(c);
2059
+	return n;
2060
+#endif /* TCP_CONNET_WAIT */
2061
+release_c:
2062
+	tcpconn_chld_put(c); /* release c (dec refcnt & free on 0) */
2063
+end_no_deref:
2064
+end_no_conn:
2065
+	return n;
2066
+}
2067
+
2068
+
2069
+
2070
+/** sends on an existing tcpconn.
2071
+ * As opposed to tcp_send(), this function requires an existing
2072
+ * tcp connection.
2073
+ * WARNING: the tcp_connection will be de-referenced.
2074
+ * @param c - existing tcp connection pointer.
2075
+ * @param buf - data to be sent.
2076
+ * @param len - data length,
2077
+ * @return >=0 on success, -1 on error.
2078
+ */
2079
+static int tcpconn_send_put(struct tcp_connection* c, char* buf, unsigned len,
2080
+							snd_flags_t send_flags)
2081
+{
2082
+	struct tcp_connection *tmp;
2083
+	int fd;
2084
+	long response[2];
2085
+	int n;
2086
+	int do_close_fd;
2087
+#ifdef TCP_FD_CACHE
2088
+	struct fd_cache_entry* fd_cache_e;
2089
+	int use_fd_cache;
2090
+	
2091
+	use_fd_cache=cfg_get(tcp, tcp_cfg, fd_cache);
2092
+	fd_cache_e=0;
2093
+#endif /* TCP_FD_CACHE */
2094
+	do_close_fd=1; /* close the fd on exit */
2095
+	response[1] = CONN_NOP;
1983 2096
 #ifdef TCP_ASYNC
1984
-		/* if data is already queued, we don't need the fd any more */
2097
+	/* if data is already queued, we don't need the fd */
1985 2098
 #ifdef TCP_CONNECT_WAIT
1986 2099
 		if (unlikely(cfg_get(tcp, tcp_cfg, async) &&
1987 2100
 						(_wbufq_non_empty(c) || (c->flags&F_CONN_PENDING)) ))
... ...
@@ -2000,6 +2113,9 @@ int tcp_send(struct dest_info* dst, union sockaddr_union* from,
2000 2113
 					if (unlikely(_wbufq_add(c, buf, len)<0)){
2001 2114
 						lock_release(&c->write_lock);
2002 2115
 						n=-1;
2116
+						response[1] = CONN_ERROR;
2117
+						c->state=S_CONN_BAD;
2118
+						c->timeout=get_ticks_raw(); /* force timeout */
2003 2119
 						goto error;
2004 2120
 					}
2005 2121
 					n=len;
... ...
@@ -2057,17 +2173,105 @@ int tcp_send(struct dest_info* dst, union sockaddr_union* from,
2057 2173
 						  tmp, n
2058 2174
 				   );
2059 2175
 				n=-1; /* fail */
2176
+				/* don't cache fd & close it */
2177
+				do_close_fd = 1;
2178
+#ifdef TCP_FD_CACHE
2179
+				use_fd_cache = 0;
2180
+#endif /* TCP_FD_CACHE */
2060 2181
 				goto end;
2061 2182
 			}
2062 2183
 			DBG("tcp_send: after receive_fd: c= %p n=%d fd=%d\n",c, n, fd);
2063 2184
 		}
2064 2185
 	
2065
-	
2066
-send_it:
2186
+	n = tcpconn_do_send(fd, c, buf, len, send_flags, &response[1]);
2187
+	if (unlikely(response[1] != CONN_NOP)) {
2188
+error:
2189
+		response[0]=(long)c;
2190
+		if (send_all(unix_tcp_sock, response, sizeof(response)) <= 0) {
2191
+			BUG("tcp_main command %ld sending failed (write):%s (%d)\n",
2192
+					response[1], strerror(errno), errno);
2193
+			/* all commands != CONN_NOP returned by tcpconn_do_send()
2194
+			   (CONN_EOF, CONN_ERROR, CONN_QUEUED_WRITE) will auto-dec refcnt
2195
+			   => if sending the command fails we have to dec. refcnt by hand
2196
+			 */
2197
+			tcpconn_chld_put(c); /* deref. it manually */
2198
+			n=-1;
2199
+		}
2200
+		/* here refcnt for c is already decremented => c contents can no
2201
+		   longer be used and refcnt _must_ _not_ be decremented again
2202
+		   on exit */
2203
+		if (unlikely(n < 0 || response[1] == CONN_EOF)) {
2204
+			/* on error or eof, remove from cache or close fd */
2205
+#ifdef TCP_FD_CACHE
2206
+			if (unlikely(fd_cache_e)){
2207
+				tcp_fd_cache_rm(fd_cache_e);
2208
+				fd_cache_e = 0;
2209
+				close(fd);
2210
+			}else
2211
+#endif /* TCP_FD_CACHE */
2212
+				if (do_close_fd) close(fd);
2213
+		} else if (response[1] == CONN_QUEUED_WRITE) {
2214
+#ifdef TCP_FD_CACHE
2215
+			if (unlikely((fd_cache_e==0) && use_fd_cache)){
2216
+				tcp_fd_cache_add(c, fd);
2217
+			}else
2218
+#endif /* TCP_FD_CACHE */
2219
+				if (do_close_fd) close(fd);
2220
+		} else {
2221
+			BUG("unexpected tcpconn_do_send() return & response: %d, %ld\n",
2222
+					n, response[1]);
2223
+		}
2224
+		return n; /* no tcpconn_put */
2225
+	}
2226
+end:
2227
+#ifdef TCP_FD_CACHE
2228
+	if (unlikely((fd_cache_e==0) && use_fd_cache)){
2229
+		tcp_fd_cache_add(c, fd);
2230
+	}else
2231
+#endif /* TCP_FD_CACHE */
2232
+	if (do_close_fd) close(fd);
2233
+	/* here we can have only commands that _do_ _not_ dec refcnt.
2234
+	   (CONN_EOF, CON_ERROR, CON_QUEUED_WRITE are all treated above) */
2235
+release_c:
2236
+	tcpconn_chld_put(c); /* release c (dec refcnt & free on 0) */
2237
+	return n;
2238
+}
2239
+
2240
+
2241
+
2242
+/** lower level send (connection and fd should be known).
2243
+ * It takes care of possible write-queueing, blacklisting a.s.o.
2244
+ * It expects a valid tcp connection. It doesn't touch the ref. cnts.
2245
+ * @param c - existing tcp connection pointer (state and flags might be
2246
+ *            changed).
2247
+ * @param buf - data to be sent.
2248
+ * @param len - data length.
2249
+ * @param send_flags
2250
+ * @param resp - filled with a cmd. for tcp_main:
2251
+ *                      CONN_NOP - nothing needs to be done (do not send
2252
+ *                                 anything to tcp_main).
2253
+ *                      CONN_ERROR - error, connection should be closed.
2254
+ *                      CONN_EOF - no error, but connection should be closed.
2255
+ *                      CONN_QUEUED_WRITE - new write queue (connection
2256
+ *                                 should be watched for write and the wr.
2257
+ *                                 queue flushed).
2258
+ * @return >=0 on success, < 0 on error && *resp == CON_ERROR.
2259
+ *
2260
+ */
2261
+static int tcpconn_do_send(int fd, struct tcp_connection* c,
2262
+							char* buf, unsigned len,
2263
+							snd_flags_t send_flags, long* resp)
2264
+{
2265
+	int  n;
2266
+#ifdef TCP_ASYNC
2267
+	int enable_write_watch;
2268
+#endif /* TCP_ASYNC */
2269
+
2067 2270
 	DBG("tcp_send: sending...\n");
2271
+	*resp = CONN_NOP;
2068 2272
 	lock_get(&c->write_lock);
2069 2273
 	/* update connection send flags with the current ones */
2070
-	tcpconn_set_send_flags(c, dst->send_flags);
2274
+	tcpconn_set_send_flags(c, send_flags);
2071 2275
 #ifdef TCP_ASYNC
2072 2276
 	if (likely(cfg_get(tcp, tcp_cfg, async))){
2073 2277
 		if (_wbufq_non_empty(c)
... ...
@@ -2088,14 +2292,14 @@ send_it:
2088 2292
 	}else{
2089 2293
 #endif /* TCP_ASYNC */
2090 2294
 #ifdef USE_TLS
2091
-	if (c->type==PROTO_TLS)
2092
-		n=tls_blocking_write(c, fd, buf, len);
2093
-	else
2295
+		if (c->type==PROTO_TLS)
2296
+			n=tls_blocking_write(c, fd, buf, len);
2297
+		else
2094 2298
 #endif
2095 2299
 		/* n=tcp_blocking_write(c, fd, buf, len); */
2096
-		n=tsend_stream(fd, buf, len,
2097
-						TICKS_TO_S(cfg_get(tcp, tcp_cfg, send_timeout)) *
2098
-						1000);
2300
+			n=tsend_stream(fd, buf, len,
2301
+							TICKS_TO_S(cfg_get(tcp, tcp_cfg, send_timeout)) *
2302
+							1000);
2099 2303
 #ifdef TCP_ASYNC
2100 2304
 	}
2101 2305
 #else /* ! TCP_ASYNC */
... ...
@@ -2122,16 +2326,8 @@ send_it:
2122 2326
 			}
2123 2327
 			lock_release(&c->write_lock);
2124 2328
 			n=len;
2125
-			if (likely(enable_write_watch)){
2126
-				response[0]=(long)c;
2127
-				response[1]=CONN_QUEUED_WRITE;
2128
-				if (send_all(unix_tcp_sock, response, sizeof(response)) <= 0){
2129
-					LOG(L_ERR, "BUG: tcp_send: error return failed "
2130
-								"(write):%s (%d)\n", strerror(errno), errno);
2131
-					n=-1;
2132
-					goto error;
2133
-				}
2134
-			}
2329
+			if (likely(enable_write_watch))
2330
+				*resp=CONN_QUEUED_WRITE;
2135 2331
 			goto end;
2136 2332
 		}else{
2137 2333
 			lock_release(&c->write_lock);
... ...
@@ -2181,6 +2377,7 @@ send_it:
2181 2377
 					"\n", c, ip_addr2a(&c->rcv.dst_ip), c->rcv.dst_port,
2182 2378
 					su2a(&c->rcv.src_su, sizeof(c->rcv.src_su)),
2183 2379
 					strerror(errno), errno);
2380
+		n = -1;
2184 2381
 #ifdef TCP_ASYNC
2185 2382
 error:
2186 2383
 #endif /* TCP_ASYNC */
... ...
@@ -2188,27 +2385,7 @@ error:
2188 2385
 		c->state=S_CONN_BAD;
2189 2386
 		c->timeout=get_ticks_raw();
2190 2387
 		/* tell "main" it should drop this (optional it will t/o anyway?)*/
2191
-		response[0]=(long)c;
2192
-		response[1]=CONN_ERROR;
2193
-		if (send_all(unix_tcp_sock, response, sizeof(response))<=0){
2194
-			LOG(L_CRIT, "BUG: tcp_send: error return failed (write):%s (%d)\n",
2195
-					strerror(errno), errno);
2196
-			tcpconn_chld_put(c); /* deref. it manually */
2197
-			n=-1;
2198
-		}
2199
-		/* CONN_ERROR will auto-dec refcnt => we must not call tcpconn_put 
2200
-		 * if it succeeds */
2201
-#ifdef TCP_FD_CACHE
2202
-		if (unlikely(fd_cache_e)){
2203
-			LOG(L_ERR, "ERROR: tcp_send %s: error on cached fd, removing from"
2204
-					" the cache (%d, %p, %d)\n", 
2205
-					su2a(&c->rcv.src_su, sizeof(c->rcv.src_su)),
2206
-					fd, fd_cache_e->con, fd_cache_e->id);
2207
-			tcp_fd_cache_rm(fd_cache_e);
2208
-			close(fd);
2209
-		}else
2210
-#endif /* TCP_FD_CACHE */
2211
-		if (do_close_fd) close(fd);
2388
+		*resp=CONN_ERROR;
2212 2389
 		return n; /* error return, no tcpconn_put */
2213 2390
 	}
2214 2391
 	
... ...
@@ -2220,70 +2397,16 @@ error:
2220 2397
 			TCP_STATS_ESTABLISHED(c->state);
2221 2398
 			c->state=S_CONN_OK;
2222 2399
 	}
2223
-	if (unlikely(dst->send_flags.f & SND_F_CON_CLOSE)){
2400
+	if (unlikely(send_flags.f & SND_F_CON_CLOSE)){
2224 2401
 		/* close after write => send EOF request to tcp_main */
2225 2402
 		c->state=S_CONN_BAD;
2226 2403
 		c->timeout=get_ticks_raw();
2227 2404
 		/* tell "main" it should drop this*/
2228
-		response[0]=(long)c;
2229
-		response[1]=CONN_EOF;
2230
-		if (send_all(unix_tcp_sock, response, sizeof(response))<=0){
2231
-			LOG(L_CRIT, "BUG: tcp_send: error return failed (write):%s (%d)\n",
2232
-					strerror(errno), errno);
2233
-			tcpconn_chld_put(c); /* deref. it manually */
2234
-			n=-1;
2235
-		}
2236
-		/* CONN_EOF will auto-dec refcnt => we must not call tcpconn_put 
2237
-		 * if it succeeds */
2238
-#ifdef TCP_FD_CACHE
2239
-		if (unlikely(fd_cache_e)){
2240
-			tcp_fd_cache_rm(fd_cache_e);
2241
-			fd_cache_e=0;
2242
-			close(fd);
2243
-		}else
2244
-#endif /* TCP_FD_CACHE */
2245
-		if (do_close_fd) close(fd);
2246
-		goto end_no_conn;
2405
+		*resp=CONN_EOF;
2406
+		return n;
2247 2407
 	}
2248 2408
 end:
2249
-#ifdef TCP_FD_CACHE
2250
-	if (unlikely((fd_cache_e==0) && use_fd_cache)){
2251
-		tcp_fd_cache_add(c, fd);
2252
-	}else
2253
-#endif /* TCP_FD_CACHE */
2254
-	if (do_close_fd) close(fd);
2255
-release_c:
2256
-	tcpconn_chld_put(c); /* release c (dec refcnt & free on 0) */
2257
-end_no_conn:
2258 2409
 	return n;
2259
-#ifdef TCP_CONNECT_WAIT
2260
-conn_wait_error:
2261
-	n=-1;
2262
-conn_wait_close:
2263
-	/* connect or send failed or immediate close-after-send was requested on
2264
-	 * newly created connection which was not yet sent to tcp_main (but was
2265
-	 * already hashed) => don't send to main, unhash and destroy directly
2266
-	 * (if refcnt>2 it will be destroyed when the last sender releases the
2267
-	 * connection (tcpconn_chld_put(c))) or when tcp_main receives a
2268
-	 * CONN_ERROR it*/
2269
-	c->state=S_CONN_BAD;
2270
-	/* we are here only if we opened a new fd (and not reused a cached or
2271
-	   a reader one) => if the connect was successful close the fd */
2272
-	if (fd>=0) close(fd);
2273
-	TCPCONN_LOCK;
2274
-		if (c->flags & F_CONN_HASHED){
2275
-			/* if some other parallel tcp_send did send CONN_ERROR to
2276
-			 * tcp_main, the connection might be already detached */
2277
-			_tcpconn_detach(c);
2278
-			c->flags&=~F_CONN_HASHED;
2279
-			TCPCONN_UNLOCK;
2280
-			tcpconn_put(c);
2281
-		}else
2282
-			TCPCONN_UNLOCK;
2283
-	/* dec refcnt -> mark it for destruction */
2284
-	tcpconn_chld_put(c);
2285
-	return n;
2286
-#endif /* TCP_CONNET_WAIT */
2287 2410
 }
2288 2411
 
2289 2412
 
... ...
@@ -2525,7 +2648,7 @@ inline static void tcpconn_destroy(struct tcp_connection* tcpconn)
2525 2648
  */
2526 2649
 inline static int tcpconn_put_destroy(struct tcp_connection* tcpconn)
2527 2650
 {
2528
-	if (unlikely((tcpconn->flags & 
2651
+	if (unlikely((tcpconn->flags &
2529 2652
 			(F_CONN_WRITE_W|F_CONN_HASHED|F_CONN_MAIN_TIMER|F_CONN_READ_W)) )){
2530 2653
 		/* sanity check */
2531 2654
 		if (unlikely(tcpconn->flags & F_CONN_HASHED)){
... ...
@@ -3158,10 +3281,17 @@ inline static int handle_ser_child(struct process_table* p, int fd_i)
3158 3281
 			/* received only if the wr. queue is empty and a write finishes
3159 3282
 			 * with EAGAIN (common after connect())
3160 3283
 			 * it should only enable write watching on the fd. The connection
3161
-			 * should be  already in the hash. The refcnt is not changed.
3284
+			 * should be  already in the hash. The refcnt is automatically
3285
+			 * decremented.
3162 3286
 			 */
3163
-			if (unlikely((tcpconn->state==S_CONN_BAD) || 
3287
+			/* auto-dec refcnt */
3288
+			if (unlikely(tcpconn_put(tcpconn))){
3289
+				tcpconn_destroy(tcpconn);
3290
+				break;
3291
+			}
3292
+			if (unlikely((tcpconn->state==S_CONN_BAD) ||
3164 3293
 							!(tcpconn->flags & F_CONN_HASHED) ))
3294
+				/* in the process of being destroyed => do nothing */
3165 3295
 				break;
3166 3296
 			if (!(tcpconn->flags & F_CONN_WANTS_WR)){
3167 3297
 				tcpconn->flags|=F_CONN_WANTS_WR;