commit 96b1e52802a0e9c7c3206f683734e5a744b0cd7a
parent 6f15980cd96722609c3f4b933f07cc21e5dcb0f8
Author: Oswald Buddenhagen <ossi@users.sf.net>
Date: Fri, 26 Nov 2021 11:39:55 +0100
make socket_read()'s interface more like socket_read_line()'s
return a pointer into the internal buffer rather than copying into a
user-supplied one. this permits zero-copy in future use cases.
Diffstat:
3 files changed, 32 insertions(+), 18 deletions(-)
diff --git a/src/drv_imap.c b/src/drv_imap.c
@@ -824,7 +824,8 @@ parse_imap_list( imap_store_t *ctx, char **sp, parse_list_state_t *sts )
{
list_t *cur, **curp;
char *s = *sp, *d, *p;
- int n, bytes;
+ int bytes;
+ uint n;
char c;
assert( sts );
@@ -882,12 +883,14 @@ parse_imap_list( imap_store_t *ctx, char **sp, parse_list_state_t *sts )
s[cur->len] = 0;
getbytes:
- n = socket_read( &ctx->conn, s, (uint)bytes );
- if (n < 0) {
+ if (!(p = socket_read( &ctx->conn, 1, (uint)bytes, &n )))
+ goto postpone;
+ if (p == (void *)~0) {
badeof:
sts->err = "unexpected EOF";
goto bail;
}
+ memcpy( s, p, n );
bytes -= n;
if (bytes > 0)
goto postpone;
diff --git a/src/socket.c b/src/socket.c
@@ -799,20 +799,30 @@ socket_expect_eof( conn_t *sock )
#endif
}
-int
-socket_read( conn_t *conn, char *buf, uint len )
+char *
+socket_read( conn_t *conn, uint min_len, uint max_len, uint *out_len )
{
- uint n = conn->bytes;
- if (!n && conn->state == SCK_EOF)
- return -1;
- if (n > len)
- n = len;
- memcpy( buf, conn->buf + conn->offset, n );
- if (!(conn->bytes -= n))
- conn->offset = 0;
- else
- conn->offset += n;
- return (int)n;
+ assert( min_len > 0 );
+ assert( min_len <= sizeof(conn->buf) );
+ assert( min_len <= max_len );
+
+ uint off = conn->offset;
+ uint cnt = conn->bytes;
+ if (cnt < min_len) {
+ if (conn->state == SCK_EOF)
+ return (void *)~0;
+ if (off + min_len > sizeof(conn->buf)) {
+ memmove( conn->buf, conn->buf + off, cnt );
+ conn->offset = 0;
+ }
+ return NULL;
+ }
+ uint n = (cnt < max_len) ? cnt : max_len;
+ cnt -= n;
+ conn->offset = cnt ? off + n : 0;
+ conn->bytes = cnt;
+ *out_len = n;
+ return conn->buf + off;
}
char *
diff --git a/src/socket.h b/src/socket.h
@@ -128,8 +128,9 @@ void socket_start_deflate( conn_t *conn );
void socket_close( conn_t *sock );
void socket_expect_activity( conn_t *sock, int expect );
void socket_expect_eof( conn_t *sock );
-int socket_read( conn_t *sock, char *buf, uint len ); /* never waits */
-char *socket_read_line( conn_t *sock ); /* don't free return value; never waits */
+// Don't free return values. These functions never wait.
+char *socket_read( conn_t *conn, uint min_len, uint max_len, uint *out_len );
+char *socket_read_line( conn_t *conn );
typedef enum { KeepOwn = 0, GiveOwn } ownership_t;
typedef struct {
char *buf;