istream-multiplex.c revision 36aa1b351b8e9d02a93aa17e5de8a06ac5440084
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen/* Copyright (c) 2017 Dovecot authors, see the included COPYING file */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "lib.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "ioloop.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "array.h"
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen#include "istream-private.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "istream-multiplex.h"
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen/* all multiplex packets are [1 byte cid][4 byte length][data] */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenstruct multiplex_istream;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainenstruct multiplex_ichannel {
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen struct istream_private istream;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen struct multiplex_istream *mstream;
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen uint8_t cid;
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen size_t pending_pos;
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen bool closed:1;
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen};
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainenstruct multiplex_istream {
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen struct istream *parent;
373492be949e159fda651807b3acda2c5c077027Timo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen /* channel 0 is main channel */
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen uint8_t cur_channel;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen unsigned int remain;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen size_t bufsize;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen ARRAY(struct multiplex_ichannel *) channels;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
373492be949e159fda651807b3acda2c5c077027Timo Sirainen bool blocking:1;
373492be949e159fda651807b3acda2c5c077027Timo Sirainen};
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainenstatic ssize_t i_stream_multiplex_ichannel_read(struct istream_private *stream);
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainenstatic struct multiplex_ichannel *
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainenget_channel(struct multiplex_istream *mstream, uint8_t cid)
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen{
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen struct multiplex_ichannel **channelp;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen i_assert(mstream != NULL);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen array_foreach_modifiable(&mstream->channels, channelp) {
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen if (*channelp != NULL && (*channelp)->cid == cid)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen return *channelp;
635df5b4cbcd7b24c825e01d9dd66d3a4274c4c7Timo Sirainen }
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen return NULL;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen}
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainenstatic void propagate_error(struct multiplex_istream *mstream, int stream_errno)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen{
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen struct multiplex_ichannel **channelp;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen array_foreach_modifiable(&mstream->channels, channelp)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen if (*channelp != NULL)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen (*channelp)->istream.istream.stream_errno = stream_errno;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen}
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainenstatic void propagate_eof(struct multiplex_istream *mstream)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen{
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen struct multiplex_ichannel **channelp;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen array_foreach_modifiable(&mstream->channels, channelp) {
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen if (*channelp != NULL) {
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen (*channelp)->istream.istream.eof = TRUE;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen }
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen }
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen}
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
635df5b4cbcd7b24c825e01d9dd66d3a4274c4c7Timo Sirainenstatic ssize_t
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Siraineni_stream_multiplex_read(struct multiplex_istream *mstream, uint8_t cid)
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen{
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen struct multiplex_ichannel *req_channel = get_channel(mstream, cid);
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen const unsigned char *data;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen size_t len = 0, used, wanted, avail;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen ssize_t ret, got = 0;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen if (mstream->parent == NULL) {
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen req_channel->istream.istream.eof = TRUE;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen return -1;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen }
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen (void)i_stream_get_data(mstream->parent, &len);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen if (len == 0 && mstream->parent->closed) {
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen req_channel->istream.istream.eof = TRUE;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen return -1;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen }
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen if (((mstream->remain > 0 && len == 0) ||
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen (mstream->remain == 0 && len < 5)) &&
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen (ret = i_stream_read(mstream->parent)) <= 0) {
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen propagate_error(mstream, mstream->parent->stream_errno);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen if (mstream->parent->eof)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen propagate_eof(mstream);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen return ret;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen }
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen for(;;) {
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen data = i_stream_get_data(mstream->parent, &len);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen if (len == 0) {
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen if (got == 0 && mstream->blocking) {
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen /* can't return 0 with blocking istreams,
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen so try again from the beginning. */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return i_stream_multiplex_read(mstream, cid);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen break;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (mstream->remain > 0) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen struct multiplex_ichannel *channel =
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen get_channel(mstream, mstream->cur_channel);
380dbb60ae291cbe39d1f710284562ca9167150bTimo Sirainen wanted = I_MIN(len, mstream->remain);
380dbb60ae291cbe39d1f710284562ca9167150bTimo Sirainen /* is it open? */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (channel != NULL && !channel->closed) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen struct istream_private *stream = &channel->istream;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen stream->pos += channel->pending_pos;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen bool alloc_ret = i_stream_try_alloc(stream, wanted, &avail);
1b823b2b7790a1e1b7974fcf11a4c48a28e70f37Timo Sirainen stream->pos -= channel->pending_pos;
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen if (!alloc_ret) {
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen i_stream_set_input_pending(&stream->istream, TRUE);
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen if (channel->cid != cid)
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen return 0;
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen if (got > 0)
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen break;
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen return -2;
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen }
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
1b823b2b7790a1e1b7974fcf11a4c48a28e70f37Timo Sirainen used = I_MIN(wanted, avail);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen /* dump into buffer */
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen if (channel->cid != cid) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen i_assert(stream->pos + channel->pending_pos + used <= stream->buffer_size);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen memcpy(stream->w_buffer + stream->pos + channel->pending_pos,
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen data, used);
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen channel->pending_pos += used;
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen i_stream_set_input_pending(&stream->istream, TRUE);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen } else {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen i_assert(stream->pos + used <= stream->buffer_size);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen memcpy(stream->w_buffer + stream->pos, data, used);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen stream->pos += used;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen got += used;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen } else {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen used = wanted;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen mstream->remain -= used;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen i_stream_skip(mstream->parent, used);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen /* see if there is more to read */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen continue;
1b823b2b7790a1e1b7974fcf11a4c48a28e70f37Timo Sirainen }
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen if (mstream->remain == 0) {
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen /* need more data */
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen if (len < 5) {
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen ret = i_stream_multiplex_ichannel_read(&req_channel->istream);
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen if (ret > 0)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen got += ret;
1b823b2b7790a1e1b7974fcf11a4c48a28e70f37Timo Sirainen break;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen /* channel ID */
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen mstream->cur_channel = data[0];
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen /* data length */
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen mstream->remain = be32_to_cpu_unaligned(data+1);
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen i_stream_skip(mstream->parent, 5);
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen }
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen propagate_error(mstream, mstream->parent->stream_errno);
57d2429fae575e96ca276355af675deb66b76d00Timo Sirainen if (mstream->parent->eof)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen propagate_eof(mstream);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return got;
57d2429fae575e96ca276355af675deb66b76d00Timo Sirainen}
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenstatic ssize_t i_stream_multiplex_ichannel_read(struct istream_private *stream)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen{
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen struct multiplex_ichannel *channel = (struct multiplex_ichannel*)stream;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen /* if previous multiplex read dumped data for us
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen actually serve it here. */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (channel->pending_pos > 0) {
61618d4c58080570f689614fec204ae14e90cef2Timo Sirainen ssize_t ret = channel->pending_pos;
50e20db49f29917fe9adcf1b56b11badf28bd0e4Timo Sirainen stream->pos += channel->pending_pos;
50e20db49f29917fe9adcf1b56b11badf28bd0e4Timo Sirainen channel->pending_pos = 0;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return ret;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return i_stream_multiplex_read(channel->mstream, channel->cid);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen}
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenstatic void
a64adf62fa33f2463a86f990217b0c9078531a40Timo Siraineni_stream_multiplex_ichannel_switch_ioloop(struct istream_private *stream)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen{
50e20db49f29917fe9adcf1b56b11badf28bd0e4Timo Sirainen struct multiplex_ichannel *channel = (struct multiplex_ichannel*)stream;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen i_stream_switch_ioloop(channel->mstream->parent);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen}
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
c6f894e1522f7b0b6068c228900914073c145175Timo Sirainenstatic void
a64adf62fa33f2463a86f990217b0c9078531a40Timo Siraineni_stream_multiplex_ichannel_close(struct iostream_private *stream, bool close_parent)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen{
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen struct multiplex_ichannel *const *channelp;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen struct multiplex_ichannel *channel = (struct multiplex_ichannel*)stream;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen channel->closed = TRUE;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (close_parent) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen array_foreach(&channel->mstream->channels, channelp)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (*channelp != NULL && !(*channelp)->closed)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen i_stream_close(channel->mstream->parent);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen}
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainenstatic void i_stream_multiplex_try_destroy(struct multiplex_istream *mstream)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen{
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen struct multiplex_ichannel **channelp;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen /* can't do anything until they are all closed */
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen array_foreach_modifiable(&mstream->channels, channelp)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen if (*channelp != NULL)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen return;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen i_stream_unref(&mstream->parent);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen array_free(&mstream->channels);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen i_free(mstream);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen}
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainenstatic void i_stream_multiplex_ichannel_destroy(struct iostream_private *stream)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen{
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen struct multiplex_ichannel **channelp;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen struct multiplex_ichannel *channel = (struct multiplex_ichannel*)stream;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen i_stream_multiplex_ichannel_close(stream, TRUE);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen i_free(channel->istream.w_buffer);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen array_foreach_modifiable(&channel->mstream->channels, channelp) {
c6f894e1522f7b0b6068c228900914073c145175Timo Sirainen if (*channelp == channel) {
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen *channelp = NULL;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen break;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen }
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen }
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen i_stream_multiplex_try_destroy(channel->mstream);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen}
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainenstatic struct istream *
a64adf62fa33f2463a86f990217b0c9078531a40Timo Siraineni_stream_add_channel_real(struct multiplex_istream *mstream, uint8_t cid)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen{
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen struct multiplex_ichannel *channel = i_new(struct multiplex_ichannel, 1);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen channel->cid = cid;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen channel->mstream = mstream;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen channel->istream.read = i_stream_multiplex_ichannel_read;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen channel->istream.switch_ioloop = i_stream_multiplex_ichannel_switch_ioloop;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen channel->istream.iostream.close = i_stream_multiplex_ichannel_close;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen channel->istream.iostream.destroy = i_stream_multiplex_ichannel_destroy;
383d0e8c24451468d6bea17e4b55d74de744abe6Timo Sirainen channel->istream.max_buffer_size = mstream->bufsize;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen channel->istream.istream.blocking = mstream->blocking;
383d0e8c24451468d6bea17e4b55d74de744abe6Timo Sirainen if (cid == 0)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen channel->istream.fd = i_stream_get_fd(mstream->parent);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen else
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen channel->istream.fd = -1;
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen array_append(&channel->mstream->channels, &channel, 1);
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen
2024157e8de36edd31f5fd72f5ea7364a0955fa7Timo Sirainen return i_stream_create(&channel->istream, NULL, channel->istream.fd);
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen}
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainenstruct istream *i_stream_multiplex_add_channel(struct istream *stream, uint8_t cid)
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen{
15f526e5ac611b4532568d131fcd0abf664abe41Timo Sirainen struct multiplex_ichannel *chan =
15f526e5ac611b4532568d131fcd0abf664abe41Timo Sirainen (struct multiplex_ichannel *)stream->real_stream;
15f526e5ac611b4532568d131fcd0abf664abe41Timo Sirainen i_assert(get_channel(chan->mstream, cid) == NULL);
15f526e5ac611b4532568d131fcd0abf664abe41Timo Sirainen
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen return i_stream_add_channel_real(chan->mstream, cid);
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen}
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainenstruct istream *i_stream_create_multiplex(struct istream *parent, size_t bufsize)
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen{
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen struct multiplex_istream *mstream;
0f62889d833767acf9c2ad010c3269806b4cfae3Timo Sirainen
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen mstream = i_new(struct multiplex_istream, 1);
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen mstream->parent = parent;
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen mstream->bufsize = bufsize;
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen mstream->blocking = parent->blocking;
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen i_array_init(&mstream->channels, 8);
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen i_stream_ref(parent);
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen return i_stream_add_channel_real(mstream, 0);
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen}
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainenuint8_t i_stream_multiplex_get_channel_id(struct istream *stream)
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen{
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen struct multiplex_ichannel *channel =
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen (struct multiplex_ichannel *)stream->real_stream;
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen return channel->cid;
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen}
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen