istream-multiplex.c revision b78f4649c236bf4746c81c1d0e877675f0842ac8
2e37d45867d081db150ab78dad303b9077aea24fTimo Sirainen/* Copyright (c) 2017 Dovecot authors, see the included COPYING file */
94ba4820927b906b333e39445c1508a29387c3aaTimo Sirainen
94ba4820927b906b333e39445c1508a29387c3aaTimo Sirainen#include "lib.h"
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen#include "ioloop.h"
94ba4820927b906b333e39445c1508a29387c3aaTimo Sirainen#include "array.h"
94ba4820927b906b333e39445c1508a29387c3aaTimo Sirainen#include "istream-private.h"
94ba4820927b906b333e39445c1508a29387c3aaTimo Sirainen#include "istream-multiplex.h"
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen/* all multiplex packets are [1 byte cid][4 byte length][data] */
1631885636d15abaf0375304a17928c8c23782cdTimo Sirainen
94ba4820927b906b333e39445c1508a29387c3aaTimo Sirainenstruct multiplex_istream;
f330fcc3307d48954b6f8909349546773368a041Timo Sirainen
d389c93ada174a8fc6edf995b4f829d38e8fe567Timo Sirainenstruct multiplex_ichannel {
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen struct istream_private istream;
94ba4820927b906b333e39445c1508a29387c3aaTimo Sirainen struct multiplex_istream *mstream;
8732bdd21579472feb40da8ffc99b8fd3b341417Timo Sirainen uint8_t cid;
f23baa3b53b1dd4eb19729e99a43937fa3c7f309Timo Sirainen size_t pending_pos;
8732bdd21579472feb40da8ffc99b8fd3b341417Timo Sirainen bool closed:1;
7f098e28ddad259d9fbe76e18347c722bb005189Timo Sirainen};
7f098e28ddad259d9fbe76e18347c722bb005189Timo Sirainen
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainenstruct multiplex_istream {
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainen struct istream *parent;
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainen
8732bdd21579472feb40da8ffc99b8fd3b341417Timo Sirainen /* channel 0 is main channel */
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen uint8_t cur_channel;
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen unsigned int remain;
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen size_t bufsize;
d38ca817bdcec666a3b91efb917064ab844c36a2Timo Sirainen ARRAY(struct multiplex_ichannel *) channels;
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen
8732bdd21579472feb40da8ffc99b8fd3b341417Timo Sirainen bool blocking:1;
d38ca817bdcec666a3b91efb917064ab844c36a2Timo Sirainen};
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainenstatic ssize_t i_stream_multiplex_ichannel_read(struct istream_private *stream);
d38ca817bdcec666a3b91efb917064ab844c36a2Timo Sirainen
d38ca817bdcec666a3b91efb917064ab844c36a2Timo Sirainenstatic struct multiplex_ichannel *
d38ca817bdcec666a3b91efb917064ab844c36a2Timo Sirainenget_channel(struct multiplex_istream *mstream, uint8_t cid)
d38ca817bdcec666a3b91efb917064ab844c36a2Timo Sirainen{
d38ca817bdcec666a3b91efb917064ab844c36a2Timo Sirainen struct multiplex_ichannel **channelp;
d38ca817bdcec666a3b91efb917064ab844c36a2Timo Sirainen i_assert(mstream != NULL);
1631885636d15abaf0375304a17928c8c23782cdTimo Sirainen array_foreach_modifiable(&mstream->channels, channelp) {
1631885636d15abaf0375304a17928c8c23782cdTimo Sirainen if (*channelp != NULL && (*channelp)->cid == cid)
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen return *channelp;
1631885636d15abaf0375304a17928c8c23782cdTimo Sirainen }
1631885636d15abaf0375304a17928c8c23782cdTimo Sirainen return NULL;
1631885636d15abaf0375304a17928c8c23782cdTimo Sirainen}
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainen
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainenstatic void propagate_error(struct multiplex_istream *mstream, int stream_errno)
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen{
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen struct multiplex_ichannel **channelp;
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen array_foreach_modifiable(&mstream->channels, channelp)
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen if (*channelp != NULL)
ea1ae54fcfbd8e911978c149f9e7265a45b6380aTimo Sirainen (*channelp)->istream.istream.stream_errno = stream_errno;
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen}
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainenstatic void propagate_eof(struct multiplex_istream *mstream)
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen{
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainen struct multiplex_ichannel **channelp;
f77da594de6318312a7f31589c9e4c38e2b74c73Timo Sirainen array_foreach_modifiable(&mstream->channels, channelp) {
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen if (*channelp != NULL) {
f77da594de6318312a7f31589c9e4c38e2b74c73Timo Sirainen (*channelp)->istream.istream.eof = TRUE;
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen }
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen }
f77da594de6318312a7f31589c9e4c38e2b74c73Timo Sirainen}
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen
f77da594de6318312a7f31589c9e4c38e2b74c73Timo Sirainenstatic ssize_t
f77da594de6318312a7f31589c9e4c38e2b74c73Timo Siraineni_stream_multiplex_read(struct multiplex_istream *mstream, uint8_t cid)
f77da594de6318312a7f31589c9e4c38e2b74c73Timo Sirainen{
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainen struct multiplex_ichannel *req_channel = get_channel(mstream, cid);
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen const unsigned char *data;
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen size_t len = 0, used, wanted, avail;
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen ssize_t ret, got = 0;
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen if (mstream->parent == NULL) {
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainen req_channel->istream.istream.eof = TRUE;
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen return -1;
1f792fb84e8fdfd2a9b65100ce1c31d0212fa3b0Timo Sirainen }
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen (void)i_stream_get_data(mstream->parent, &len);
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainen if (len == 0 && mstream->parent->closed) {
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen req_channel->istream.istream.eof = TRUE;
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen return -1;
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen }
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen if (((mstream->remain > 0 && len == 0) ||
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen (mstream->remain == 0 && len < 5)) &&
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen (ret = i_stream_read(mstream->parent)) <= 0) {
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen propagate_error(mstream, mstream->parent->stream_errno);
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen if (mstream->parent->eof)
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainen propagate_eof(mstream);
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen return ret;
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen }
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen for(;;) {
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen data = i_stream_get_data(mstream->parent, &len);
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen if (len == 0) {
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen if (got == 0 && mstream->blocking) {
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen /* can't return 0 with blocking istreams,
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen so try again from the beginning. */
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainen return i_stream_multiplex_read(mstream, cid);
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen }
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen break;
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen }
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen if (mstream->remain > 0) {
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen struct multiplex_ichannel *channel =
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen get_channel(mstream, mstream->cur_channel);
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen wanted = I_MIN(len, mstream->remain);
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen /* is it open? */
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen if (channel != NULL && !channel->closed) {
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen struct istream_private *stream = &channel->istream;
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen stream->pos += channel->pending_pos;
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen bool alloc_ret = i_stream_try_alloc(stream, wanted, &avail);
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen stream->pos -= channel->pending_pos;
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen if (!alloc_ret) {
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen i_stream_set_input_pending(&stream->istream, TRUE);
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen if (channel->cid != cid)
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen return 0;
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen if (got > 0)
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen break;
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen return -2;
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen }
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen used = I_MIN(wanted, avail);
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen /* dump into buffer */
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen if (channel->cid != cid) {
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen i_assert(stream->pos + channel->pending_pos + used <= stream->buffer_size);
d38ca817bdcec666a3b91efb917064ab844c36a2Timo Sirainen memcpy(stream->w_buffer + stream->pos + channel->pending_pos,
d38ca817bdcec666a3b91efb917064ab844c36a2Timo Sirainen data, used);
d38ca817bdcec666a3b91efb917064ab844c36a2Timo Sirainen channel->pending_pos += used;
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen i_stream_set_input_pending(&stream->istream, TRUE);
d38ca817bdcec666a3b91efb917064ab844c36a2Timo Sirainen } else {
d38ca817bdcec666a3b91efb917064ab844c36a2Timo Sirainen i_assert(stream->pos + used <= stream->buffer_size);
d38ca817bdcec666a3b91efb917064ab844c36a2Timo Sirainen memcpy(stream->w_buffer + stream->pos, data, used);
d38ca817bdcec666a3b91efb917064ab844c36a2Timo Sirainen stream->pos += used;
d38ca817bdcec666a3b91efb917064ab844c36a2Timo Sirainen got += used;
d38ca817bdcec666a3b91efb917064ab844c36a2Timo Sirainen }
d38ca817bdcec666a3b91efb917064ab844c36a2Timo Sirainen } else {
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen used = wanted;
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen }
d38ca817bdcec666a3b91efb917064ab844c36a2Timo Sirainen mstream->remain -= used;
d38ca817bdcec666a3b91efb917064ab844c36a2Timo Sirainen i_stream_skip(mstream->parent, used);
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen /* see if there is more to read */
d38ca817bdcec666a3b91efb917064ab844c36a2Timo Sirainen continue;
d38ca817bdcec666a3b91efb917064ab844c36a2Timo Sirainen }
d38ca817bdcec666a3b91efb917064ab844c36a2Timo Sirainen if (mstream->remain == 0) {
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainen /* need more data */
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen if (len < 5) {
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen ret = i_stream_multiplex_ichannel_read(&req_channel->istream);
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen if (ret > 0)
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen got += ret;
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen break;
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen }
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen /* channel ID */
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen mstream->cur_channel = data[0];
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen /* data length */
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen mstream->remain = be32_to_cpu_unaligned(data+1);
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen i_stream_skip(mstream->parent, 5);
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen }
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen }
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen propagate_error(mstream, mstream->parent->stream_errno);
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen if (mstream->parent->eof)
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen propagate_eof(mstream);
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen return got;
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen}
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainenstatic ssize_t i_stream_multiplex_ichannel_read(struct istream_private *stream)
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen{
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen struct multiplex_ichannel *channel = (struct multiplex_ichannel*)stream;
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen /* if previous multiplex read dumped data for us
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen actually serve it here. */
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen if (channel->pending_pos > 0) {
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainen ssize_t ret = channel->pending_pos;
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen stream->pos += channel->pending_pos;
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen channel->pending_pos = 0;
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen return ret;
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen }
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen return i_stream_multiplex_read(channel->mstream, channel->cid);
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen}
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainenstatic void
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Siraineni_stream_multiplex_ichannel_close(struct iostream_private *stream, bool close_parent)
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen{
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen struct multiplex_ichannel *const *channelp;
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen struct multiplex_ichannel *channel = (struct multiplex_ichannel*)stream;
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen channel->closed = TRUE;
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen if (close_parent) {
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen array_foreach(&channel->mstream->channels, channelp)
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen if (*channelp != NULL && !(*channelp)->closed)
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen return;
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen i_stream_close(channel->mstream->parent);
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen }
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen}
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainenstatic void i_stream_multiplex_try_destroy(struct multiplex_istream *mstream)
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen{
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen struct multiplex_ichannel **channelp;
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen /* can't do anything until they are all closed */
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainen array_foreach_modifiable(&mstream->channels, channelp)
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen if (*channelp != NULL)
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen return;
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen i_stream_unref(&mstream->parent);
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen array_free(&mstream->channels);
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen i_free(mstream);
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen}
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainenstatic void i_stream_multiplex_ichannel_destroy(struct iostream_private *stream)
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen{
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainen struct multiplex_ichannel **channelp;
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen struct multiplex_ichannel *channel = (struct multiplex_ichannel*)stream;
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen i_stream_multiplex_ichannel_close(stream, TRUE);
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen i_free(channel->istream.w_buffer);
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen array_foreach_modifiable(&channel->mstream->channels, channelp) {
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen if (*channelp == channel) {
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen *channelp = NULL;
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen break;
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen }
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen }
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainen i_stream_multiplex_try_destroy(channel->mstream);
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen}
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainenstatic struct istream *
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Siraineni_stream_add_channel_real(struct multiplex_istream *mstream, uint8_t cid)
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen{
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen struct multiplex_ichannel *channel = i_new(struct multiplex_ichannel, 1);
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen channel->cid = cid;
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen channel->mstream = mstream;
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen channel->istream.read = i_stream_multiplex_ichannel_read;
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainen channel->istream.iostream.close = i_stream_multiplex_ichannel_close;
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen channel->istream.iostream.destroy = i_stream_multiplex_ichannel_destroy;
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen channel->istream.max_buffer_size = mstream->bufsize;
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen channel->istream.istream.blocking = mstream->blocking;
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen if (cid == 0)
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen channel->istream.fd = i_stream_get_fd(mstream->parent);
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen else
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen channel->istream.fd = -1;
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen array_append(&channel->mstream->channels, &channel, 1);
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen return i_stream_create(&channel->istream, NULL, channel->istream.fd);
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen}
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainenstruct istream *i_stream_multiplex_add_channel(struct istream *stream, uint8_t cid)
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen{
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen struct multiplex_ichannel *chan =
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainen (struct multiplex_ichannel *)stream->real_stream;
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen i_assert(get_channel(chan->mstream, cid) == NULL);
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen return i_stream_add_channel_real(chan->mstream, cid);
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen}
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainenstruct istream *i_stream_create_multiplex(struct istream *parent, size_t bufsize)
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen{
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen struct multiplex_istream *mstream;
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen
c8ff6ff3a9b76f12b0e8269ca7bdd62d895f476bTimo Sirainen mstream = i_new(struct multiplex_istream, 1);
c8ff6ff3a9b76f12b0e8269ca7bdd62d895f476bTimo Sirainen mstream->parent = parent;
c8ff6ff3a9b76f12b0e8269ca7bdd62d895f476bTimo Sirainen mstream->bufsize = bufsize;
c8ff6ff3a9b76f12b0e8269ca7bdd62d895f476bTimo Sirainen mstream->blocking = parent->blocking;
c8ff6ff3a9b76f12b0e8269ca7bdd62d895f476bTimo Sirainen i_array_init(&mstream->channels, 8);
c8ff6ff3a9b76f12b0e8269ca7bdd62d895f476bTimo Sirainen i_stream_ref(parent);
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen
c8ff6ff3a9b76f12b0e8269ca7bdd62d895f476bTimo Sirainen return i_stream_add_channel_real(mstream, 0);
c8ff6ff3a9b76f12b0e8269ca7bdd62d895f476bTimo Sirainen}
c8ff6ff3a9b76f12b0e8269ca7bdd62d895f476bTimo Sirainen
c8ff6ff3a9b76f12b0e8269ca7bdd62d895f476bTimo Sirainenuint8_t i_stream_multiplex_get_channel_id(struct istream *stream)
c8ff6ff3a9b76f12b0e8269ca7bdd62d895f476bTimo Sirainen{
c8ff6ff3a9b76f12b0e8269ca7bdd62d895f476bTimo Sirainen struct multiplex_ichannel *channel =
c8ff6ff3a9b76f12b0e8269ca7bdd62d895f476bTimo Sirainen (struct multiplex_ichannel *)stream->real_stream;
c8ff6ff3a9b76f12b0e8269ca7bdd62d895f476bTimo Sirainen return channel->cid;
c8ff6ff3a9b76f12b0e8269ca7bdd62d895f476bTimo Sirainen}
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen