ostream-multiplex.c revision 2707567dbba16966d76a986fba09f639659a24e1
183bea41fa640dc8117f3eb45ff935cd81377a84Timo Sirainen/* Copyright (c) 2017 Dovecot authors, see the included COPYING file */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include "lib.h"
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include "ioloop.h"
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include "array.h"
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include "ostream-private.h"
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include "ostream-multiplex.h"
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen/* all multiplex packets are [1 byte cid][4 byte length][data] */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenstruct multiplex_ostream;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenstruct multiplex_ochannel {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen struct ostream_private ostream;
1d738cce754bc64bbc66d3355ebdaf3f6eac55f1Timo Sirainen struct multiplex_ostream *mstream;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen uint8_t cid;
bdd7a96c363346f7c38f389791be1487ca08775bTimo Sirainen buffer_t *buf;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen time_t last_sent;
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen bool closed:1;
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen};
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainenstruct multiplex_ostream {
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen struct ostream *parent;
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen /* channel 0 is main channel */
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen uint8_t cur_channel;
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen unsigned int remain;
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen buffer_t *wbuf;
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen size_t bufsize;
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen ARRAY(struct multiplex_ochannel *) channels;
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen bool destroyed:1;
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen};
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainenstatic struct multiplex_ochannel *
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainenget_channel(struct multiplex_ostream *mstream, uint8_t cid)
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen{
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen struct multiplex_ochannel **channelp;
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen i_assert(mstream != NULL);
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen array_foreach_modifiable(&mstream->channels, channelp) {
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen if (*channelp != NULL && (*channelp)->cid == cid)
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen return *channelp;
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen }
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen return NULL;
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen}
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainenstatic void propagate_error(struct multiplex_ostream *mstream, int stream_errno)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen struct multiplex_ochannel **channelp;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen array_foreach_modifiable(&mstream->channels, channelp)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (*channelp != NULL)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen (*channelp)->ostream.ostream.stream_errno = stream_errno;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenstatic struct multiplex_ochannel *get_next_channel(struct multiplex_ostream *mstream)
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen{
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen time_t oldest = ioloop_time;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen struct multiplex_ochannel *channel = NULL;
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen struct multiplex_ochannel **channelp;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen array_foreach_modifiable(&mstream->channels, channelp)
b397665e90fa0fc7c6a9156fdd6cf28b571e8e39Timo Sirainen if (*channelp != NULL && (*channelp)->last_sent <= oldest &&
b397665e90fa0fc7c6a9156fdd6cf28b571e8e39Timo Sirainen (*channelp)->buf->used > 0)
b397665e90fa0fc7c6a9156fdd6cf28b571e8e39Timo Sirainen channel = *channelp;
b397665e90fa0fc7c6a9156fdd6cf28b571e8e39Timo Sirainen return channel;
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen}
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenstatic ssize_t
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Siraineno_stream_multiplex_sendv(struct multiplex_ostream *mstream)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen struct multiplex_ochannel *channel;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen ssize_t ret = 0;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (mstream->bufsize <= mstream->wbuf->used + 5)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -2;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen while((channel = get_next_channel(mstream)) != NULL) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen size_t tmp = mstream->bufsize - mstream->wbuf->used - 5;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* ensure it fits into 32 bit int */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen size_t amt = I_MIN(UINT_MAX, I_MIN(tmp, channel->buf->used));
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (tmp == 0)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen break;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen uint32_t len = cpu32_to_be(amt);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen buffer_append(mstream->wbuf, &channel->cid, 1);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen buffer_append(mstream->wbuf, &len, 4);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen buffer_append(mstream->wbuf, channel->buf->data, amt);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen buffer_delete(channel->buf, 0, amt);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen channel->last_sent = ioloop_time;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (mstream->wbuf->used > 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen ret = o_stream_send(mstream->parent, mstream->wbuf->data,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mstream->wbuf->used);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (ret < 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen propagate_error(mstream, mstream->parent->stream_errno);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return ret;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen o_stream_flush(mstream->parent);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen buffer_delete(mstream->wbuf, 0, ret);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return ret;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenstatic ssize_t
0f66f12eb4cdbf47670975044c88d8f388bf92dfTimo Siraineno_stream_multiplex_ochannel_sendv(struct ostream_private *stream,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen const struct const_iovec *iov, unsigned int iov_count)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen struct multiplex_ochannel *channel = (struct multiplex_ochannel*)stream;
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen ssize_t ret;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen size_t total = 0;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (channel->mstream->bufsize <= channel->buf->used)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return -2;
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen for(unsigned int i=0; i < iov_count; i++) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* copy data to buffer */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen size_t tmp = channel->mstream->bufsize - channel->buf->used;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (tmp == 0)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen break;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen buffer_append(channel->buf, iov[i].iov_base,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen I_MIN(tmp, iov[i].iov_len));
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen total += I_MIN(tmp, iov[i].iov_len);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen stream->ostream.offset += total;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if ((ret = o_stream_multiplex_sendv(channel->mstream)) < 0)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return ret;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen return total;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainenstatic void
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Siraineno_stream_multiplex_ochannel_close(struct iostream_private *stream, bool close_parent)
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen{
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen struct multiplex_ochannel *const *channelp;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen struct multiplex_ochannel *channel = (struct multiplex_ochannel*)stream;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen o_stream_flush(&channel->ostream.ostream);
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen channel->closed = TRUE;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen if (close_parent) {
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen array_foreach(&channel->mstream->channels, channelp)
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen if (*channelp !=NULL && !(*channelp)->closed)
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen return;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen o_stream_close(channel->mstream->parent);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen}
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainenstatic void o_stream_multiplex_try_destroy(struct multiplex_ostream *mstream)
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen{
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen struct multiplex_ochannel **channelp;
0bf3eac1110a902e7ec7e695c64e8e46c114e623Timo Sirainen /* can't do anything until they are all closed */
0bf3eac1110a902e7ec7e695c64e8e46c114e623Timo Sirainen array_foreach_modifiable(&mstream->channels, channelp)
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen if (*channelp != NULL)
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen return;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen o_stream_flush(mstream->parent);
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen o_stream_unref(&mstream->parent);
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen array_free(&mstream->channels);
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen buffer_free(&mstream->wbuf);
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen i_free(mstream);
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen}
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainenstatic void o_stream_multiplex_ochannel_destroy(struct iostream_private *stream)
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen{
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen struct multiplex_ochannel **channelp;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen struct multiplex_ochannel *channel = (struct multiplex_ochannel*)stream;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen o_stream_multiplex_ochannel_close(stream, TRUE);
f153a2cec0319f549388d28f8cfd4d50229d1132Timo Sirainen o_stream_unref(&channel->ostream.parent);
f153a2cec0319f549388d28f8cfd4d50229d1132Timo Sirainen if (channel->buf != NULL)
f153a2cec0319f549388d28f8cfd4d50229d1132Timo Sirainen buffer_free(&channel->buf);
f153a2cec0319f549388d28f8cfd4d50229d1132Timo Sirainen /* delete the channel */
f153a2cec0319f549388d28f8cfd4d50229d1132Timo Sirainen array_foreach_modifiable(&channel->mstream->channels, channelp) {
dffa503fd4ce31334346e539496084c80a2d8d37Timo Sirainen if (*channelp != NULL && (*channelp)->cid == channel->cid) {
dffa503fd4ce31334346e539496084c80a2d8d37Timo Sirainen *channelp = NULL;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen break;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen }
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen }
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen o_stream_multiplex_try_destroy(channel->mstream);
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen}
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainenstatic struct ostream *
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Siraineno_stream_add_channel_real(struct multiplex_ostream *mstream, uint8_t cid)
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen{
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen struct multiplex_ochannel *channel = i_new(struct multiplex_ochannel, 1);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen channel->cid = cid;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen channel->buf = buffer_create_dynamic(default_pool, 256);
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen channel->mstream = mstream;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen channel->ostream.sendv = o_stream_multiplex_ochannel_sendv;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen channel->ostream.iostream.close = o_stream_multiplex_ochannel_close;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen channel->ostream.iostream.destroy = o_stream_multiplex_ochannel_destroy;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen channel->ostream.fd = o_stream_get_fd(mstream->parent);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen array_append(&channel->mstream->channels, &channel, 1);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return o_stream_create(&channel->ostream, mstream->parent,
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen mstream->bufsize);
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen}
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainenstruct ostream *o_stream_multiplex_add_channel(struct ostream *stream, uint8_t cid)
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen{
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen struct multiplex_ochannel *chan =
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen (struct multiplex_ochannel *)stream->real_stream;
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen i_assert(get_channel(chan->mstream, cid) == NULL);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return o_stream_add_channel_real(chan->mstream, cid);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenstruct ostream *o_stream_create_multiplex(struct ostream *parent, size_t bufsize)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen struct multiplex_ostream *mstream;
b5b3b4c9159f506cdfdce7399faaeeffdf73faf7Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mstream = i_new(struct multiplex_ostream, 1);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mstream->parent = parent;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mstream->bufsize = bufsize;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mstream->wbuf = buffer_create_dynamic(default_pool, 256);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen i_array_init(&mstream->channels, 8);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen o_stream_ref(parent);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
40ad2c4902e9d83557f2e8a4bff3d98fea2c8aa1Timo Sirainen return o_stream_add_channel_real(mstream, 0);
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen}
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenuint8_t o_stream_multiplex_get_channel_id(struct ostream *stream)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen struct multiplex_ochannel *channel =
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen (struct multiplex_ochannel *)stream->real_stream;
14c474d9f4591c397ed0b5206af6537c7b52c924Timo Sirainen return channel->cid;
14c474d9f4591c397ed0b5206af6537c7b52c924Timo Sirainen}
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen