bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2017-2018 Dovecot authors, see the included COPYING file */
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi#include "test-lib.h"
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi#include "ioloop.h"
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi#include "str.h"
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi#include "istream.h"
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi#include "istream-multiplex.h"
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi#include "ostream.h"
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi#include "ostream-multiplex.h"
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi#include "ostream.h"
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi#include "randgen.h"
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi#include <unistd.h>
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomistruct test_channel {
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi int fds[2];
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi unsigned int cid;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct istream *in;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct ostream *out;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct io *io;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct istream *in_alt;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct ostream *out_alt;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct io *io_alt;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi buffer_t *received;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi buffer_t *received_alt;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi unsigned int counter;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi};
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomistatic struct test_channel test_channel[2];
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomistatic void test_multiplex_channel_write(struct test_channel *channel)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi{
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi unsigned char buf[128];
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi size_t len = i_rand() % sizeof(buf);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi random_fill(buf, len);
bc038dfe3ea41392ab50cd4c1c1fdd620cc3deefAki Tuomi o_stream_nsend(channel->out, buf, len);
bc038dfe3ea41392ab50cd4c1c1fdd620cc3deefAki Tuomi o_stream_nsend(channel->out_alt, buf, len);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi}
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomistatic void test_multiplex_stream_write(struct ostream *channel ATTR_UNUSED)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi{
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi if (test_channel[0].received->used > 1000 &&
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_channel[1].received->used > 1000)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi io_loop_stop(current_ioloop);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi else
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_multiplex_channel_write(&test_channel[i_rand() % 2]);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi}
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomistatic void test_istream_multiplex_stream_read(struct test_channel *channel)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi{
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi const unsigned char *data = NULL;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi size_t siz = 0;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi if (i_stream_read(channel->in) > 0) {
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi data = i_stream_get_data(channel->in, &siz);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi buffer_append(channel->received, data, siz);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_stream_skip(channel->in, siz);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi }
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi}
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomistatic void test_istream_read_alt(struct test_channel *channel)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi{
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi const unsigned char *data = NULL;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi size_t siz = 0;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi if (i_stream_read(channel->in_alt) > 0) {
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi data = i_stream_get_data(channel->in_alt, &siz);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi buffer_append(channel->received_alt, data, siz);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_stream_skip(channel->in_alt, siz);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi }
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi}
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomistatic void setup_channel(struct test_channel *channel,
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct istream *is, struct ostream *os)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi{
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi /* setup first channel */
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi channel->in = is;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi channel->out = os;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi channel->io = io_add_istream(is, test_istream_multiplex_stream_read,
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi channel);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_assert(pipe(channel->fds) == 0);
c704b7fa16ac4fa95c1d84d82d93837ae5cf98e7Timo Sirainen fd_set_nonblock(channel->fds[0], TRUE);
c704b7fa16ac4fa95c1d84d82d93837ae5cf98e7Timo Sirainen fd_set_nonblock(channel->fds[1], TRUE);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi channel->in_alt = i_stream_create_fd(channel->fds[0], (size_t)-1);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi channel->out_alt = o_stream_create_fd(channel->fds[1], IO_BLOCK_SIZE);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi channel->io_alt = io_add_istream(channel->in_alt, test_istream_read_alt,
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi channel);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi channel->received = buffer_create_dynamic(default_pool, 32768);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi channel->received_alt = buffer_create_dynamic(default_pool, 32768);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi}
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomistatic void teardown_channel(struct test_channel *channel)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi{
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_assert(memcmp(channel->received->data,
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi channel->received_alt->data,
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi channel->received->used) == 0);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_assert(channel->received->used == channel->received_alt->used);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi buffer_free(&channel->received);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi buffer_free(&channel->received_alt);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi io_remove(&channel->io);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi io_remove(&channel->io_alt);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_stream_unref(&channel->in);
ad9afb64630511d5e25bc5bc11c5304986156928Timo Sirainen test_assert(o_stream_finish(channel->out) > 0);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi o_stream_unref(&channel->out);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_stream_unref(&channel->in_alt);
ad9afb64630511d5e25bc5bc11c5304986156928Timo Sirainen test_assert(o_stream_finish(channel->out_alt) > 0);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi o_stream_unref(&channel->out_alt);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_close_fd(&channel->fds[0]);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_close_fd(&channel->fds[1]);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi}
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomistatic void test_multiplex_stream(void) {
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_begin("test multiplex (stream)");
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct ioloop *ioloop = io_loop_create();
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi io_loop_set_current(ioloop);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi int fds[2];
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_assert(pipe(fds) == 0);
c704b7fa16ac4fa95c1d84d82d93837ae5cf98e7Timo Sirainen fd_set_nonblock(fds[0], TRUE);
c704b7fa16ac4fa95c1d84d82d93837ae5cf98e7Timo Sirainen fd_set_nonblock(fds[1], TRUE);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct ostream *os = o_stream_create_fd(fds[1], (size_t)-1);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct istream *is = i_stream_create_fd(fds[0], (size_t)-1);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct istream *ichan0 = i_stream_create_multiplex(is, (size_t)-1);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct istream *ichan1 = i_stream_multiplex_add_channel(ichan0, 1);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_stream_unref(&is);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct ostream *ochan0 = o_stream_create_multiplex(os, 1024);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct ostream *ochan1 = o_stream_multiplex_add_channel(ochan0, 1);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi o_stream_unref(&os);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct io *io = io_add(fds[1], IO_WRITE, test_multiplex_stream_write, os);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi setup_channel(&test_channel[0], ichan0, ochan0);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi setup_channel(&test_channel[1], ichan1, ochan1);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_channel[0].cid = 0;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_channel[1].cid = 1;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi io_loop_run(current_ioloop);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi io_remove(&io);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi teardown_channel(&test_channel[0]);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi teardown_channel(&test_channel[1]);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi io_loop_destroy(&ioloop);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_close_fd(&fds[0]);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_close_fd(&fds[1]);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_end();
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi}
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomivoid test_multiplex(void) {
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi random_init();
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_multiplex_stream();
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi random_deinit();
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi}