Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:Ledest:erlang:24
erlang
7891-Avoid-read-ahead-for-packet-mode-ssl_tls.p...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 7891-Avoid-read-ahead-for-packet-mode-ssl_tls.patch of Package erlang
From 6ae17400b5e338eef3862a555e4960ebc31706bd Mon Sep 17 00:00:00 2001 From: Raimo Niskanen <raimo@erlang.org> Date: Tue, 23 Jul 2024 18:45:59 +0200 Subject: [PATCH 1/7] Avoid read-ahead for packet mode ssl_tls --- erts/emulator/drivers/common/inet_drv.c | 175 ++++++++++++++++-------- 1 file changed, 120 insertions(+), 55 deletions(-) diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index f10820653c..ac4bd0a72a 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -12428,6 +12428,24 @@ static int tcp_recv_error(tcp_descriptor* desc, int err) +static int packet_header_length(tcp_descriptor *desc) { + /* XXX RaNi. Here we shall decide whether to read as short as possible, + * or to fill the buffer as much as possible. + * + * Return 0 when we shall read ahead, and > 0 for the amount of byte + * we need to deduce the packet length. + */ + + switch (desc->inet.htype) { + case TCP_PB_SSL_TLS: + /* Return the minimal length to not read ahead */ + return 5; + default: + return 0; /* Read ahead as much as is comfortable */ + } +} + + /* ** Calculate number of bytes that remain to read before deliver ** Assume buf, ptr_start, ptr has been setup @@ -12437,8 +12455,9 @@ static int tcp_recv_error(tcp_descriptor* desc, int err) ** < 0 on error ** ** if return value == 0 then *len will hold the length of the first packet -** return value > 0 then if *len == 0 then value means upperbound -** *len > 0 then value means exact +** return value > 0 then +** if *len == 0 then value means what to read next: upperbound or minimum +** *len > 0 then value means exactly what is missing for a packet ** */ static int tcp_remain(tcp_descriptor* desc, int* len) @@ -12449,7 +12468,7 @@ static int tcp_remain(tcp_descriptor* desc, int* len) int n = desc->i_ptr - ptr; /* number of bytes read */ int tlen; - tlen = packet_get_length(desc->inet.htype, ptr, n, + tlen = packet_get_length(desc->inet.htype, ptr, n, desc->inet.psize, desc->i_bufsz, desc->inet.delimiter, &desc->http_state); @@ -12471,10 +12490,20 @@ static int tcp_remain(tcp_descriptor* desc, int* len) } } else if (tlen == 0) { /* need unknown more */ + int nread; + *len = 0; - if (nsz == 0) { - if (nfill == n) { + nread = packet_header_length(desc); + if (nread != 0) + return nread; + + if (nsz == 0) { /* No remaining space - buffer is full */ + if (nfill == n) { /* The current packet itself fills the buffer */ if (desc->inet.psize != 0 && desc->inet.psize > nfill) { + /* There is a max packet size that is larger than + * the current buffer - expand the buffer + * to max packet size + */ if (tcp_expand_buffer(desc, desc->inet.psize) < 0) return -1; return desc->inet.psize; @@ -12483,12 +12512,17 @@ static int tcp_remain(tcp_descriptor* desc, int* len) goto error; } DEBUGF((" => restart more=%d\r\n", nfill - n)); + /* Return the unused buffer space before desc->i_ptr_start, + * XXX RaNi. Is there a missing copy down here? + * Won't the sock_recv that follows overwrite + * the buffer end...??? + */ return nfill - n; } else { DEBUGF((" => more=%d \r\n", nsz)); - return nsz; - } + return nsz; /* Remaining buffer space */ + } } error: @@ -12513,7 +12547,8 @@ static int tcp_deliver(tcp_descriptor* desc, int len) if ((n = tcp_remain(desc, &len)) != 0) { if (n < 0) /* packet error */ return n; - if (len > 0) /* more data pending */ + /* Packet incomplete */ + if (len > 0) /* This is what is missing */ desc->i_remain = len; return 0; } @@ -12589,8 +12624,9 @@ static int tcp_deliver(tcp_descriptor* desc, int len) static int tcp_recv(tcp_descriptor* desc, int request_len) { - int n; - int len; + /* request_len is 0 unless called from TCP_REQ_RECV, and then + * inet.htype == TCP_PB_RAW and inet.active is INET_PASSIVE (false). + */ int nread; if (desc->i_buf == NULL) { /* allocate a read buffer */ @@ -12604,14 +12640,24 @@ static int tcp_recv(tcp_descriptor* desc, int request_len) desc->i_bufsz = sz; /* use i_bufsz not i_buf->orig_size ! */ desc->i_ptr_start = desc->i_buf->orig_bytes; desc->i_ptr = desc->i_ptr_start; - nread = sz; + if (request_len > 0) { + nread = sz; /* Read ahead */ + desc->i_remain = request_len; + } + else { + nread = packet_header_length(desc); + if (nread == 0) + nread = sz; /* Read ahead */ + desc->i_remain = 0; + } if (request_len > 0) desc->i_remain = request_len; else desc->i_remain = 0; } else if (request_len > 0) { /* we have a data in buffer and a request */ - n = desc->i_ptr - desc->i_ptr_start; + int n = desc->i_ptr - desc->i_ptr_start; + if (n >= request_len) return tcp_deliver(desc, request_len); else if (tcp_expand_buffer(desc, request_len) < 0) @@ -12620,6 +12666,8 @@ static int tcp_recv(tcp_descriptor* desc, int request_len) desc->i_remain = nread = request_len - n; } else if (desc->i_remain == 0) { /* poll remain from buffer data */ + int len; + if ((nread = tcp_remain(desc, &len)) < 0) return tcp_recv_error(desc, EMSGSIZE); else if (nread == 0) @@ -12628,53 +12676,70 @@ static int tcp_recv(tcp_descriptor* desc, int request_len) desc->i_remain = len; /* set remain */ } else /* remain already set use it */ + /* XXX RaNi. I think there is a race here... + * If the packet mode is changed between desc->i_remain is set + * and remaining data is read, then when the packet is delivered; + * packet_parse() is called with the new packet mode (desc->inet.htype) + * which is wrong for that packet. + */ nread = desc->i_remain; - - DEBUGF(("tcp_recv(%p): s=%d about to read %d bytes...\r\n", - desc->inet.port, desc->inet.s, nread)); - n = sock_recv(desc->inet.s, desc->i_ptr, nread, 0); + for (;;) { + int n; - if (IS_SOCKET_ERROR(n)) { - int err = sock_errno(); - if (err == ECONNRESET) { - DEBUGF((" => detected close (connreset)\r\n")); - if (desc->tcp_add_flags & TCP_ADDF_SHOW_ECONNRESET) - return tcp_recv_error(desc, err); - else - return tcp_recv_closed(desc); - } - if (err == ERRNO_BLOCK) { - DEBUGF((" => would block\r\n")); - return 0; - } - else { - DEBUGF((" => error: %d\r\n", err)); - return tcp_recv_error(desc, err); - } - } - else if (n == 0) { - DEBUGF((" => detected close\r\n")); - return tcp_recv_closed(desc); - } + DEBUGF(("tcp_recv(%p): s=%d about to read %d bytes...\r\n", + desc->inet.port, desc->inet.s, nread)); - DEBUGF((" => got %d bytes\r\n", n)); - desc->i_ptr += n; - if (desc->i_remain > 0) { - desc->i_remain -= n; - if (desc->i_remain == 0) - return tcp_deliver(desc, desc->i_ptr - desc->i_ptr_start); - } - else { - nread = tcp_remain(desc, &len); - if (nread < 0) - return tcp_recv_error(desc, EMSGSIZE); - else if (nread == 0) - return tcp_deliver(desc, len); - else if (len > 0) - desc->i_remain = len; /* set remain */ - } - return 0; + n = sock_recv(desc->inet.s, desc->i_ptr, nread, 0); + + if (IS_SOCKET_ERROR(n)) { + int err = sock_errno(); + if (err == ECONNRESET) { + DEBUGF((" => detected close (connreset)\r\n")); + if (desc->tcp_add_flags & TCP_ADDF_SHOW_ECONNRESET) + return tcp_recv_error(desc, err); + else + return tcp_recv_closed(desc); + } + if (err == ERRNO_BLOCK) { + DEBUGF((" => would block\r\n")); + return 0; + } + else { + DEBUGF((" => error: %d\r\n", err)); + return tcp_recv_error(desc, err); + } + } + else if (n == 0) { + DEBUGF((" => detected close\r\n")); + return tcp_recv_closed(desc); + } + ASSERT(nread >= n); + + DEBUGF((" => got %d bytes\r\n", n)); + desc->i_ptr += n; + if (desc->i_remain > 0) { + desc->i_remain -= n; + if (desc->i_remain == 0) + return tcp_deliver(desc, desc->i_ptr - desc->i_ptr_start); + else + /* We just tried to read the whole packet, + * no point in trying again immediately + */ + return 0; + } + else { + int len; + + nread = tcp_remain(desc, &len); + if (nread < 0) + return tcp_recv_error(desc, EMSGSIZE); + else if (nread == 0) + return tcp_deliver(desc, len); + else if (len > 0) /* nread > 0 */ + desc->i_remain = len; /* What is missing for this packet */ + } + } /* for (;;) */ } -- 2.43.0
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor