bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2017-2018 Dovecot authors, see the included COPYING file */
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi#include "lib.h"
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi#include "ioloop.h"
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi#include "array.h"
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi#include "istream-private.h"
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi#include "istream-multiplex.h"
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi/* all multiplex packets are [1 byte cid][4 byte length][data] */
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomistruct multiplex_istream;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomistruct multiplex_ichannel {
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct istream_private istream;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct multiplex_istream *mstream;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi uint8_t cid;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi size_t pending_pos;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi bool closed:1;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi};
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomistruct multiplex_istream {
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct istream *parent;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi /* channel 0 is main channel */
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi uint8_t cur_channel;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi unsigned int remain;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi size_t bufsize;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi ARRAY(struct multiplex_ichannel *) channels;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi bool blocking:1;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi};
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomistatic ssize_t i_stream_multiplex_ichannel_read(struct istream_private *stream);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomistatic struct multiplex_ichannel *
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomiget_channel(struct multiplex_istream *mstream, uint8_t cid)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi{
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct multiplex_ichannel **channelp;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_assert(mstream != NULL);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi array_foreach_modifiable(&mstream->channels, channelp) {
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi if (*channelp != NULL && (*channelp)->cid == cid)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi return *channelp;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi }
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi return NULL;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi}
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomistatic void propagate_error(struct multiplex_istream *mstream, int stream_errno)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi{
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct multiplex_ichannel **channelp;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi array_foreach_modifiable(&mstream->channels, channelp)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi if (*channelp != NULL)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi (*channelp)->istream.istream.stream_errno = stream_errno;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi}
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomistatic void propagate_eof(struct multiplex_istream *mstream)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi{
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct multiplex_ichannel **channelp;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi array_foreach_modifiable(&mstream->channels, channelp) {
45ba3f8b55734aa2c96b6fc510919565ba70038cTimo Sirainen if (*channelp == NULL)
45ba3f8b55734aa2c96b6fc510919565ba70038cTimo Sirainen continue;
45ba3f8b55734aa2c96b6fc510919565ba70038cTimo Sirainen
45ba3f8b55734aa2c96b6fc510919565ba70038cTimo Sirainen (*channelp)->istream.istream.eof = TRUE;
45ba3f8b55734aa2c96b6fc510919565ba70038cTimo Sirainen if (mstream->remain > 0) {
45ba3f8b55734aa2c96b6fc510919565ba70038cTimo Sirainen (*channelp)->istream.istream.stream_errno = EPIPE;
45ba3f8b55734aa2c96b6fc510919565ba70038cTimo Sirainen io_stream_set_error(&(*channelp)->istream.iostream,
45ba3f8b55734aa2c96b6fc510919565ba70038cTimo Sirainen "Unexpected EOF - %u bytes remaining in packet",
45ba3f8b55734aa2c96b6fc510919565ba70038cTimo Sirainen mstream->remain);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi }
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi }
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi}
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomistatic ssize_t
f01fe9df4240c5b15d0b1c4b485a38f7c5736781Timo Siraineni_stream_multiplex_read(struct multiplex_istream *mstream,
f01fe9df4240c5b15d0b1c4b485a38f7c5736781Timo Sirainen struct multiplex_ichannel *req_channel)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi{
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi const unsigned char *data;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi size_t len = 0, used, wanted, avail;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi ssize_t ret, got = 0;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi if (mstream->parent == NULL) {
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi req_channel->istream.istream.eof = TRUE;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi return -1;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi }
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
b78f4649c236bf4746c81c1d0e877675f0842ac8Timo Sirainen (void)i_stream_get_data(mstream->parent, &len);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi if (len == 0 && mstream->parent->closed) {
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi req_channel->istream.istream.eof = TRUE;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi return -1;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi }
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi if (((mstream->remain > 0 && len == 0) ||
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi (mstream->remain == 0 && len < 5)) &&
bcd286622779a93f809b11993db0550f8c7cc9b5Timo Sirainen (ret = i_stream_read_memarea(mstream->parent)) <= 0) {
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi propagate_error(mstream, mstream->parent->stream_errno);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi if (mstream->parent->eof)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi propagate_eof(mstream);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi return ret;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi }
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi for(;;) {
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi data = i_stream_get_data(mstream->parent, &len);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi if (len == 0) {
c50acc5547b9d92784825a09e3de97db0a806f4eTimo Sirainen if (got == 0 && mstream->blocking) {
c50acc5547b9d92784825a09e3de97db0a806f4eTimo Sirainen /* can't return 0 with blocking istreams,
c50acc5547b9d92784825a09e3de97db0a806f4eTimo Sirainen so try again from the beginning. */
f01fe9df4240c5b15d0b1c4b485a38f7c5736781Timo Sirainen return i_stream_multiplex_read(mstream, req_channel);
c50acc5547b9d92784825a09e3de97db0a806f4eTimo Sirainen }
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi break;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi }
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi if (mstream->remain > 0) {
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct multiplex_ichannel *channel =
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi get_channel(mstream, mstream->cur_channel);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi wanted = I_MIN(len, mstream->remain);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi /* is it open? */
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi if (channel != NULL && !channel->closed) {
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct istream_private *stream = &channel->istream;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi stream->pos += channel->pending_pos;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi bool alloc_ret = i_stream_try_alloc(stream, wanted, &avail);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi stream->pos -= channel->pending_pos;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi if (!alloc_ret) {
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_stream_set_input_pending(&stream->istream, TRUE);
f01fe9df4240c5b15d0b1c4b485a38f7c5736781Timo Sirainen if (channel->cid != req_channel->cid)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi return 0;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi if (got > 0)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi break;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi return -2;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi }
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi used = I_MIN(wanted, avail);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi /* dump into buffer */
f01fe9df4240c5b15d0b1c4b485a38f7c5736781Timo Sirainen if (channel->cid != req_channel->cid) {
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_assert(stream->pos + channel->pending_pos + used <= stream->buffer_size);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi memcpy(stream->w_buffer + stream->pos + channel->pending_pos,
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi data, used);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi channel->pending_pos += used;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_stream_set_input_pending(&stream->istream, TRUE);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi } else {
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_assert(stream->pos + used <= stream->buffer_size);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi memcpy(stream->w_buffer + stream->pos, data, used);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi stream->pos += used;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi got += used;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi }
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi } else {
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi used = wanted;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi }
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi mstream->remain -= used;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_stream_skip(mstream->parent, used);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi /* see if there is more to read */
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi continue;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi }
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi if (mstream->remain == 0) {
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi /* need more data */
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi if (len < 5) {
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi ret = i_stream_multiplex_ichannel_read(&req_channel->istream);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi if (ret > 0)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi got += ret;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi break;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi }
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi /* channel ID */
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi mstream->cur_channel = data[0];
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi /* data length */
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi mstream->remain = be32_to_cpu_unaligned(data+1);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_stream_skip(mstream->parent, 5);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi }
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi }
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi propagate_error(mstream, mstream->parent->stream_errno);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi if (mstream->parent->eof)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi propagate_eof(mstream);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi return got;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi}
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomistatic ssize_t i_stream_multiplex_ichannel_read(struct istream_private *stream)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi{
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct multiplex_ichannel *channel = (struct multiplex_ichannel*)stream;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi /* if previous multiplex read dumped data for us
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi actually serve it here. */
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi if (channel->pending_pos > 0) {
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi ssize_t ret = channel->pending_pos;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi stream->pos += channel->pending_pos;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi channel->pending_pos = 0;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi return ret;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi }
f01fe9df4240c5b15d0b1c4b485a38f7c5736781Timo Sirainen return i_stream_multiplex_read(channel->mstream, channel);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi}
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
36aa1b351b8e9d02a93aa17e5de8a06ac5440084Timo Sirainenstatic void
038c2831447440bf0bef89b43dd0968afc298abcStephan Boschi_stream_multiplex_ichannel_switch_ioloop_to(struct istream_private *stream,
038c2831447440bf0bef89b43dd0968afc298abcStephan Bosch struct ioloop *ioloop)
36aa1b351b8e9d02a93aa17e5de8a06ac5440084Timo Sirainen{
36aa1b351b8e9d02a93aa17e5de8a06ac5440084Timo Sirainen struct multiplex_ichannel *channel = (struct multiplex_ichannel*)stream;
36aa1b351b8e9d02a93aa17e5de8a06ac5440084Timo Sirainen
038c2831447440bf0bef89b43dd0968afc298abcStephan Bosch i_stream_switch_ioloop_to(channel->mstream->parent, ioloop);
36aa1b351b8e9d02a93aa17e5de8a06ac5440084Timo Sirainen}
36aa1b351b8e9d02a93aa17e5de8a06ac5440084Timo Sirainen
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomistatic void
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomii_stream_multiplex_ichannel_close(struct iostream_private *stream, bool close_parent)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi{
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct multiplex_ichannel *const *channelp;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct multiplex_ichannel *channel = (struct multiplex_ichannel*)stream;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi channel->closed = TRUE;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi if (close_parent) {
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi array_foreach(&channel->mstream->channels, channelp)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi if (*channelp != NULL && !(*channelp)->closed)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi return;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_stream_close(channel->mstream->parent);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi }
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi}
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomistatic void i_stream_multiplex_try_destroy(struct multiplex_istream *mstream)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi{
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct multiplex_ichannel **channelp;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi /* can't do anything until they are all closed */
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi array_foreach_modifiable(&mstream->channels, channelp)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi if (*channelp != NULL)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi return;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_stream_unref(&mstream->parent);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi array_free(&mstream->channels);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_free(mstream);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi}
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomistatic void i_stream_multiplex_ichannel_destroy(struct iostream_private *stream)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi{
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct multiplex_ichannel **channelp;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct multiplex_ichannel *channel = (struct multiplex_ichannel*)stream;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_stream_multiplex_ichannel_close(stream, TRUE);
54bd0fec0be357266e299466a582f3c9269884e9Timo Sirainen i_stream_free_buffer(&channel->istream);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi array_foreach_modifiable(&channel->mstream->channels, channelp) {
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi if (*channelp == channel) {
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi *channelp = NULL;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi break;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi }
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi }
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_stream_multiplex_try_destroy(channel->mstream);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi}
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomistatic struct istream *
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomii_stream_add_channel_real(struct multiplex_istream *mstream, uint8_t cid)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi{
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct multiplex_ichannel *channel = i_new(struct multiplex_ichannel, 1);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi channel->cid = cid;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi channel->mstream = mstream;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi channel->istream.read = i_stream_multiplex_ichannel_read;
038c2831447440bf0bef89b43dd0968afc298abcStephan Bosch channel->istream.switch_ioloop_to = i_stream_multiplex_ichannel_switch_ioloop_to;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi channel->istream.iostream.close = i_stream_multiplex_ichannel_close;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi channel->istream.iostream.destroy = i_stream_multiplex_ichannel_destroy;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi channel->istream.max_buffer_size = mstream->bufsize;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi channel->istream.istream.blocking = mstream->blocking;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi if (cid == 0)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi channel->istream.fd = i_stream_get_fd(mstream->parent);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi else
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi channel->istream.fd = -1;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi array_append(&channel->mstream->channels, &channel, 1);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
2974dca6be5120e49279f06c8aa952e5fac56048Timo Sirainen return i_stream_create(&channel->istream, NULL, channel->istream.fd, 0);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi}
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomistruct istream *i_stream_multiplex_add_channel(struct istream *stream, uint8_t cid)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi{
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct multiplex_ichannel *chan =
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi (struct multiplex_ichannel *)stream->real_stream;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_assert(get_channel(chan->mstream, cid) == NULL);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi return i_stream_add_channel_real(chan->mstream, cid);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi}
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomistruct istream *i_stream_create_multiplex(struct istream *parent, size_t bufsize)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi{
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct multiplex_istream *mstream;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi mstream = i_new(struct multiplex_istream, 1);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi mstream->parent = parent;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi mstream->bufsize = bufsize;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi mstream->blocking = parent->blocking;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_array_init(&mstream->channels, 8);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_stream_ref(parent);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi return i_stream_add_channel_real(mstream, 0);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi}
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomiuint8_t i_stream_multiplex_get_channel_id(struct istream *stream)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi{
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct multiplex_ichannel *channel =
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi (struct multiplex_ichannel *)stream->real_stream;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi return channel->cid;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi}