/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "istream.h"
#include "ostream.h"
#include "iostream-private.h"
static void
io_stream_default_close(struct iostream_private *stream ATTR_UNUSED,
bool close_parent ATTR_UNUSED)
{
}
static void
io_stream_default_destroy(struct iostream_private *stream ATTR_UNUSED)
{
}
void io_stream_init(struct iostream_private *stream)
{
if (stream->close == NULL)
stream->close = io_stream_default_close;
if (stream->destroy == NULL)
stream->destroy = io_stream_default_destroy;
stream->ioloop = current_ioloop;
stream->refcount = 1;
}
void io_stream_ref(struct iostream_private *stream)
{
i_assert(stream->refcount > 0);
stream->refcount++;
}
bool io_stream_unref(struct iostream_private *stream)
{
i_assert(stream->refcount > 0);
if (--stream->refcount != 0)
return TRUE;
stream->close(stream, FALSE);
stream->destroy(stream);
return FALSE;
}
void io_stream_free(struct iostream_private *stream)
{
const struct iostream_destroy_callback *dc;
if (array_is_created(&stream->destroy_callbacks)) {
array_foreach(&stream->destroy_callbacks, dc)
dc->callback(dc->context);
array_free(&stream->destroy_callbacks);
}
i_free(stream->error);
i_free(stream->name);
i_free(stream);
}
void io_stream_close(struct iostream_private *stream, bool close_parent)
{
stream->close(stream, close_parent);
}
void io_stream_set_max_buffer_size(struct iostream_private *stream,
size_t max_size)
{
stream->set_max_buffer_size(stream, max_size);
}
void io_stream_add_destroy_callback(struct iostream_private *stream,
void (*callback)(void *), void *context)
{
struct iostream_destroy_callback *dc;
if (!array_is_created(&stream->destroy_callbacks))
i_array_init(&stream->destroy_callbacks, 2);
dc = array_append_space(&stream->destroy_callbacks);
dc->callback = callback;
dc->context = context;
}
void io_stream_remove_destroy_callback(struct iostream_private *stream,
void (*callback)(void *))
{
const struct iostream_destroy_callback *dcs;
unsigned int i, count;
dcs = array_get(&stream->destroy_callbacks, &count);
for (i = 0; i < count; i++) {
if (dcs[i].callback == callback) {
array_delete(&stream->destroy_callbacks, i, 1);
return;
}
}
i_unreached();
}
void io_stream_set_error(struct iostream_private *stream,
const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
io_stream_set_verror(stream, fmt, args);
va_end(args);
}
void io_stream_set_verror(struct iostream_private *stream,
const char *fmt, va_list args)
{
/* one of the parameters may be the old stream->error, so don't free
it before the new error is created. */
char *error = i_strdup_vprintf(fmt, args);
i_free(stream->error);
stream->error = error;
}
const char *io_stream_get_disconnect_reason(struct istream *input,
struct ostream *output)
{
const char *errstr;
if (input != NULL && input->stream_errno != 0) {
errno = input->stream_errno;
errstr = i_stream_get_error(input);
} else if (output != NULL && output->stream_errno != 0) {
errno = output->stream_errno;
errstr = o_stream_get_error(output);
} else {
errno = 0;
errstr = "";
}
if (errno == 0 || errno == EPIPE)
return "Connection closed";
else
return t_strdup_printf("Connection closed: %s", errstr);
}
void io_stream_switch_ioloop_to(struct iostream_private *stream,
struct ioloop *ioloop)
{
stream->ioloop = ioloop;
}
struct ioloop *io_stream_get_ioloop(struct iostream_private *stream)
{
return (stream->ioloop == NULL ? current_ioloop : stream->ioloop);
}