Welcome! Log In Create A New Profile

Advanced

Re: [PATCH 1 of 3] Stream: socket peek in preread phase

Sergey Kandaurov
December 12, 2023 08:18AM
> On 10 Nov 2023, at 14:07, Roman Arutyunyan <arut@nginx.com> wrote:
>
> # HG changeset patch
> # User Roman Arutyunyan <arut@nginx.com>
> # Date 1699456644 -14400
> # Wed Nov 08 19:17:24 2023 +0400
> # Node ID 966331bb4936888ef2f034aa2700c130514d0b57
> # Parent 7ec761f0365f418511e30b82e9adf80bc56681df
> Stream: socket peek in preread phase.
>
> Previously, preread buffer was always read out from socket, which made it
> impossible to terminate SSL on the connection without introducing additional
> SSL BIOs. The following patches will rely on this.
>
> Now, when possible, recv(MSG_PEEK) is used instead, which keeps data in socket.
> It's called if SSL is not already terminated and if an egde-triggered event
> method is used. For epoll, EPOLLRDHUP support is also required.

Not sure if it is a good way to introduce new functionality
that depends on connection processing methods.

>
> diff --git a/src/stream/ngx_stream_core_module.c b/src/stream/ngx_stream_core_module.c
> --- a/src/stream/ngx_stream_core_module.c
> +++ b/src/stream/ngx_stream_core_module.c
> @@ -10,6 +10,10 @@
> #include <ngx_stream.h>
>
>
> +static ngx_int_t ngx_stream_preread_peek(ngx_stream_session_t *s,
> + ngx_stream_phase_handler_t *ph);
> +static ngx_int_t ngx_stream_preread(ngx_stream_session_t *s,
> + ngx_stream_phase_handler_t *ph);
> static ngx_int_t ngx_stream_core_preconfiguration(ngx_conf_t *cf);
> static void *ngx_stream_core_create_main_conf(ngx_conf_t *cf);
> static char *ngx_stream_core_init_main_conf(ngx_conf_t *cf, void *conf);
> @@ -203,8 +207,6 @@ ngx_int_t
> ngx_stream_core_preread_phase(ngx_stream_session_t *s,
> ngx_stream_phase_handler_t *ph)
> {
> - size_t size;
> - ssize_t n;
> ngx_int_t rc;
> ngx_connection_t *c;
> ngx_stream_core_srv_conf_t *cscf;
> @@ -217,56 +219,40 @@ ngx_stream_core_preread_phase(ngx_stream
>
> if (c->read->timedout) {
> rc = NGX_STREAM_OK;
> + goto done;
> + }
>
> - } else if (c->read->timer_set) {
> - rc = NGX_AGAIN;
> + if (!c->read->timer_set) {
> + rc = ph->handler(s);
>
> - } else {
> - rc = ph->handler(s);
> + if (rc != NGX_AGAIN) {
> + goto done;
> + }
> }
>
> - while (rc == NGX_AGAIN) {
> -
> + if (c->buffer == NULL) {
> + c->buffer = ngx_create_temp_buf(c->pool, cscf->preread_buffer_size);
> if (c->buffer == NULL) {
> - c->buffer = ngx_create_temp_buf(c->pool, cscf->preread_buffer_size);
> - if (c->buffer == NULL) {
> - rc = NGX_ERROR;
> - break;
> - }
> + rc = NGX_ERROR;
> + goto done;
> }
> -
> - size = c->buffer->end - c->buffer->last;
> -
> - if (size == 0) {
> - ngx_log_error(NGX_LOG_ERR, c->log, 0, "preread buffer full");
> - rc = NGX_STREAM_BAD_REQUEST;
> - break;
> - }
> + }
>
> - if (c->read->eof) {
> - rc = NGX_STREAM_OK;
> - break;
> - }
> -
> - if (!c->read->ready) {
> - break;
> - }
> -
> - n = c->recv(c, c->buffer->last, size);
> + if (c->ssl == NULL
> + && (ngx_event_flags & NGX_USE_CLEAR_EVENT)
> + && ((ngx_event_flags & NGX_USE_EPOLL_EVENT) == 0
> +#if (NGX_HAVE_EPOLLRDHUP)
> + || ngx_use_epoll_rdhup
> +#endif
> + ))
> + {
> + rc = ngx_stream_preread_peek(s, ph);
>
> - if (n == NGX_ERROR || n == 0) {
> - rc = NGX_STREAM_OK;
> - break;
> - }
> + } else {
> + rc = ngx_stream_preread(s, ph);
> + }
>
> - if (n == NGX_AGAIN) {
> - break;
> - }
> -
> - c->buffer->last += n;
> -
> - rc = ph->handler(s);
> - }
> +done:
>
> if (rc == NGX_AGAIN) {
> if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
> @@ -311,6 +297,95 @@ ngx_stream_core_preread_phase(ngx_stream
> }
>
>
> +static ngx_int_t
> +ngx_stream_preread_peek(ngx_stream_session_t *s, ngx_stream_phase_handler_t *ph)
> +{
> + ssize_t n;
> + ngx_int_t rc;
> + ngx_err_t err;
> + ngx_connection_t *c;
> +
> + c = s->connection;
> +
> + n = recv(c->fd, (char *) c->buffer->last,
> + c->buffer->end - c->buffer->last, MSG_PEEK);
> +
> + err = ngx_socket_errno;
> +
> + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,

typo: NGX_LOG_DEBUG_STREAM

> + "stream recv(MSG_PEEK): %z", n);

Nitpicking: I couldn't find precedence to log "MSG_PEEK", e.g.:

src/mail/ngx_mail_handler.c: n = recv(c->fd, (char *) buf, sizeof(buf), MSG_PEEK);
src/mail/ngx_mail_handler.c-
src/mail/ngx_mail_handler.c- err = ngx_socket_errno;
src/mail/ngx_mail_handler.c-
src/mail/ngx_mail_handler.c- ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, "recv(): %z", n);
src/mail/ngx_mail_handler.c-
--
src/stream/ngx_stream_handler.c: n = recv(c->fd, (char *) buf, sizeof(buf), MSG_PEEK);
src/stream/ngx_stream_handler.c-
src/stream/ngx_stream_handler.c- err = ngx_socket_errno;
src/stream/ngx_stream_handler.c-
src/stream/ngx_stream_handler.c- ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, "recv(): %z", n);
src/stream/ngx_stream_handler.c-

Might be "stream recv(): %z" or just "recv(): %z" is enough.

> +
> + if (n == -1) {
> + if (err == NGX_EAGAIN) {

You don't reset c->read->ready, which introduces a bad pattern.

> + return NGX_AGAIN;
> + }
> +
> + ngx_connection_error(c, err, "recv() failed");
> + return NGX_STREAM_OK;
> + }
> +
> + if (n == 0) {
> + return NGX_STREAM_OK;
> + }
> +
> + c->buffer->last += n;
> +
> + rc = ph->handler(s);
> +
> + if (rc == NGX_AGAIN && c->buffer->last == c->buffer->end) {
> + ngx_log_error(NGX_LOG_ERR, c->log, 0, "preread buffer full");
> + return NGX_STREAM_BAD_REQUEST;
> + }
> +
> + if (rc == NGX_AGAIN && c->read->pending_eof) {
> + return NGX_STREAM_OK;
> + }
> +
> + c->buffer->last = c->buffer->pos;
> +
> + return rc;
> +}

Don't you want to make ngx_stream_preread_peek() more similar to
ngx_stream_preread() ? Something like this:

rc = ph->handler(s);

if (rc != NGX_AGAIN) {
c->buffer->last = c->buffer->pos;
return rc;
}

if (c->buffer->last == c->buffer->end) {
ngx_log_error(NGX_LOG_ERR, c->log, 0, "preread buffer full");
return NGX_STREAM_BAD_REQUEST;
}

if (c->read->pending_eof) {
return NGX_STREAM_OK;
}

c->buffer->last = c->buffer->pos;

return NGX_AGAIN;


> +
> +
> +static ngx_int_t
> +ngx_stream_preread(ngx_stream_session_t *s, ngx_stream_phase_handler_t *ph)
> +{
> + ssize_t n;
> + ngx_int_t rc;
> + ngx_connection_t *c;
> +
> + c = s->connection;
> +
> + while (c->read->ready) {
> +
> + n = c->recv(c, c->buffer->last, c->buffer->end - c->buffer->last);
> +
> + if (n == NGX_AGAIN) {
> + return NGX_AGAIN;
> + }
> +
> + if (n == NGX_ERROR || n == 0) {
> + return NGX_STREAM_OK;
> + }
> +
> + c->buffer->last += n;
> +
> + rc = ph->handler(s);
> +
> + if (rc != NGX_AGAIN) {
> + return rc;
> + }
> +
> + if (c->buffer->last == c->buffer->end) {
> + ngx_log_error(NGX_LOG_ERR, c->log, 0, "preread buffer full");
> + return NGX_STREAM_BAD_REQUEST;
> + }
> + }
> +
> + return NGX_AGAIN;
> +}
> +
> +
> ngx_int_t
> ngx_stream_core_content_phase(ngx_stream_session_t *s,
> ngx_stream_phase_handler_t *ph)
> _______________________________________________
> nginx-devel mailing list
> nginx-devel@nginx.org
> https://mailman.nginx.org/mailman/listinfo/nginx-devel

--
Sergey Kandaurov
_______________________________________________
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel
Subject Author Views Posted

[PATCH 0 of 3] Stream connection handling updates

Roman Arutyunyan 805 November 10, 2023 05:08AM

[PATCH 1 of 3] Stream: socket peek in preread phase

Roman Arutyunyan 144 November 10, 2023 05:08AM

Re: [PATCH 1 of 3] Stream: socket peek in preread phase

Sergey Kandaurov 123 December 12, 2023 08:18AM

Re: [PATCH 1 of 3] Stream: socket peek in preread phase

Roman Arutyunyan 139 December 13, 2023 09:08AM

Re: [PATCH 1 of 3] Stream: socket peek in preread phase

Sergey Kandaurov 138 December 13, 2023 10:52AM

Re: [PATCH 1 of 3] Stream: socket peek in preread phase

Sergey Kandaurov 124 December 27, 2023 09:36AM

Re: [PATCH 1 of 3] Stream: socket peek in preread phase

Roman Arutyunyan 124 January 04, 2024 11:04AM

Re: [PATCH 1 of 3] Stream: socket peek in preread phase

Sergey Kandaurov 133 January 18, 2024 08:44AM

Re: [PATCH 1 of 3] Stream: socket peek in preread phase

Roman Arutyunyan 117 January 18, 2024 10:08AM

Re: [PATCH 1 of 3] Stream: socket peek in preread phase

Sergey Kandaurov 106 January 18, 2024 11:16AM

Re: [PATCH 1 of 3] Stream: socket peek in preread phase

Maxim Dounin 135 January 18, 2024 02:46PM

Re: [PATCH 1 of 3] Stream: socket peek in preread phase

Sergey Kandaurov 111 January 19, 2024 06:44AM

Re: [PATCH 1 of 3] Stream: socket peek in preread phase

Maxim Dounin 131 January 19, 2024 03:28PM

[PATCH 2 of 3] Stream: virtual servers

Roman Arutyunyan 194 November 10, 2023 05:08AM

Re: [PATCH 2 of 3] Stream: virtual servers

Sergey Kandaurov 162 December 13, 2023 08:42AM

Re: [PATCH 2 of 3] Stream: virtual servers

Sergey Kandaurov 142 December 14, 2023 12:36PM

[PATCH 0 of 6] Re: [PATCH 2 of 3] Stream: virtual servers

Sergey Kandaurov 142 December 15, 2023 10:40AM

[PATCH 1 of 6] Stream: using ngx_stream_ssl_srv_conf_t *sscf naming convention

Sergey Kandaurov 160 December 15, 2023 10:40AM

Re: [PATCH 1 of 6] Stream: using ngx_stream_ssl_srv_conf_t *sscf naming convention

Roman Arutyunyan 135 January 08, 2024 08:32AM

[PATCH 2 of 6] Overhauled some diagnostic messages missed in 1b05b9bbcebf

Sergey Kandaurov 127 December 15, 2023 10:40AM

Re: [PATCH 2 of 6] Overhauled some diagnostic messages missed in 1b05b9bbcebf

Roman Arutyunyan 120 January 09, 2024 08:16AM

[PATCH 3 of 6] Stream: reshuffled ngx_stream_listen_opt_t fields

Sergey Kandaurov 148 December 15, 2023 10:40AM

Re: [PATCH 3 of 6] Stream: reshuffled ngx_stream_listen_opt_t fields

Roman Arutyunyan 122 January 09, 2024 08:18AM

[PATCH 4 of 6] Stream: the "deferred" parameter of the "listen" directive

Sergey Kandaurov 130 December 15, 2023 10:40AM

Re: [PATCH 4 of 6] Stream: the "deferred" parameter of the "listen" directive

Roman Arutyunyan 117 January 09, 2024 10:40AM

Re: [PATCH 4 of 6] Stream: the "deferred" parameter of the "listen" directive

Sergey Kandaurov 111 January 18, 2024 09:52AM

Re: [PATCH 4 of 6] Stream: the "deferred" parameter of the "listen" directive

Roman Arutyunyan 115 January 18, 2024 10:26AM

Re: [PATCH 4 of 6] Stream: the "deferred" parameter of the "listen" directive

Sergey Kandaurov 123 January 18, 2024 11:22AM

[PATCH 5 of 6] Stream: the "accept_filter" parameter of the "listen" directive

Sergey Kandaurov 141 December 15, 2023 10:40AM

Re: [PATCH 5 of 6] Stream: the "accept_filter" parameter of the "listen" directive

Roman Arutyunyan 127 January 11, 2024 07:42AM

[PATCH 6 of 6] Stream: the "setfib" parameter of the "listen" directive

Sergey Kandaurov 134 December 15, 2023 10:42AM

Re: [PATCH 6 of 6] Stream: the "setfib" parameter of the "listen" directive

Roman Arutyunyan 146 January 11, 2024 07:46AM

[PATCH 3 of 3] Stream: ngx_stream_pass_module

Roman Arutyunyan 159 November 10, 2023 05:08AM

Re: [PATCH 3 of 3] Stream: ngx_stream_pass_module

Sergey Kandaurov 122 December 13, 2023 10:46AM

Re: [PATCH 3 of 3] Stream: ngx_stream_pass_module

Sergey Kandaurov 154 December 15, 2023 10:48AM

Re: [PATCH 3 of 3] Stream: ngx_stream_pass_module

Sergey Kandaurov 116 February 13, 2024 05:48AM

Re: [PATCH 3 of 3] Stream: ngx_stream_pass_module

Roman Arutyunyan 156 February 21, 2024 08:38AM

Re: [PATCH 3 of 3] Stream: ngx_stream_pass_module

Sergey Kandaurov 116 February 28, 2024 05:18AM

Re: [PATCH 3 of 3] Stream: ngx_stream_pass_module

Roman Arutyunyan 139 February 28, 2024 09:24AM

Re: [PATCH 3 of 3] Stream: ngx_stream_pass_module

Sergey Kandaurov 215 February 29, 2024 06:40AM



Sorry, you do not have permission to post/reply in this forum.

Online Users

Guests: 148
Record Number of Users: 8 on April 13, 2023
Record Number of Guests: 500 on July 15, 2024
Powered by nginx      Powered by FreeBSD      PHP Powered      Powered by MariaDB      ipv6 ready