<div dir="ltr"><div style>Hi,</div><div style><br></div><div style>Could you please take a look at patch below.</div><div style>I've tried to fix problem that TCP_CORK option is not cleaned in SPDY case.</div><div><br>
</div><div># HG changeset patch</div><div># User <a href="mailto:ykirpichev@gmail.com">ykirpichev@gmail.com</a></div><div># Date 1370939502 -14400</div><div># Branch nopush_fix_1</div><div># Node ID 58d7a76b975ed7afb6a980b8810051a10dfc96f4</div>
<div># Parent 725fb71ab1a60bd48b0afb8b001b5349f5054cb1</div><div>Fix tcp_nopush cleanup for spdy</div><div><br></div><div>diff -r 725fb71ab1a6 -r 58d7a76b975e src/http/ngx_http.c</div><div>--- a/src/http/ngx_http.c<span class="" style="white-space:pre"> </span>Fri Jun 07 13:16:00 2013 -0700</div>
<div>+++ b/src/http/ngx_http.c<span class="" style="white-space:pre"> </span>Tue Jun 11 12:31:42 2013 +0400</div><div>@@ -2106,3 +2106,112 @@</div><div> </div><div> return NGX_OK;</div><div> }</div><div>+</div><div>+</div>
<div>+ngx_int_t</div><div>+ngx_http_check_and_set_nopush(ngx_connection_t* c)</div><div>+{</div><div>+ int tcp_nodelay;</div><div>+</div><div>+ /* the TCP_CORK and TCP_NODELAY are mutually exclusive */</div><div>+ if (c->tcp_nodelay == NGX_TCP_NODELAY_SET) {</div>
<div>+</div><div>+ tcp_nodelay = 0;</div><div>+</div><div>+ if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY,</div><div>+ (const void *) &tcp_nodelay, sizeof(int)) == -1)</div><div>
+ {</div><div>+ /*</div><div>+ * there is a tiny chance to be interrupted, however,</div><div>+ * we continue a processing with the TCP_NODELAY</div><div>+ * and without the TCP_CORK</div>
<div>+ */</div><div>+</div><div>+ if (ngx_errno != NGX_EINTR) {</div><div>+ ngx_connection_error(c, ngx_errno,</div><div>+ "setsockopt(TCP_NODELAY) failed");</div>
<div>+ return NGX_ERROR;</div><div>+ }</div><div>+</div><div>+ } else {</div><div>+ c->tcp_nodelay = NGX_TCP_NODELAY_UNSET;</div><div>+</div><div>+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,</div>
<div>+ "no tcp_nodelay");</div><div>+ }</div><div>+ }</div><div>+</div><div>+ if (c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) {</div><div>+</div><div>+ if (ngx_tcp_nopush(c->fd) == NGX_ERROR) {</div>
<div>+</div><div>+ /*</div><div>+ * there is a tiny chance to be interrupted, however,</div><div>+ * we continue a processing without the TCP_CORK</div><div>+ */</div><div>+</div>
<div>+ if (ngx_errno != NGX_EINTR) {</div><div>+ ngx_connection_error(c, ngx_errno,</div><div>+ ngx_tcp_nopush_n " failed");</div><div>+ return NGX_ERROR;</div>
<div>+ }</div><div>+</div><div>+ } else {</div><div>+ c->tcp_nopush = NGX_TCP_NOPUSH_SET;</div><div>+</div><div>+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,</div><div>+ "tcp_nopush");</div>
<div>+ }</div><div>+ }</div><div>+</div><div>+ return NGX_OK;</div><div>+}</div><div>+</div><div>+ngx_int_t</div><div>+ngx_http_check_and_restore_nopush(ngx_connection_t* c,</div><div>+ ngx_http_core_loc_conf_t* clcf)</div>
<div>+{</div><div>+ int tcp_nodelay;</div><div>+</div><div>+ if (c->tcp_nopush == NGX_TCP_NOPUSH_SET) {</div><div>+ if (ngx_tcp_push(c->fd) == -1) {</div><div>+ ngx_connection_error(c, ngx_socket_errno, ngx_tcp_push_n " failed");</div>
<div>+ return NGX_ERROR;</div><div>+ }</div><div>+</div><div>+ c->tcp_nopush = NGX_TCP_NOPUSH_UNSET;</div><div>+ tcp_nodelay = ngx_tcp_nodelay_and_tcp_nopush ? 1 : 0;</div><div>+</div><div>
+ } else {</div><div>+ tcp_nodelay = 1;</div><div>+ }</div><div>+#if 1</div><div>+ if (tcp_nodelay</div><div>+ && clcf->tcp_nodelay</div><div>+ && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET)</div>
<div>+ {</div><div>+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "tcp_nodelay");</div><div>+</div><div>+ if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY,</div><div>+ (const void *) &tcp_nodelay, sizeof(int))</div>
<div>+ == -1)</div><div>+ {</div><div>+#if (NGX_SOLARIS)</div><div>+ /* Solaris returns EINVAL if a socket has been shut down */</div><div>+ c->log_error = NGX_ERROR_IGNORE_EINVAL;</div>
<div>+#endif</div><div>+</div><div>+ ngx_connection_error(c, ngx_socket_errno,</div><div>+ "setsockopt(TCP_NODELAY) failed");</div><div>+</div><div>+ c->log_error = NGX_ERROR_INFO;</div>
<div>+ return NGX_ERROR;</div><div>+ }</div><div>+</div><div>+ c->tcp_nodelay = NGX_TCP_NODELAY_SET;</div><div>+ }</div><div>+#endif</div><div>+</div><div>+ return NGX_OK;</div><div>+}</div>
<div>+</div><div>diff -r 725fb71ab1a6 -r 58d7a76b975e src/http/ngx_http.h</div><div>--- a/src/http/ngx_http.h<span class="" style="white-space:pre"> </span>Fri Jun 07 13:16:00 2013 -0700</div><div>+++ b/src/http/ngx_http.h<span class="" style="white-space:pre"> </span>Tue Jun 11 12:31:42 2013 +0400</div>
<div>@@ -180,5 +180,9 @@</div><div> extern ngx_http_output_header_filter_pt ngx_http_top_header_filter;</div><div> extern ngx_http_output_body_filter_pt ngx_http_top_body_filter;</div><div> </div><div>+ngx_int_t ngx_http_check_and_set_nopush(ngx_connection_t* c); </div>
<div>+</div><div>+ngx_int_t ngx_http_check_and_restore_nopush(ngx_connection_t* c,</div><div>+ ngx_http_core_loc_conf_t* clcf);</div><div> </div><div> #endif /* _NGX_HTTP_H_INCLUDED_ */</div>
<div>diff -r 725fb71ab1a6 -r 58d7a76b975e src/http/ngx_http_request.c</div><div>--- a/src/http/ngx_http_request.c<span class="" style="white-space:pre"> </span>Fri Jun 07 13:16:00 2013 -0700</div><div>+++ b/src/http/ngx_http_request.c<span class="" style="white-space:pre"> </span>Tue Jun 11 12:31:42 2013 +0400</div>
<div>@@ -2740,7 +2740,6 @@</div><div> static void</div><div> ngx_http_set_keepalive(ngx_http_request_t *r)</div><div> {</div><div>- int tcp_nodelay;</div><div> ngx_int_t i;</div>
<div> ngx_buf_t *b, *f;</div><div> ngx_event_t *rev, *wev;</div><div>@@ -2913,44 +2912,9 @@</div><div> </div><div> c->log->action = "keepalive";</div><div> </div><div>
- if (c->tcp_nopush == NGX_TCP_NOPUSH_SET) {</div><div>- if (ngx_tcp_push(c->fd) == -1) {</div><div>- ngx_connection_error(c, ngx_socket_errno, ngx_tcp_push_n " failed");</div><div>- ngx_http_close_connection(c);</div>
<div>- return;</div><div>- }</div><div>-</div><div>- c->tcp_nopush = NGX_TCP_NOPUSH_UNSET;</div><div>- tcp_nodelay = ngx_tcp_nodelay_and_tcp_nopush ? 1 : 0;</div><div>-</div><div>- } else {</div>
<div>- tcp_nodelay = 1;</div><div>- }</div><div>-</div><div>- if (tcp_nodelay</div><div>- && clcf->tcp_nodelay</div><div>- && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET)</div>
<div>- {</div><div>- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "tcp_nodelay");</div><div>-</div><div>- if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY,</div><div>- (const void *) &tcp_nodelay, sizeof(int))</div>
<div>- == -1)</div><div>- {</div><div>-#if (NGX_SOLARIS)</div><div>- /* Solaris returns EINVAL if a socket has been shut down */</div><div>- c->log_error = NGX_ERROR_IGNORE_EINVAL;</div>
<div>-#endif</div><div>-</div><div>- ngx_connection_error(c, ngx_socket_errno,</div><div>- "setsockopt(TCP_NODELAY) failed");</div><div>-</div><div>- c->log_error = NGX_ERROR_INFO;</div>
<div>- ngx_http_close_connection(c);</div><div>- return;</div><div>- }</div><div>-</div><div>- c->tcp_nodelay = NGX_TCP_NODELAY_SET;</div><div>+ if (ngx_http_check_and_restore_nopush(c, clcf) != NGX_OK) {</div>
<div>+ ngx_http_close_connection(c);</div><div>+ return;</div><div> }</div><div> </div><div> #if 0</div><div>diff -r 725fb71ab1a6 -r 58d7a76b975e src/http/ngx_http_spdy.c</div><div>--- a/src/http/ngx_http_spdy.c<span class="" style="white-space:pre"> </span>Fri Jun 07 13:16:00 2013 -0700</div>
<div>+++ b/src/http/ngx_http_spdy.c<span class="" style="white-space:pre"> </span>Tue Jun 11 12:31:42 2013 +0400</div><div>@@ -450,7 +450,6 @@</div><div> ngx_http_spdy_handle_connection(sc);</div><div> }</div><div> </div>
<div>-</div><div> ngx_int_t</div><div> ngx_http_spdy_send_output_queue(ngx_http_spdy_connection_t *sc)</div><div> {</div><div>@@ -490,6 +489,13 @@</div><div> }</div><div> </div><div> cl = c->send_chain(c, cl, 0);</div>
<div>+ clcf = ngx_http_get_module_loc_conf(sc->http_connection->conf_ctx,</div><div>+ ngx_http_core_module);</div><div>+</div><div>+ if (ngx_http_check_and_restore_nopush(c, clcf) != NGX_OK) {</div>
<div>+ c->error = 1;</div><div>+ return NGX_ERROR;</div><div>+ }</div><div> </div><div> if (cl == NGX_CHAIN_ERROR) {</div><div> c->error = 1;</div><div>@@ -501,8 +507,6 @@</div><div> return NGX_ERROR;</div>
<div> }</div><div> </div><div>- clcf = ngx_http_get_module_loc_conf(sc->http_connection->conf_ctx,</div><div>- ngx_http_core_module);</div><div> </div><div> if (ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) {</div>
<div> return NGX_ERROR; /* FIXME */</div><div>diff -r 725fb71ab1a6 -r 58d7a76b975e src/os/unix/ngx_linux_sendfile_chain.c</div><div>--- a/src/os/unix/ngx_linux_sendfile_chain.c<span class="" style="white-space:pre"> </span>Fri Jun 07 13:16:00 2013 -0700</div>
<div>+++ b/src/os/unix/ngx_linux_sendfile_chain.c<span class="" style="white-space:pre"> </span>Tue Jun 11 12:31:42 2013 +0400</div><div>@@ -33,11 +33,13 @@</div><div> #define NGX_HEADERS IOV_MAX</div><div> #endif</div><div>
</div><div>+ngx_int_t</div><div>+ngx_http_check_and_set_nopush(ngx_connection_t* c);</div><div> </div><div> ngx_chain_t *</div><div> ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)</div><div> {</div>
<div>- int rc, tcp_nodelay;</div><div>+ int rc;</div><div> off_t size, send, prev_send, aligned, sent, fprev;</div><div> u_char *prev;</div><div> size_t file_size;</div>
<div>@@ -154,61 +156,9 @@</div><div> && cl</div><div> && cl->buf->in_file)</div><div> {</div><div>- /* the TCP_CORK and TCP_NODELAY are mutually exclusive */</div>
<div>-</div><div>- if (c->tcp_nodelay == NGX_TCP_NODELAY_SET) {</div><div>-</div><div>- tcp_nodelay = 0;</div><div>-</div><div>- if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY,</div>
<div>- (const void *) &tcp_nodelay, sizeof(int)) == -1)</div><div>- {</div><div>- err = ngx_errno;</div><div>-</div><div>- /*</div><div>
- * there is a tiny chance to be interrupted, however,</div><div>- * we continue a processing with the TCP_NODELAY</div><div>- * and without the TCP_CORK</div><div>
- */</div><div>-</div><div>- if (err != NGX_EINTR) {</div><div>- wev->error = 1;</div><div>- ngx_connection_error(c, err,</div><div>- "setsockopt(TCP_NODELAY) failed");</div>
<div>- return NGX_CHAIN_ERROR;</div><div>- }</div><div>-</div><div>- } else {</div><div>- c->tcp_nodelay = NGX_TCP_NODELAY_UNSET;</div><div>-</div>
<div>- ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,</div><div>- "no tcp_nodelay");</div><div>- }</div><div>- }</div><div>-</div>
<div>- if (c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) {</div><div>-</div><div>- if (ngx_tcp_nopush(c->fd) == NGX_ERROR) {</div><div>- err = ngx_errno;</div><div>-</div><div>
- /*</div><div>- * there is a tiny chance to be interrupted, however,</div><div>- * we continue a processing without the TCP_CORK</div><div>- */</div>
<div>-</div><div>- if (err != NGX_EINTR) {</div><div>- wev->error = 1;</div><div>- ngx_connection_error(c, err,</div><div>- ngx_tcp_nopush_n " failed");</div>
<div>- return NGX_CHAIN_ERROR;</div><div>- }</div><div>-</div><div>- } else {</div><div>- c->tcp_nopush = NGX_TCP_NOPUSH_SET;</div><div>-</div>
<div>- ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,</div><div>- "tcp_nopush");</div><div>- }</div><div>+ if (ngx_http_check_and_set_nopush(c) != NGX_OK) {</div>
<div>+ wev->error = 1;</div><div>+ return NGX_CHAIN_ERROR;</div><div> }</div><div> }</div></div>