dovecot-2.2: lib: Added istream-callback API

dovecot at dovecot.org dovecot at dovecot.org
Mon Aug 11 14:45:32 UTC 2014


details:   http://hg.dovecot.org/dovecot-2.2/rev/1b76af8a8ded
changeset: 17701:1b76af8a8ded
user:      Timo Sirainen <tss at iki.fi>
date:      Mon Aug 11 17:43:25 2014 +0300
description:
lib: Added istream-callback API

diffstat:

 src/lib/Makefile.am        |    2 +
 src/lib/istream-callback.c |  107 +++++++++++++++++++++++++++++++++++++++++++++
 src/lib/istream-callback.h |   35 ++++++++++++++
 3 files changed, 144 insertions(+), 0 deletions(-)

diffs (169 lines):

diff -r 2ce864f0176a -r 1b76af8a8ded src/lib/Makefile.am
--- a/src/lib/Makefile.am	Mon Aug 11 16:08:44 2014 +0300
+++ b/src/lib/Makefile.am	Mon Aug 11 17:43:25 2014 +0300
@@ -58,6 +58,7 @@
 	istream.c \
 	istream-base64-decoder.c \
 	istream-base64-encoder.c \
+	istream-callback.c \
 	istream-chain.c \
 	istream-concat.c \
 	istream-crlf.c \
@@ -191,6 +192,7 @@
 	iso8601-date.h \
 	istream.h \
 	istream-base64.h \
+	istream-callback.h \
 	istream-chain.h \
 	istream-concat.h \
 	istream-crlf.h \
diff -r 2ce864f0176a -r 1b76af8a8ded src/lib/istream-callback.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/istream-callback.c	Mon Aug 11 17:43:25 2014 +0300
@@ -0,0 +1,107 @@
+/* Copyright (c) 2014 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "buffer.h"
+#include "istream-private.h"
+#include "istream-callback.h"
+
+struct callback_istream {
+	struct istream_private istream;
+	istream_callback_read_t *callback;
+	void *context;
+
+	buffer_t *buf;
+	size_t pending_size;
+};
+
+static void i_stream_callback_destroy(struct iostream_private *stream)
+{
+	struct callback_istream *cstream = (struct callback_istream *)stream;
+
+	buffer_free(&cstream->buf);
+}
+
+static ssize_t i_stream_callback_read(struct istream_private *stream)
+{
+	struct callback_istream *cstream = (struct callback_istream *)stream;
+	size_t pos;
+
+	if (cstream->callback == NULL) {
+		/* already returned EOF / error */
+		stream->istream.eof = TRUE;
+		return -1;
+	}
+
+	if (stream->skip > 0) {
+		buffer_delete(cstream->buf, 0, stream->skip);
+		stream->pos -= stream->skip;
+		stream->skip = 0;
+	}
+	pos = cstream->buf->used;
+	if (cstream->pending_size > 0) {
+		i_assert(pos >= cstream->pending_size);
+		pos -= cstream->pending_size;
+		cstream->pending_size = 0;
+	} else if (!cstream->callback(cstream->buf, cstream->context)) {
+		/* EOF / error */
+		stream->istream.eof = TRUE;
+		cstream->callback = NULL;
+		if (cstream->buf->used == pos ||
+		    stream->istream.stream_errno != 0)
+			return -1;
+		/* EOF was returned with some data still added to the buffer.
+		   return the buffer first and EOF only on the next call. */
+	} else if (cstream->buf->used == pos) {
+		/* buffer full */
+		i_assert(cstream->buf->used > 0);
+		return -2;
+	}
+	i_assert(cstream->buf->used > pos);
+	stream->buffer = cstream->buf->data;
+	stream->pos = cstream->buf->used;
+	return cstream->buf->used - pos;
+}
+
+#undef i_stream_create_callback
+struct istream *
+i_stream_create_callback(istream_callback_read_t *callback, void *context)
+{
+	struct callback_istream *cstream;
+	struct istream *istream;
+
+	i_assert(callback != NULL);
+
+	cstream = i_new(struct callback_istream, 1);
+	cstream->callback = callback;
+	cstream->context = context;
+	cstream->buf = buffer_create_dynamic(default_pool, 1024);
+
+	cstream->istream.iostream.destroy = i_stream_callback_destroy;
+	cstream->istream.read = i_stream_callback_read;
+
+	istream = i_stream_create(&cstream->istream, NULL, -1);
+	istream->blocking = TRUE;
+	return istream;
+}
+
+void i_stream_callback_append(struct istream *input,
+			      const void *data, size_t size)
+{
+	struct callback_istream *cstream =
+		(struct callback_istream *)input->real_stream;
+
+	buffer_append(cstream->buf, data, size);
+	cstream->pending_size += size;
+}
+
+void i_stream_callback_append_str(struct istream *input, const char *str)
+{
+	i_stream_callback_append(input, str, strlen(str));
+}
+
+void i_stream_callback_set_error(struct istream *input, int stream_errno,
+				 const char *error)
+{
+	input->stream_errno = stream_errno;
+	io_stream_set_error(&input->real_stream->iostream, "%s", error);
+}
diff -r 2ce864f0176a -r 1b76af8a8ded src/lib/istream-callback.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/istream-callback.h	Mon Aug 11 17:43:25 2014 +0300
@@ -0,0 +1,35 @@
+#ifndef ISTREAM_CALLBACK_H
+#define ISTREAM_CALLBACK_H
+
+/* istream-callback can be used to implement an istream that returns data
+   by calling the specified callback. The callback needs to do:
+
+   a) Add data to buffer unless the buffer size is already too large
+   (the callback can decide by itself what is too large). Return TRUE
+   regardless of whether any data was added.
+
+   b) Return FALSE when it's finished adding data or when it reaches an error.
+   On error i_stream_callback_set_error() must be called before returning.
+
+   i_stream_add_destroy_callback() can be also added to do any cleanups that
+   the callback may need to do.
+*/
+typedef bool istream_callback_read_t(buffer_t *buf, void *context);
+
+struct istream *
+i_stream_create_callback(istream_callback_read_t *callback, void *context);
+#define i_stream_create_callback(callback, context) \
+	i_stream_create_callback(1 ? (istream_callback_read_t *)callback : \
+		CALLBACK_TYPECHECK(callback, bool (*)(buffer_t *buf, typeof(context))), \
+		context)
+
+/* Append data to the istream externally. Typically this is used to add a
+   header to the stream before the callbacks are called. */
+void i_stream_callback_append(struct istream *input,
+			      const void *data, size_t size);
+void i_stream_callback_append_str(struct istream *input, const char *str);
+
+void i_stream_callback_set_error(struct istream *input, int stream_errno,
+				 const char *error);
+
+#endif


More information about the dovecot-cvs mailing list