Jelajahi Sumber

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.
Oswald Buddenhagen 14 tahun lalu
induk
melakukan
802c99edcf
3 mengubah file dengan 30 tambahan dan 14 penghapusan
  1. 8 9
      src/drv_imap.c
  2. 12 0
      src/isync.h
  3. 10 5
      src/socket.c

+ 8 - 9
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;
 

+ 12 - 0
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 );

+ 10 - 5
src/socket.c

@@ -48,6 +48,12 @@
 #include <arpa/inet.h>
 #include <netdb.h>
 
+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 );