From 802c99edcf04c9aafcfd0459ccc3e13e5522ec38 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Sun, 27 Mar 2011 16:50:32 +0200 Subject: [PATCH] make socket read/write error reporting callback-based the functions still have synchronous return codes as well - this enables early error returns without having to resort to refcounting. --- src/drv_imap.c | 17 ++++++++--------- src/isync.h | 12 ++++++++++++ src/socket.c | 15 ++++++++++----- 3 files changed, 30 insertions(+), 14 deletions(-) diff --git a/src/drv_imap.c b/src/drv_imap.c index 71c432f..64e0e44 100644 --- a/src/drv_imap.c +++ b/src/drv_imap.c @@ -236,7 +236,7 @@ v_submit_imap_cmd( imap_store_t *ctx, struct imap_cmd *cmd, while (ctx->literal_pending) if (get_cmd_result( ctx, 0 ) == RESP_CANCEL) - goto bail2; + goto bail; cmd->tag = ++ctx->nexttag; if (fmt) @@ -279,8 +279,6 @@ v_submit_imap_cmd( imap_store_t *ctx, struct imap_cmd *cmd, return cmd; bail: - imap_invoke_bad_callback( ctx ); - bail2: done_imap_cmd( ctx, cmd, RESP_CANCEL ); return NULL; } @@ -811,7 +809,7 @@ get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd ) for (;;) { if (!(cmd = socket_read_line( &ctx->conn ))) { if (socket_fill( &ctx->conn ) < 0) - break; + return RESP_CANCEL; continue; } @@ -854,7 +852,7 @@ get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd ) break; /* stream is likely to be useless now */ if (resp == LIST_PARTIAL) { if (socket_fill( &ctx->conn ) < 0) - break; + return RESP_CANCEL; goto do_fetch; } if (parse_fetch( ctx, ctx->parse_list_sts.head ) < 0) @@ -882,16 +880,16 @@ get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd ) p = cmdp->param.data; cmdp->param.data = 0; if (socket_write( &ctx->conn, p, cmdp->param.data_len, GiveOwn ) < 0) - break; + return RESP_CANCEL; } else if (cmdp->param.cont) { if (cmdp->param.cont( ctx, cmdp, cmd )) - break; + return RESP_CANCEL; } else { error( "IMAP error: unexpected command continuation request\n" ); break; } if (socket_write( &ctx->conn, "\r\n", 2, KeepOwn ) < 0) - break; + return RESP_CANCEL; if (!cmdp->param.cont) ctx->literal_pending = 0; if (!tcmd) @@ -1128,13 +1126,14 @@ imap_open_store( store_conf_t *conf, ctx = nfcalloc( sizeof(*ctx) ); ctx->gen.conf = conf; - ctx->conn.fd = -1; ctx->ref_count = 1; ctx->callbacks.imap_open = cb; ctx->callback_aux = aux; set_bad_callback( &ctx->gen, (void (*)(void *))imap_open_store_bail, ctx ); ctx->in_progress_append = &ctx->in_progress; + socket_init( &ctx->conn, (void (*)( void * ))imap_invoke_bad_callback, ctx ); + if (!socket_connect( &srvc->sconf, &ctx->conn )) goto bail; diff --git a/src/isync.h b/src/isync.h index 7de6f33..ff27ed3 100644 --- a/src/isync.h +++ b/src/isync.h @@ -79,6 +79,9 @@ typedef struct { SSL *ssl; #endif + void (*bad_callback)( void *aux ); /* async fail while sending or listening */ + void *callback_aux; + int offset; /* start of filled bytes in buffer */ int bytes; /* number of filled bytes in buffer */ int scanoff; /* offset to continue scanning for newline at, relative to 'offset' */ @@ -330,6 +333,15 @@ extern const char *Home; /* socket.c */ +/* call this before doing anything with the socket */ +static INLINE void socket_init( conn_t *conn, + void (*bad_callback)( void *aux ), + void *aux ) +{ + conn->bad_callback = bad_callback; + conn->callback_aux = aux; + conn->fd = -1; +} int socket_connect( const server_conf_t *conf, conn_t *sock ); int socket_start_tls( const server_conf_t *conf, conn_t *sock ); void socket_close( conn_t *sock ); diff --git a/src/socket.c b/src/socket.c index 076c075..7d0d24e 100644 --- a/src/socket.c +++ b/src/socket.c @@ -48,6 +48,12 @@ #include #include +static void +socket_fail( conn_t *conn ) +{ + conn->bad_callback( conn->callback_aux ); +} + static void socket_perror( const char *func, conn_t *sock, int ret ) { @@ -65,20 +71,18 @@ socket_perror( const char *func, conn_t *sock, int ret ) error( "SSL_%s: %s\n", func, strerror(errno) ); } else error( "SSL_%s: %s\n", func, ERR_error_string( err, 0 ) ); - return; + break; default: error( "SSL_%s: unhandled SSL error %d\n", func, err ); break; } - return; - } -#else - (void)sock; + } else #endif if (ret < 0) perror( func ); else error( "%s: unexpected EOF\n", func ); + socket_fail( sock ); } #ifdef HAVE_LIBSSL @@ -361,6 +365,7 @@ socket_fill( conn_t *sock ) int len = sizeof(sock->buf) - n; if (!len) { error( "Socket error: receive buffer full. Probably protocol error.\n" ); + socket_fail( sock ); return -1; } assert( sock->fd >= 0 );