<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>