changeset 2790:02c0b8d532c2 HEAD

Changed ostream's flush callback to have return value which can tell if there are more bytes to be sent even if there is none in output buffer itself. Fixes FETCH commands which used o_stream_send_istream() getting stuck.
author Timo Sirainen <tss@iki.fi>
date Wed, 20 Oct 2004 20:07:32 +0300
parents c6f128e5520b
children b12e61e55c01
files src/auth/auth-master-connection.c src/imap-login/client.c src/imap/client.c src/lib/ostream-file.c src/lib/ostream-internal.h src/lib/ostream.c src/lib/ostream.h src/login-common/login-proxy.c src/pop3-login/client.c src/pop3/client.c
diffstat 10 files changed, 62 insertions(+), 43 deletions(-) [+]
line wrap: on
line diff
--- a/src/auth/auth-master-connection.c	Wed Oct 20 20:04:27 2004 +0300
+++ b/src/auth/auth-master-connection.c	Wed Oct 20 20:07:32 2004 +0300
@@ -34,7 +34,7 @@
 	struct auth_request *auth_request;
 };
 
-static void master_output(void *context);
+static int master_output(void *context);
 static void auth_master_connection_close(struct auth_master_connection *conn);
 static int auth_master_connection_unref(struct auth_master_connection *conn);
 
@@ -205,7 +205,7 @@
 	}
 }
 
-static void master_output(void *context)
+static int master_output(void *context)
 {
 	struct auth_master_connection *conn = context;
 	int ret;
@@ -213,13 +213,14 @@
 	if ((ret = o_stream_flush(conn->output)) < 0) {
 		/* transmit error, probably master died */
 		auth_master_connection_close(conn);
-		return;
+		return 1;
 	}
 
 	if (o_stream_get_buffer_used_size(conn->output) <= MAX_OUTBUF_SIZE/2) {
 		/* allow input again */
 		conn->io = io_add(conn->fd, IO_READ, master_input, conn);
 	}
+	return 1;
 }
 
 static void
--- a/src/imap-login/client.c	Wed Oct 20 20:04:27 2004 +0300
+++ b/src/imap-login/client.c	Wed Oct 20 20:07:32 2004 +0300
@@ -138,18 +138,19 @@
 	client->io = io_add(client->common.fd, IO_READ, client_input, client);
 }
 
-static void client_output_starttls(void *context)
+static int client_output_starttls(void *context)
 {
 	struct imap_client *client = context;
 	int ret;
 
 	if ((ret = o_stream_flush(client->output)) < 0) {
 		client_destroy(client, "Disconnected");
-		return;
+		return 1;
 	}
 
 	if (ret > 0)
 		client_start_tls(client);
+	return 1;
 }
 
 static int cmd_starttls(struct imap_client *client)
--- a/src/imap/client.c	Wed Oct 20 20:04:27 2004 +0300
+++ b/src/imap/client.c	Wed Oct 20 20:07:32 2004 +0300
@@ -15,7 +15,7 @@
 static struct client *my_client; /* we don't need more than one currently */
 static struct timeout *to_idle;
 
-static void client_output(void *context);
+static int client_output(void *context);
 
 struct client *client_create(int hin, int hout, struct namespace *namespaces)
 {
@@ -375,32 +375,35 @@
 		client_destroy(client);
 }
 
-static void client_output(void *context)
+static int client_output(void *context)
 {
 	struct client *client = context;
-	int finished;
-
-	if (o_stream_flush(client->output) < 0) {
-		client_destroy(client);
-		return;
-	}
+	int ret, finished;
 
 	client->last_output = ioloop_time;
 
-	if (client->command_pending) {
-		o_stream_cork(client->output);
-		finished = client->cmd_func(client) || client->cmd_param_error;
-		o_stream_uncork(client->output);
+	if ((ret = o_stream_flush(client->output)) < 0) {
+		client_destroy(client);
+		return 1;
+	}
+
+	if (!client->command_pending)
+		return 1;
 
-		if (finished) {
-			/* command execution was finished */
-                        client->bad_counter = 0;
-			_client_reset_command(client);
+	/* continue processing command */
+	o_stream_cork(client->output);
+	finished = client->cmd_func(client) || client->cmd_param_error;
+	o_stream_uncork(client->output);
 
-			if (client->input_pending)
-				_client_input(client);
-		}
+	if (finished) {
+		/* command execution was finished */
+		client->bad_counter = 0;
+		_client_reset_command(client);
+
+		if (client->input_pending)
+			_client_input(client);
 	}
+	return finished;
 }
 
 static void idle_timeout(void *context __attr_unused__)
--- a/src/lib/ostream-file.c	Wed Oct 20 20:04:27 2004 +0300
+++ b/src/lib/ostream-file.c	Wed Oct 20 20:07:32 2004 +0300
@@ -332,19 +332,20 @@
 static void stream_send_io(void *context)
 {
 	struct file_ostream *fstream = context;
+	int ret;
 
+	o_stream_ref(&fstream->ostream.ostream);
 	if (fstream->ostream.callback != NULL)
-		fstream->ostream.callback(fstream->ostream.context);
-	else {
-		if (_flush(&fstream->ostream) <= 0)
-			return;
-	}
+		ret = fstream->ostream.callback(fstream->ostream.context);
+	else
+		ret = _flush(&fstream->ostream);
 
-	if (IS_STREAM_EMPTY(fstream) && fstream->io != NULL) {
+	if (ret > 0 && IS_STREAM_EMPTY(fstream) && fstream->io != NULL) {
 		/* all sent */
 		io_remove(fstream->io);
 		fstream->io = NULL;
 	}
+	o_stream_unref(&fstream->ostream.ostream);
 }
 
 static size_t o_stream_add(struct file_ostream *fstream,
--- a/src/lib/ostream-internal.h	Wed Oct 20 20:04:27 2004 +0300
+++ b/src/lib/ostream-internal.h	Wed Oct 20 20:07:32 2004 +0300
@@ -21,7 +21,7 @@
 /* data: */
 	struct ostream ostream;
 
-	io_callback_t *callback;
+	stream_flush_callback_t *callback;
 	void *context;
 };
 
--- a/src/lib/ostream.c	Wed Oct 20 20:04:27 2004 +0300
+++ b/src/lib/ostream.c	Wed Oct 20 20:07:32 2004 +0300
@@ -21,7 +21,8 @@
 }
 
 void o_stream_set_flush_callback(struct ostream *stream,
-				 io_callback_t *callback, void *context)
+				 stream_flush_callback_t *callback,
+				 void *context)
 {
 	struct _ostream *_stream = stream->real_stream;
 
--- a/src/lib/ostream.h	Wed Oct 20 20:04:27 2004 +0300
+++ b/src/lib/ostream.h	Wed Oct 20 20:07:32 2004 +0300
@@ -12,6 +12,11 @@
 	struct _ostream *real_stream;
 };
 
+/* Returns 1 if all data is sent (not necessarily flushed), 0 if not.
+   Pretty much the only real reason to return 0 is if you wish to send more
+   data to client which isn't buffered, eg. o_stream_send_istream(). */
+typedef int stream_flush_callback_t(void *context);
+
 /* Create new output stream from given file descriptor.
    If max_buffer_size is 0, an "optimal" buffer size is used (max 128kB). */
 struct ostream *
@@ -26,9 +31,11 @@
 /* Mark the stream closed. Nothing will be sent after this call. */
 void o_stream_close(struct ostream *stream);
 
-/* Set IO_WRITE callback. Default will just try to flush the output. */
+/* Set IO_WRITE callback. Default will just try to flush the output and
+   finishes when the buffer is empty.  */
 void o_stream_set_flush_callback(struct ostream *stream,
-				 io_callback_t *callback, void *context);
+				 stream_flush_callback_t *callback,
+				 void *context);
 /* Change the maximum size for stream's output buffer to grow. */
 void o_stream_set_max_buffer_size(struct ostream *stream, size_t max_size);
 
--- a/src/login-common/login-proxy.c	Wed Oct 20 20:04:27 2004 +0300
+++ b/src/login-common/login-proxy.c	Wed Oct 20 20:07:32 2004 +0300
@@ -72,13 +72,13 @@
                 login_proxy_free(proxy);
 }
 
-static void proxy_output(void *context)
+static int proxy_output(void *context)
 {
 	struct login_proxy *proxy = context;
 
 	if (o_stream_flush(proxy->proxy_output) < 0) {
                 login_proxy_free(proxy);
-		return;
+		return 1;
 	}
 
 	if (proxy->client_io == NULL &&
@@ -89,15 +89,16 @@
 		proxy->client_io = io_add(proxy->client_fd, IO_READ,
 					  proxy_client_input, proxy);
 	}
+	return 1;
 }
 
-static void proxy_client_output(void *context)
+static int proxy_client_output(void *context)
 {
 	struct login_proxy *proxy = context;
 
 	if (o_stream_flush(proxy->client_output) < 0) {
                 login_proxy_free(proxy);
-		return;
+		return 1;
 	}
 
 	if (proxy->proxy_io == NULL &&
@@ -108,6 +109,7 @@
 		proxy->proxy_io =
 			io_add(proxy->proxy_fd, IO_READ, proxy_input, proxy);
 	}
+	return 1;
 }
 
 static void proxy_prelogin_input(void *context)
--- a/src/pop3-login/client.c	Wed Oct 20 20:04:27 2004 +0300
+++ b/src/pop3-login/client.c	Wed Oct 20 20:07:32 2004 +0300
@@ -92,18 +92,19 @@
 	client->io = io_add(client->common.fd, IO_READ, client_input, client);
 }
 
-static void client_output_starttls(void *context)
+static int client_output_starttls(void *context)
 {
 	struct pop3_client *client = context;
 	int ret;
 
 	if ((ret = o_stream_flush(client->output)) < 0) {
 		client_destroy(client, "Disconnected");
-		return;
+		return 1;
 	}
 
 	if (ret > 0)
 		client_start_tls(client);
+	return 1;
 }
 
 static int cmd_stls(struct pop3_client *client)
--- a/src/pop3/client.c	Wed Oct 20 20:04:27 2004 +0300
+++ b/src/pop3/client.c	Wed Oct 20 20:07:32 2004 +0300
@@ -35,7 +35,7 @@
 static struct timeout *to_idle;
 
 static void client_input(void *context);
-static void client_output(void *context);
+static int client_output(void *context);
 
 static int sync_mailbox(struct mailbox *box)
 {
@@ -325,14 +325,14 @@
 		client_destroy(client);
 }
 
-static void client_output(void *context)
+static int client_output(void *context)
 {
 	struct client *client = context;
 	int ret;
 
 	if ((ret = o_stream_flush(client->output)) < 0) {
 		client_destroy(client);
-		return;
+		return 1;
 	}
 
 	client->last_output = ioloop_time;
@@ -352,6 +352,8 @@
 
 	if (client->cmd == NULL && client->io != NULL && client->waiting_input)
 		client_input(client);
+
+	return client->cmd == NULL;
 }
 
 static void idle_timeout(void *context __attr_unused__)