bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2016-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 "crc32.h"
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi#include "randgen.h"
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi#include "istream-private.h"
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi#include "istream-multiplex.h"
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi#include "ostream.h"
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi#include <unistd.h>
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomistatic void test_istream_multiplex_simple(void)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi{
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_begin("istream multiplex (simple)");
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi static const char data[] = "\x00\x00\x00\x00\x06Hello\x00"
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi "\x01\x00\x00\x00\x03Wor"
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi "\x00\x00\x00\x00\x00"
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi "\x01\x00\x00\x00\x03ld\x00";
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi static const size_t data_len = sizeof(data)-1;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct istream *input = test_istream_create_data(data, data_len);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi size_t siz;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct istream *chan0 = i_stream_create_multiplex(input, (size_t)-1);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct istream *chan1 = i_stream_multiplex_add_channel(chan0, 1);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi /* nothing to read until the first byte */
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi for (size_t i = 0; i <= 1+4; i++) {
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_istream_set_size(input, i);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_assert(i_stream_read(chan0) == 0);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_assert(i_stream_read(chan1) == 0);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi }
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi /* partial read of the first packet */
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi size_t input_max = 1+4+3;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_istream_set_size(input, input_max);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_assert(i_stream_read(chan0) == 3);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_assert(memcmp(i_stream_get_data(chan0, &siz), "Hel", 3) == 0 &&
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi siz == 3);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_assert(i_stream_read(chan1) == 0);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi /* read the rest of the first packet and the second packet.
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi read chan1 before chan0 to see that it works. */
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi input_max += 3 + 1+4+3;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_istream_set_size(input, input_max);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_assert(i_stream_read(chan1) == 3);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_assert(i_stream_read(chan0) == 3);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_assert(memcmp(i_stream_get_data(chan0, &siz), "Hello\0", 6) == 0 &&
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi siz == 6);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_assert(memcmp(i_stream_get_data(chan1, &siz), "Wor", 3) == 0 &&
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi siz == 3);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi /* 0-sized packet is ignored */
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi input_max += 1+4;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_istream_set_size(input, input_max);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_assert(i_stream_read(chan0) == 0);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_assert(i_stream_read(chan1) == 0);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi /* read the final packet */
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi input_max += 1+4+3;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_assert(input_max == data_len);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_istream_set_size(input, input_max);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_assert(i_stream_read(chan0) == 0);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_assert(i_stream_read(chan1) == 3);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi /* we should have the final data in all channels now */
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_assert(memcmp(i_stream_get_data(chan0, &siz), "Hello\0", 6) == 0 &&
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi siz == 6);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_assert(memcmp(i_stream_get_data(chan1, &siz), "World\0", 6) == 0 &&
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi siz == 6);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi /* all channels should return EOF */
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_assert(i_stream_read(chan0) == -1 && chan0->stream_errno == 0);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_stream_unref(&chan0);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_assert(i_stream_read(chan1) == -1 && chan1->stream_errno == 0);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_stream_unref(&chan1);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_stream_unref(&input);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_end();
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi}
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomistatic void test_istream_multiplex_maxbuf(void)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi{
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_begin("istream multiplex (maxbuf)");
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi static const char data[] = "\x00\x00\x00\x00\x06Hello\x00"
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi "\x01\x00\x00\x00\x06World\x00";
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi static const size_t data_len = sizeof(data)-1;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct istream *input = test_istream_create_data(data, data_len);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi size_t siz;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct istream *chan0 = i_stream_create_multiplex(input, 5);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct istream *chan1 = i_stream_multiplex_add_channel(chan0, 1);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi /* we get data for channel 0 and congest */
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_assert(i_stream_read(chan1) == 0);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi /* we read data for channel 0 */
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_assert(i_stream_read(chan0) == 5);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi /* and now it's congested */
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_assert(i_stream_read(chan0) == -2);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_assert(memcmp(i_stream_get_data(chan0, &siz), "Hello", 5) == 0 &&
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi siz == 5);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi /* consume data */
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_stream_skip(chan0, 5);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi /* we read data for channel 1 */
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_assert(i_stream_read(chan1) == 5);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_assert(memcmp(i_stream_get_data(chan1, &siz), "World", 5) == 0 &&
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi siz == 5);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi /* consume data */
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_stream_skip(chan1, 5);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi /* read last byte */
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_assert(i_stream_read(chan0) == 1);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi /* now we get byte for channel 1 */
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_assert(i_stream_read(chan0) == 0);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi /* now we read byte for channel 1 */
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_assert(i_stream_read(chan1) == 1);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi /* and everything should return EOF now */
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_assert(i_stream_read(chan1) == -1);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_assert(i_stream_read(chan0) == -1);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_stream_unref(&chan0);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_stream_unref(&chan1);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_stream_unref(&input);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_end();
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi}
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomistatic void test_istream_multiplex_random(void)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi{
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi const unsigned int max_channel = 6;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi const unsigned int packets_count = 30;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_begin("istream multiplex (random)");
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi unsigned int i;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi uoff_t bytes_written = 0, bytes_read = 0;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi buffer_t *buf = buffer_create_dynamic(default_pool, 10240);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi uint32_t input_crc[max_channel];
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi uint32_t output_crc[max_channel];
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi memset(input_crc, 0, sizeof(input_crc));
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi memset(output_crc, 0, sizeof(output_crc));
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi for (i = 0; i < packets_count; i++) {
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi unsigned int len = i_rand_limit(1024+1);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi unsigned char packet_data[len];
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi uint32_t len_be = cpu32_to_be(len);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi unsigned int channel = i_rand_limit(max_channel);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi random_fill(packet_data, len);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi input_crc[channel] =
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi crc32_data_more(input_crc[channel], packet_data, len);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi buffer_append_c(buf, channel);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi buffer_append(buf, &len_be, sizeof(len_be));
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi buffer_append(buf, packet_data, len);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi bytes_written += len;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi }
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct istream *input = test_istream_create_data(buf->data, buf->used);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct istream *chan[max_channel];
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi chan[0] = i_stream_create_multiplex(input, 1024/4);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi for (i = 1; i < max_channel; i++)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi chan[i] = i_stream_multiplex_add_channel(chan[0], i);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_istream_set_size(input, 0);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi /* read from each stream, 1 byte at a time */
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi size_t input_size = 0;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi int max_ret = -3;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi unsigned int read_max_channel = max_channel/2;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi bool something_read = FALSE;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi for (i = 0;;) {
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi ssize_t ret = i_stream_read(chan[i]);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi if (max_ret < ret)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi max_ret = ret;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi if (ret > 0) {
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi size_t size;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi const unsigned char *data =
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_stream_get_data(chan[i], &size);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi output_crc[i] = crc32_data_more(output_crc[i], data, size);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi bytes_read += size;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_assert((size_t)ret == size);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_stream_skip(chan[i], size);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi something_read = TRUE;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi }
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi if (++i < read_max_channel)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi ;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi else if (max_ret == 0 && !something_read &&
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi read_max_channel < max_channel) {
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi read_max_channel++;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi } else {
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi if (max_ret <= -1) {
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_assert(max_ret == -1);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi break;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi }
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi if (max_ret == 0)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_istream_set_size(input, ++input_size);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i = 0;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi max_ret = -3;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi something_read = FALSE;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi read_max_channel = max_channel/2;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi }
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi }
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_assert(bytes_read == bytes_written);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi for (i = 0; i < max_channel; i++) {
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_assert_idx(input_crc[i] == output_crc[i], i);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_assert_idx(i_stream_read(chan[i]) == -1 &&
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi chan[i]->stream_errno == 0, i);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_stream_unref(&chan[i]);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi }
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_stream_unref(&input);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi buffer_free(&buf);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_end();
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi}
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomistatic unsigned int channel_counter[2] = {0, 0};
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomistatic const char *msgs[] = {
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi "",
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi "a",
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi "bb",
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi "ccc",
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi "dddd",
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi "eeeee",
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi "ffffff"
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi};
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomistatic void test_istream_multiplex_stream_read(struct istream *channel)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi{
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi uint8_t cid = i_stream_multiplex_get_channel_id(channel);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi const char *line;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi size_t siz;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi if (i_stream_read(channel) < 0)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi return;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi while((line = i_stream_next_line(channel)) != NULL) {
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi siz = strlen(line);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_assert_idx(siz > 0 && siz < N_ELEMENTS(msgs),
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi channel_counter[cid]);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi if (siz > 0 && siz < N_ELEMENTS(msgs)) {
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_assert_idx(strcmp(line, msgs[siz]) == 0,
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi channel_counter[cid]);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi }
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi channel_counter[cid]++;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi }
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi if (channel_counter[0] > 100 && channel_counter[1] > 100)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi io_loop_stop(current_ioloop);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi}
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomistatic void test_send_msg(struct ostream *os, uint8_t cid, const char *msg)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi{
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi uint32_t len = cpu32_to_be(strlen(msg) + 1);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi const struct const_iovec iov[] = {
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi { &cid, sizeof(cid) },
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi { &len, sizeof(len) },
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi { msg, strlen(msg) },
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi { "\n", 1 } /* newline added for i_stream_next_line */
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi };
bc038dfe3ea41392ab50cd4c1c1fdd620cc3deefAki Tuomi o_stream_nsendv(os, iov, N_ELEMENTS(iov));
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi}
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomistatic void test_istream_multiplex_stream_write(struct ostream *channel)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi{
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi size_t rounds = i_rand() % 10;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi for(size_t i = 0; i < rounds; i++) {
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi uint8_t cid = i_rand() % 2;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_send_msg(channel, cid, msgs[1 + i_rand() % (N_ELEMENTS(msgs) - 1)]);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi }
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi}
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomistatic void test_istream_multiplex_stream(void)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi{
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_begin("istream multiplex (stream)");
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], 10 + i_rand() % 10);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct istream *chan0 = i_stream_create_multiplex(is, (size_t)-1);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct istream *chan1 = i_stream_multiplex_add_channel(chan0, 1);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct io *io0 =
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi io_add_istream(chan0, test_istream_multiplex_stream_read, chan0);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct io *io1 =
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi io_add_istream(chan1, test_istream_multiplex_stream_read, chan1);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct io *io2 =
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi io_add(fds[1], IO_WRITE, test_istream_multiplex_stream_write, os);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi io_loop_run(current_ioloop);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi io_remove(&io0);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi io_remove(&io1);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi io_remove(&io2);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_stream_unref(&chan1);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_stream_unref(&chan0);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_stream_unref(&is);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
ad9afb64630511d5e25bc5bc11c5304986156928Timo Sirainen test_assert(o_stream_finish(os) > 0);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi o_stream_unref(&os);
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 Tuomistatic void test_istream_multiplex_close_channel(void)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi{
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_begin("istream multiplex (close channel)");
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi static const char *data = "\x00\x00\x00\x00\x06Hello\x00"
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi "\x01\x00\x00\x00\x06World\x00";
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi static const size_t data_len = 22;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct istream *input = test_istream_create_data(data, data_len);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi size_t siz;
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct istream *chan0 = i_stream_create_multiplex(input, (size_t)-1);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi struct istream *chan1 = i_stream_multiplex_add_channel(chan0, 1);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_stream_unref(&chan1);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_assert(i_stream_read(chan0) == 6);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_assert(memcmp(i_stream_get_data(chan0, &siz), "Hello\0", 6) == 0 &&
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi siz == 6);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_stream_unref(&chan0);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_stream_unref(&input);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi input = test_istream_create_data(data, data_len);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi chan0 = i_stream_create_multiplex(input, (size_t)-1);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi chan1 = i_stream_multiplex_add_channel(chan0, 1);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi /* this is needed to populate chan1 data */
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi (void)i_stream_read(chan0);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_stream_unref(&chan0);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_assert(i_stream_read(chan1) == 6);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_assert(memcmp(i_stream_get_data(chan1, &siz), "World\0", 6) == 0 &&
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi siz == 6);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_stream_unref(&chan1);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi i_stream_unref(&input);
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_end();
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi}
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomivoid test_istream_multiplex(void)
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi{
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_istream_multiplex_simple();
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_istream_multiplex_maxbuf();
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_istream_multiplex_random();
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_istream_multiplex_stream();
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi test_istream_multiplex_close_channel();
1de7b73a11afda43323410a4481d866930b1e632Aki Tuomi}