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.
This commit is contained in:
Oswald Buddenhagen 2011-03-27 16:50:32 +02:00
parent f1df2f40d1
commit 802c99edcf
3 changed files with 30 additions and 14 deletions

View File

@ -236,7 +236,7 @@ v_submit_imap_cmd( imap_store_t *ctx, struct imap_cmd *cmd,
while (ctx->literal_pending) while (ctx->literal_pending)
if (get_cmd_result( ctx, 0 ) == RESP_CANCEL) if (get_cmd_result( ctx, 0 ) == RESP_CANCEL)
goto bail2; goto bail;
cmd->tag = ++ctx->nexttag; cmd->tag = ++ctx->nexttag;
if (fmt) if (fmt)
@ -279,8 +279,6 @@ v_submit_imap_cmd( imap_store_t *ctx, struct imap_cmd *cmd,
return cmd; return cmd;
bail: bail:
imap_invoke_bad_callback( ctx );
bail2:
done_imap_cmd( ctx, cmd, RESP_CANCEL ); done_imap_cmd( ctx, cmd, RESP_CANCEL );
return NULL; return NULL;
} }
@ -811,7 +809,7 @@ get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd )
for (;;) { for (;;) {
if (!(cmd = socket_read_line( &ctx->conn ))) { if (!(cmd = socket_read_line( &ctx->conn ))) {
if (socket_fill( &ctx->conn ) < 0) if (socket_fill( &ctx->conn ) < 0)
break; return RESP_CANCEL;
continue; continue;
} }
@ -854,7 +852,7 @@ get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd )
break; /* stream is likely to be useless now */ break; /* stream is likely to be useless now */
if (resp == LIST_PARTIAL) { if (resp == LIST_PARTIAL) {
if (socket_fill( &ctx->conn ) < 0) if (socket_fill( &ctx->conn ) < 0)
break; return RESP_CANCEL;
goto do_fetch; goto do_fetch;
} }
if (parse_fetch( ctx, ctx->parse_list_sts.head ) < 0) 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; p = cmdp->param.data;
cmdp->param.data = 0; cmdp->param.data = 0;
if (socket_write( &ctx->conn, p, cmdp->param.data_len, GiveOwn ) < 0) if (socket_write( &ctx->conn, p, cmdp->param.data_len, GiveOwn ) < 0)
break; return RESP_CANCEL;
} else if (cmdp->param.cont) { } else if (cmdp->param.cont) {
if (cmdp->param.cont( ctx, cmdp, cmd )) if (cmdp->param.cont( ctx, cmdp, cmd ))
break; return RESP_CANCEL;
} else { } else {
error( "IMAP error: unexpected command continuation request\n" ); error( "IMAP error: unexpected command continuation request\n" );
break; break;
} }
if (socket_write( &ctx->conn, "\r\n", 2, KeepOwn ) < 0) if (socket_write( &ctx->conn, "\r\n", 2, KeepOwn ) < 0)
break; return RESP_CANCEL;
if (!cmdp->param.cont) if (!cmdp->param.cont)
ctx->literal_pending = 0; ctx->literal_pending = 0;
if (!tcmd) if (!tcmd)
@ -1128,13 +1126,14 @@ imap_open_store( store_conf_t *conf,
ctx = nfcalloc( sizeof(*ctx) ); ctx = nfcalloc( sizeof(*ctx) );
ctx->gen.conf = conf; ctx->gen.conf = conf;
ctx->conn.fd = -1;
ctx->ref_count = 1; ctx->ref_count = 1;
ctx->callbacks.imap_open = cb; ctx->callbacks.imap_open = cb;
ctx->callback_aux = aux; ctx->callback_aux = aux;
set_bad_callback( &ctx->gen, (void (*)(void *))imap_open_store_bail, ctx ); set_bad_callback( &ctx->gen, (void (*)(void *))imap_open_store_bail, ctx );
ctx->in_progress_append = &ctx->in_progress; 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 )) if (!socket_connect( &srvc->sconf, &ctx->conn ))
goto bail; goto bail;

View File

@ -79,6 +79,9 @@ typedef struct {
SSL *ssl; SSL *ssl;
#endif #endif
void (*bad_callback)( void *aux ); /* async fail while sending or listening */
void *callback_aux;
int offset; /* start of filled bytes in buffer */ int offset; /* start of filled bytes in buffer */
int bytes; /* number 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' */ int scanoff; /* offset to continue scanning for newline at, relative to 'offset' */
@ -330,6 +333,15 @@ extern const char *Home;
/* socket.c */ /* 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_connect( const server_conf_t *conf, conn_t *sock );
int socket_start_tls( 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 ); void socket_close( conn_t *sock );

View File

@ -48,6 +48,12 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#include <netdb.h> #include <netdb.h>
static void
socket_fail( conn_t *conn )
{
conn->bad_callback( conn->callback_aux );
}
static void static void
socket_perror( const char *func, conn_t *sock, int ret ) 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) ); error( "SSL_%s: %s\n", func, strerror(errno) );
} else } else
error( "SSL_%s: %s\n", func, ERR_error_string( err, 0 ) ); error( "SSL_%s: %s\n", func, ERR_error_string( err, 0 ) );
return; break;
default: default:
error( "SSL_%s: unhandled SSL error %d\n", func, err ); error( "SSL_%s: unhandled SSL error %d\n", func, err );
break; break;
} }
return; } else
}
#else
(void)sock;
#endif #endif
if (ret < 0) if (ret < 0)
perror( func ); perror( func );
else else
error( "%s: unexpected EOF\n", func ); error( "%s: unexpected EOF\n", func );
socket_fail( sock );
} }
#ifdef HAVE_LIBSSL #ifdef HAVE_LIBSSL
@ -361,6 +365,7 @@ socket_fill( conn_t *sock )
int len = sizeof(sock->buf) - n; int len = sizeof(sock->buf) - n;
if (!len) { if (!len) {
error( "Socket error: receive buffer full. Probably protocol error.\n" ); error( "Socket error: receive buffer full. Probably protocol error.\n" );
socket_fail( sock );
return -1; return -1;
} }
assert( sock->fd >= 0 ); assert( sock->fd >= 0 );