isync

mailbox synchronization program
git clone https://git.code.sf.net/p/isync/isync
Log | Files | Refs | README | LICENSE

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:
Msrc/drv_imap.c | 9++++++---
Msrc/socket.c | 36+++++++++++++++++++++++-------------
Msrc/socket.h | 5+++--
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;