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 1728
 					char* buf, unsigned len)
1729 1729
 {
1730 1730
 	struct tcp_connection *c;
1731
-	struct tcp_connection *tmp;
1732 1731
 	struct ip_addr ip;
1733 1732
 	int port;
1734 1733
 	int fd;
... ...
@@ -1736,16 +1740,7 @@ int tcp_send(struct dest_info* dst, union sockaddr_union* from,
1736 1736
 	int n;
1737 1737
 	int do_close_fd;
1738 1738
 	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 1739
 	
1746
-	use_fd_cache=cfg_get(tcp, tcp_cfg, fd_cache);
1747
-	fd_cache_e=0;
1748
-#endif /* TCP_FD_CACHE */
1749 1740
 	do_close_fd=1; /* close the fd on exit */
1750 1741
 	port=su_getport(&dst->to);
1751 1742
 	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 1890
 							goto conn_wait_error;
1891 1891
 						}
1892 1892
 						n=len;
1893
-						goto end;
1893
+						goto conn_wait_success;
1894 1894
 					}
1895 1895
 					/* if first write failed it's most likely a
1896 1896
 					   connect error */
... ...
@@ -1945,7 +1940,7 @@ int tcp_send(struct dest_info* dst, union sockaddr_union* from,
1945 1945
 								c, strerror(errno), errno);
1946 1946
 					goto conn_wait_error;
1947 1947
 				}
1948
-				goto end;
1948
+				goto conn_wait_success;
1949 1949
 			}
1950 1950
 #endif /* TCP_CONNECT_WAIT  && TCP_ASYNC */
1951 1951
 			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 1977
 				n=-1;
1978 1978
 				goto end_no_conn;
1979 1979
 			}
1980
-			goto send_it;
1980
+			/* new connection => send on it directly */
1981
+			n = tcpconn_do_send(fd, c, buf, len, dst->send_flags,
1982
+									&response[1]);
1983
+			if (unlikely(response[1] != CONN_NOP)) {
1984
+				response[0]=(long)c;
1985
+				if (send_all(unix_tcp_sock, response, sizeof(response)) <= 0) {
1986
+					BUG("tcp_main command %ld sending failed (write):"
1987
+							"%s (%d)\n", response[1], strerror(errno), errno);
1988
+					/* all commands != CONN_NOP returned by tcpconn_do_send()
1989
+					   (CONN_EOF, CONN_ERROR, CONN_QUEUED_WRITE) will auto-dec
1990
+					   refcnt => if sending the command fails we have to
1991
+					   dec. refcnt by hand */
1992
+					tcpconn_chld_put(c); /* deref. it manually */
1993
+					n=-1;
1994
+				}
1995
+				/* here refcnt for c is already decremented => c contents can
1996
+				   no longer be used and refcnt _must_ _not_ be decremented
1997
+				   again on exit */
1998
+				if (unlikely(n < 0 || response[1] == CONN_EOF)) {
1999
+					/* on error or eof, close fd */
2000
+					close(fd);
2001
+				} else if (response[1] == CONN_QUEUED_WRITE) {
2002
+#ifdef TCP_FD_CACHE
2003
+					if (cfg_get(tcp, tcp_cfg, fd_cache)) {
2004
+						tcp_fd_cache_add(c, fd);
2005
+					} else
2006
+#endif /* TCP_FD_CACHE */
2007
+						close(fd);
2008
+				} else {
2009
+					BUG("unexpected tcpconn_do_send() return & response:"
2010
+							" %d, %ld\n", n, response[1]);
2011
+				}
2012
+				goto end_no_deref;
2013
+			}
2014
+#ifdef TCP_FD_CACHE
2015
+			if (cfg_get(tcp, tcp_cfg, fd_cache)) {
2016
+				tcp_fd_cache_add(c, fd);
2017
+			}else
2018
+#endif /* TCP_FD_CACHE */
2019
+				close(fd);
2020
+		/* here we can have only commands that _do_ _not_ dec refcnt.
2021
+		   (CONN_EOF, CON_ERROR, CON_QUEUED_WRITE are all treated above) */
2022
+			goto release_c;
1981 2023
 		}
1982 2024
 /* get_fd: */
2025
+	/* existing connection, send on it */
2026
+	n = tcpconn_send_put(c, buf, len, dst->send_flags);
2027
+	/* no deref needed (automatically done inside tcpconn_send_put() */
2028
+	return n;
2029
+#ifdef TCP_CONNECT_WAIT
2030
+conn_wait_success:
2031
+#ifdef TCP_FD_CACHE
2032
+	if (cfg_get(tcp, tcp_cfg, fd_cache)) {
2033
+		tcp_fd_cache_add(c, fd);
2034
+	} else
2035
+#endif /* TCP_FD_CACHE */
2036
+		close(fd);
2037
+	tcpconn_chld_put(c); /* release c (dec refcnt & free on 0) */
2038
+	return n;
2039
+conn_wait_error:
2040
+	n=-1;
2041
+conn_wait_close:
2042
+	/* connect or send failed or immediate close-after-send was requested on
2043
+	 * newly created connection which was not yet sent to tcp_main (but was
2044
+	 * already hashed) => don't send to main, unhash and destroy directly
2045
+	 * (if refcnt>2 it will be destroyed when the last sender releases the
2046
+	 * connection (tcpconn_chld_put(c))) or when tcp_main receives a
2047
+	 * CONN_ERROR it*/
2048
+	c->state=S_CONN_BAD;
2049
+	/* we are here only if we opened a new fd (and not reused a cached or
2050
+	   a reader one) => if the connect was successful close the fd */
2051
+	if (fd>=0) close(fd);
2052
+	TCPCONN_LOCK;
2053
+		if (c->flags & F_CONN_HASHED){
2054
+			/* if some other parallel tcp_send did send CONN_ERROR to
2055
+			 * tcp_main, the connection might be already detached */
2056
+			_tcpconn_detach(c);
2057
+			c->flags&=~F_CONN_HASHED;
2058
+			TCPCONN_UNLOCK;
2059
+			tcpconn_put(c);
2060
+		}else
2061
+			TCPCONN_UNLOCK;
2062
+	/* dec refcnt -> mark it for destruction */
2063
+	tcpconn_chld_put(c);
2064
+	return n;
2065
+#endif /* TCP_CONNET_WAIT */
2066
+release_c:
2067
+	tcpconn_chld_put(c); /* release c (dec refcnt & free on 0) */
2068
+end_no_deref:
2069
+end_no_conn:
2070
+	return n;
2071
+}
2072
+
2073
+
2074
+
2075
+/** sends on an existing tcpconn.
2076
+ * As opposed to tcp_send(), this function requires an existing
2077
+ * tcp connection.
2078
+ * WARNING: the tcp_connection will be de-referenced.
2079
+ * @param c - existing tcp connection pointer.
2080
+ * @param buf - data to be sent.
2081
+ * @param len - data length,
2082
+ * @return >=0 on success, -1 on error.
2083
+ */
2084
+static int tcpconn_send_put(struct tcp_connection* c, char* buf, unsigned len,
2085
+							snd_flags_t send_flags)
2086
+{
2087
+	struct tcp_connection *tmp;
2088
+	int fd;
2089
+	long response[2];
2090
+	int n;
2091
+	int do_close_fd;
2092
+#ifdef TCP_FD_CACHE
2093
+	struct fd_cache_entry* fd_cache_e;
2094
+	int use_fd_cache;
2095
+	
2096
+	use_fd_cache=cfg_get(tcp, tcp_cfg, fd_cache);
2097
+	fd_cache_e=0;
2098
+#endif /* TCP_FD_CACHE */
2099
+	do_close_fd=1; /* close the fd on exit */
2100
+	response[1] = CONN_NOP;
1983 2101
 #ifdef TCP_ASYNC
1984
-		/* if data is already queued, we don't need the fd any more */
2102
+	/* if data is already queued, we don't need the fd */
1985 2103
 #ifdef TCP_CONNECT_WAIT
1986 2104
 		if (unlikely(cfg_get(tcp, tcp_cfg, async) &&
1987 2105
 						(_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 2000
 					if (unlikely(_wbufq_add(c, buf, len)<0)){
2001 2001
 						lock_release(&c->write_lock);
2002 2002
 						n=-1;
2003
+						response[1] = CONN_ERROR;
2004
+						c->state=S_CONN_BAD;
2005
+						c->timeout=get_ticks_raw(); /* force timeout */
2003 2006
 						goto error;
2004 2007
 					}
2005 2008
 					n=len;
... ...
@@ -2057,17 +2173,105 @@ int tcp_send(struct dest_info* dst, union sockaddr_union* from,
2057 2057
 						  tmp, n
2058 2058
 				   );
2059 2059
 				n=-1; /* fail */
2060
+				/* don't cache fd & close it */
2061
+				do_close_fd = 1;
2062
+#ifdef TCP_FD_CACHE
2063
+				use_fd_cache = 0;
2064
+#endif /* TCP_FD_CACHE */
2060 2065
 				goto end;
2061 2066
 			}
2062 2067
 			DBG("tcp_send: after receive_fd: c= %p n=%d fd=%d\n",c, n, fd);
2063 2068
 		}
2064 2069
 	
2065
-	
2066
-send_it:
2070
+	n = tcpconn_do_send(fd, c, buf, len, send_flags, &response[1]);
2071
+	if (unlikely(response[1] != CONN_NOP)) {
2072
+error:
2073
+		response[0]=(long)c;
2074
+		if (send_all(unix_tcp_sock, response, sizeof(response)) <= 0) {
2075
+			BUG("tcp_main command %ld sending failed (write):%s (%d)\n",
2076
+					response[1], strerror(errno), errno);
2077
+			/* all commands != CONN_NOP returned by tcpconn_do_send()
2078
+			   (CONN_EOF, CONN_ERROR, CONN_QUEUED_WRITE) will auto-dec refcnt
2079
+			   => if sending the command fails we have to dec. refcnt by hand
2080
+			 */
2081
+			tcpconn_chld_put(c); /* deref. it manually */
2082
+			n=-1;
2083
+		}
2084
+		/* here refcnt for c is already decremented => c contents can no
2085
+		   longer be used and refcnt _must_ _not_ be decremented again
2086
+		   on exit */
2087
+		if (unlikely(n < 0 || response[1] == CONN_EOF)) {
2088
+			/* on error or eof, remove from cache or close fd */
2089
+#ifdef TCP_FD_CACHE
2090
+			if (unlikely(fd_cache_e)){
2091
+				tcp_fd_cache_rm(fd_cache_e);
2092
+				fd_cache_e = 0;
2093
+				close(fd);
2094
+			}else
2095
+#endif /* TCP_FD_CACHE */
2096
+				if (do_close_fd) close(fd);
2097
+		} else if (response[1] == CONN_QUEUED_WRITE) {
2098
+#ifdef TCP_FD_CACHE
2099
+			if (unlikely((fd_cache_e==0) && use_fd_cache)){
2100
+				tcp_fd_cache_add(c, fd);
2101
+			}else
2102
+#endif /* TCP_FD_CACHE */
2103
+				if (do_close_fd) close(fd);
2104
+		} else {
2105
+			BUG("unexpected tcpconn_do_send() return & response: %d, %ld\n",
2106
+					n, response[1]);
2107
+		}
2108
+		return n; /* no tcpconn_put */
2109
+	}
2110
+end:
2111
+#ifdef TCP_FD_CACHE
2112
+	if (unlikely((fd_cache_e==0) && use_fd_cache)){
2113
+		tcp_fd_cache_add(c, fd);
2114
+	}else
2115
+#endif /* TCP_FD_CACHE */
2116
+	if (do_close_fd) close(fd);
2117
+	/* here we can have only commands that _do_ _not_ dec refcnt.
2118
+	   (CONN_EOF, CON_ERROR, CON_QUEUED_WRITE are all treated above) */
2119
+release_c:
2120
+	tcpconn_chld_put(c); /* release c (dec refcnt & free on 0) */
2121
+	return n;
2122
+}
2123
+
2124
+
2125
+
2126
+/** lower level send (connection and fd should be known).
2127
+ * It takes care of possible write-queueing, blacklisting a.s.o.
2128
+ * It expects a valid tcp connection. It doesn't touch the ref. cnts.
2129
+ * @param c - existing tcp connection pointer (state and flags might be
2130
+ *            changed).
2131
+ * @param buf - data to be sent.
2132
+ * @param len - data length.
2133
+ * @param send_flags
2134
+ * @param resp - filled with a cmd. for tcp_main:
2135
+ *                      CONN_NOP - nothing needs to be done (do not send
2136
+ *                                 anything to tcp_main).
2137
+ *                      CONN_ERROR - error, connection should be closed.
2138
+ *                      CONN_EOF - no error, but connection should be closed.
2139
+ *                      CONN_QUEUED_WRITE - new write queue (connection
2140
+ *                                 should be watched for write and the wr.
2141
+ *                                 queue flushed).
2142
+ * @return >=0 on success, < 0 on error && *resp == CON_ERROR.
2143
+ *
2144
+ */
2145
+static int tcpconn_do_send(int fd, struct tcp_connection* c,
2146
+							char* buf, unsigned len,
2147
+							snd_flags_t send_flags, long* resp)
2148
+{
2149
+	int  n;
2150
+#ifdef TCP_ASYNC
2151
+	int enable_write_watch;
2152
+#endif /* TCP_ASYNC */
2153
+
2067 2154
 	DBG("tcp_send: sending...\n");
2155
+	*resp = CONN_NOP;
2068 2156
 	lock_get(&c->write_lock);
2069 2157
 	/* update connection send flags with the current ones */
2070
-	tcpconn_set_send_flags(c, dst->send_flags);
2158
+	tcpconn_set_send_flags(c, send_flags);
2071 2159
 #ifdef TCP_ASYNC
2072 2160
 	if (likely(cfg_get(tcp, tcp_cfg, async))){
2073 2161
 		if (_wbufq_non_empty(c)
... ...
@@ -2088,14 +2292,14 @@ send_it:
2088 2088
 	}else{
2089 2089
 #endif /* TCP_ASYNC */
2090 2090
 #ifdef USE_TLS
2091
-	if (c->type==PROTO_TLS)
2092
-		n=tls_blocking_write(c, fd, buf, len);
2093
-	else
2091
+		if (c->type==PROTO_TLS)
2092
+			n=tls_blocking_write(c, fd, buf, len);
2093
+		else
2094 2094
 #endif
2095 2095
 		/* 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);
2096
+			n=tsend_stream(fd, buf, len,
2097
+							TICKS_TO_S(cfg_get(tcp, tcp_cfg, send_timeout)) *
2098
+							1000);
2099 2099
 #ifdef TCP_ASYNC
2100 2100
 	}
2101 2101
 #else /* ! TCP_ASYNC */
... ...
@@ -2122,16 +2326,8 @@ send_it:
2122 2122
 			}
2123 2123
 			lock_release(&c->write_lock);
2124 2124
 			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
-			}
2125
+			if (likely(enable_write_watch))
2126
+				*resp=CONN_QUEUED_WRITE;
2135 2127
 			goto end;
2136 2128
 		}else{
2137 2129
 			lock_release(&c->write_lock);
... ...
@@ -2181,6 +2377,7 @@ send_it:
2181 2181
 					"\n", c, ip_addr2a(&c->rcv.dst_ip), c->rcv.dst_port,
2182 2182
 					su2a(&c->rcv.src_su, sizeof(c->rcv.src_su)),
2183 2183
 					strerror(errno), errno);
2184
+		n = -1;
2184 2185
 #ifdef TCP_ASYNC
2185 2186
 error:
2186 2187
 #endif /* TCP_ASYNC */
... ...
@@ -2188,27 +2385,7 @@ error:
2188 2188
 		c->state=S_CONN_BAD;
2189 2189
 		c->timeout=get_ticks_raw();
2190 2190
 		/* 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);
2191
+		*resp=CONN_ERROR;
2212 2192
 		return n; /* error return, no tcpconn_put */
2213 2193
 	}
2214 2194
 	
... ...
@@ -2220,70 +2397,16 @@ error:
2220 2220
 			TCP_STATS_ESTABLISHED(c->state);
2221 2221
 			c->state=S_CONN_OK;
2222 2222
 	}
2223
-	if (unlikely(dst->send_flags.f & SND_F_CON_CLOSE)){
2223
+	if (unlikely(send_flags.f & SND_F_CON_CLOSE)){
2224 2224
 		/* close after write => send EOF request to tcp_main */
2225 2225
 		c->state=S_CONN_BAD;
2226 2226
 		c->timeout=get_ticks_raw();
2227 2227
 		/* 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;
2228
+		*resp=CONN_EOF;
2229
+		return n;
2247 2230
 	}
2248 2231
 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 2232
 	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 2233
 }
2288 2234
 
2289 2235
 
... ...
@@ -2525,7 +2648,7 @@ inline static void tcpconn_destroy(struct tcp_connection* tcpconn)
2525 2525
  */
2526 2526
 inline static int tcpconn_put_destroy(struct tcp_connection* tcpconn)
2527 2527
 {
2528
-	if (unlikely((tcpconn->flags & 
2528
+	if (unlikely((tcpconn->flags &
2529 2529
 			(F_CONN_WRITE_W|F_CONN_HASHED|F_CONN_MAIN_TIMER|F_CONN_READ_W)) )){
2530 2530
 		/* sanity check */
2531 2531
 		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 3158
 			/* received only if the wr. queue is empty and a write finishes
3159 3159
 			 * with EAGAIN (common after connect())
3160 3160
 			 * it should only enable write watching on the fd. The connection
3161
-			 * should be  already in the hash. The refcnt is not changed.
3161
+			 * should be  already in the hash. The refcnt is automatically
3162
+			 * decremented.
3162 3163
 			 */
3163
-			if (unlikely((tcpconn->state==S_CONN_BAD) || 
3164
+			/* auto-dec refcnt */
3165
+			if (unlikely(tcpconn_put(tcpconn))){
3166
+				tcpconn_destroy(tcpconn);
3167
+				break;
3168
+			}
3169
+			if (unlikely((tcpconn->state==S_CONN_BAD) ||
3164 3170
 							!(tcpconn->flags & F_CONN_HASHED) ))
3171
+				/* in the process of being destroyed => do nothing */
3165 3172
 				break;
3166 3173
 			if (!(tcpconn->flags & F_CONN_WANTS_WR)){
3167 3174
 				tcpconn->flags|=F_CONN_WANTS_WR;