/* run in the main thread in reaction to a log_reader_reopen to change * the source LogProtoServer instance. It needs to be ran in the main * thread as it reregisters the watches associated with the main * thread. */ void log_reader_reopen_deferred(gpointer s) { gpointer *args = (gpointer *) s; LogReader *self = args[0]; LogProtoServer *proto = args[1]; log_reader_stop_watches(self); if (self->io_job.working) { /* NOTE: proto can be NULL */ self->pending_proto = proto; self->pending_proto_present = TRUE; return; } if (self->proto) log_proto_server_free(self->proto); self->proto = proto; if(proto) { log_reader_start_watches(self); } }
/**************************************************************************************** * LogProtoFramedServer ****************************************************************************************/ static void test_log_proto_framed_server_simple_messages(void) { LogProtoServer *proto; proto_server_options.max_msg_size = 32; proto = log_proto_framed_server_new( log_transport_mock_stream_new( "32 0123456789ABCDEF0123456789ABCDEF", -1, "10 01234567\n\n", -1, "10 01234567\0\0", 13, /* utf8 */ "30 árvíztűrőtükörfúrógép", -1, /* iso-8859-2 */ "21 \xe1\x72\x76\xed\x7a\x74\xfb\x72\xf5\x74\xfc\x6b\xf6\x72\x66\xfa" /* |árvíztűrőtükörfú| */ "\x72\xf3\x67\xe9\x70", -1, /* |rógép| */ /* ucs4 */ "32 \x00\x00\x00\xe1\x00\x00\x00\x72\x00\x00\x00\x76\x00\x00\x00\xed" /* |...á...r...v...í| */ "\x00\x00\x00\x7a\x00\x00\x00\x74\x00\x00\x01\x71\x00\x00\x00\x72", 35, /* |...z...t...ű...r| */ LTM_EOF), get_inited_proto_server_options()); assert_proto_server_fetch(proto, "0123456789ABCDEF0123456789ABCDEF", -1); assert_proto_server_fetch(proto, "01234567\n\n", -1); assert_proto_server_fetch(proto, "01234567\0\0", 10); assert_proto_server_fetch(proto, "árvíztűrőtükörfúrógép", -1); assert_proto_server_fetch(proto, "\xe1\x72\x76\xed\x7a\x74\xfb\x72\xf5\x74\xfc\x6b\xf6\x72\x66\xfa" /* |.rv.zt.r.t.k.rf.| */ "\x72\xf3\x67\xe9\x70", -1); /* |r.g.p| */ assert_proto_server_fetch(proto, "\x00\x00\x00\xe1\x00\x00\x00\x72\x00\x00\x00\x76\x00\x00\x00\xed" /* |...á...r...v...í| */ "\x00\x00\x00\x7a\x00\x00\x00\x74\x00\x00\x01\x71\x00\x00\x00\x72", 32); /* |...z...t...q...r| */ assert_proto_server_fetch_failure(proto, LPS_EOF, NULL); log_proto_server_free(proto); }
static void test_lines_separated_with_prefix(gboolean input_is_stream) { LogProtoServer *proto; MultiLineRegexp *re; proto = log_proto_prefix_garbage_multiline_server_new( /* 32 bytes max line length, which means that the complete * multi-line block plus one additional line must fit into 32 * bytes. */ (input_is_stream ? log_transport_mock_stream_new : log_transport_mock_records_new)( "Foo First Line\n" "Foo Second Line\n" "Foo Third Line\n" "Foo Multiline\n" "multi\n" "Foo final\n", -1, LTM_PADDING, LTM_EOF), get_inited_proto_server_options(), re = multi_line_regexp_compile("^Foo", NULL), NULL); assert_proto_server_fetch(proto, "Foo First Line", -1); assert_proto_server_fetch(proto, "Foo Second Line", -1); assert_proto_server_fetch(proto, "Foo Third Line", -1); assert_proto_server_fetch(proto, "Foo Multiline\nmulti", -1); log_proto_server_free(proto); log_proto_server_options_destroy(&proto_server_options); multi_line_regexp_free(re); }
static void test_lines_separated_with_prefix_and_suffix(gboolean input_is_stream) { LogProtoServer *proto; MultiLineRegexp *re1, *re2; proto = log_proto_prefix_suffix_multiline_server_new( /* 32 bytes max line length, which means that the complete * multi-line block plus one additional line must fit into 32 * bytes. */ (0 && input_is_stream ? log_transport_mock_stream_new : log_transport_mock_records_new)( "prefix first suffix garbage\n" "prefix multi\n" "suffix garbage\n" "prefix final\n", -1, LTM_PADDING, LTM_EOF), get_inited_proto_server_options(), re1 = multi_line_regexp_compile("^prefix", NULL), re2 = multi_line_regexp_compile("suffix", NULL)); assert_proto_server_fetch(proto, "prefix first suffix", -1); assert_proto_server_fetch(proto, "prefix multi\nsuffix", -1); log_proto_server_free(proto); log_proto_server_options_destroy(&proto_server_options); multi_line_regexp_free(re1); multi_line_regexp_free(re2); };
Test(log_proto, test_log_proto_framed_server_too_long_line_trimmed_frame_at_the_end) { LogProtoServer *proto; /* - accepting one normal sized message, which fills the buffer partially * - receiving a message which has to be trimmed * -> despite we have one part of the message in the buffer, * we had to memmove it so we can read one 'max_msg_size' message * - consume the end of the trimmed message, but the trimming will already read the * first character of the next 'frame length'. * -> need to memmove the partial data, so we can read the 'frame length' properly * - checking with a normal message, that the buffer is still handled correctly */ proto_server_options.max_msg_size = 8; proto_server_options.trim_large_messages = TRUE; proto = log_proto_framed_server_new( log_transport_mock_records_new( "3 01\n15 ", -1, "1abcdefg", -1, "12345674", -1, " 2abc", -1, LTM_EOF), get_inited_proto_server_options()); assert_proto_server_fetch(proto, "01\n", 3); assert_proto_server_fetch(proto, "1abcdefg", 8); // dropping: 1234567 assert_proto_server_fetch(proto, "2abc", 4); assert_proto_server_fetch_failure(proto, LPS_EOF, NULL); log_proto_server_free(proto); }
static void test_log_proto_text_server_is_not_fetching_input_as_long_as_there_is_an_eol_in_buffer(void) { LogProtoServer *proto; accumulate_seq = 0; proto = construct_test_proto_with_accumulator( accumulator_delay_lines, log_transport_mock_records_new( /* should the LogProto instance read ahead, it gets an * EIO error */ "foo\n" "bar\n" "baz\n" "booz\n", -1, LTM_INJECT_ERROR(EIO), LTM_EOF)); assert_proto_server_fetch(proto, "foo", -1); assert_proto_server_fetch(proto, "bar", -1); assert_proto_server_fetch(proto, "baz", -1); assert_proto_server_fetch(proto, "booz", -1); assert_proto_server_fetch_failure(proto, LPS_ERROR, NULL); log_proto_server_free(proto); }
ParameterizedTest(LogTransportMockConstructor *log_transport_mock_new, log_proto, test_lines_separated_with_prefix_and_garbage) { LogProtoServer *proto; MultiLineRegexp *re1, *re2; proto = log_proto_prefix_garbage_multiline_server_new( /* 32 bytes max line length, which means that the complete * multi-line block plus one additional line must fit into 32 * bytes. */ (*log_transport_mock_new)( "Foo First Line Bar\n" "Foo Second Line Bar\n" "Foo Third Line Bar\n" "Foo Multiline\n" "multi Bar\n" "Foo final\n", -1, LTM_PADDING, LTM_EOF), get_inited_proto_server_options(), re1 = multi_line_regexp_compile("^Foo", NULL), re2 = multi_line_regexp_compile(" Bar$", NULL)); assert_proto_server_fetch(proto, "Foo First Line", -1); assert_proto_server_fetch(proto, "Foo Second Line", -1); assert_proto_server_fetch(proto, "Foo Third Line", -1); assert_proto_server_fetch(proto, "Foo Multiline\nmulti", -1); log_proto_server_free(proto); multi_line_regexp_free(re1); multi_line_regexp_free(re2); }
static void test_log_proto_text_server_multi_read_not_allowed(void) { /* FIXME: */ #if 0 LogProtoServer *proto; proto = construct_test_proto( log_transport_mock_records_new( "foobar\n", -1, /* no EOL, proto implementation would read another chunk */ "foobaz", -1, LTM_INJECT_ERROR(EIO), LTM_EOF)); ((LogProtoBufferedServer *) proto)->no_multi_read = TRUE; assert_proto_server_fetch_single_read(proto, "foobar", -1); /* because of EAGAIN */ assert_proto_server_fetch_single_read(proto, NULL, -1); /* because of NOMREAD, partial lines are returned as empty */ assert_proto_server_fetch_single_read(proto, NULL, -1); /* because of EAGAIN */ assert_proto_server_fetch_single_read(proto, NULL, -1); /* error was detected by this time, partial line is returned before the error */ assert_proto_server_fetch_single_read(proto, "foobaz", -1); /* finally the error is returned too */ assert_proto_server_fetch_failure(proto, LPS_ERROR, NULL); log_proto_server_free(proto); #endif }
static void test_log_proto_base(void) { LogProtoServer *proto; assert_gint(log_proto_get_char_size_for_fixed_encoding("iso-8859-2"), 1, NULL); assert_gint(log_proto_get_char_size_for_fixed_encoding("ucs-4"), 4, NULL); log_proto_server_options_set_encoding(&proto_server_options, "ucs-4"); proto = log_proto_binary_record_server_new( log_transport_mock_records_new( /* ucs4, terminated by record size */ "\x00\x00\x00\xe1\x00\x00\x00\x72\x00\x00\x00\x76\x00\x00\x00\xed" /* |...á...r...v...í| */ "\x00\x00\x00\x7a\x00\x00\x00\x74\x00\x00\x01\x71\x00\x00\x00\x72", 32, /* |...z...t...ű...r| */ LTM_EOF), get_inited_proto_server_options(), 32); /* check if error state is not forgotten unless reset_error is called */ proto->status = LPS_ERROR; assert_proto_server_status(proto, proto->status , LPS_ERROR); assert_proto_server_fetch_failure(proto, LPS_ERROR, NULL); log_proto_server_reset_error(proto); assert_proto_server_fetch(proto, "árvíztűr", -1); assert_proto_server_status(proto, proto->status, LPS_SUCCESS); log_proto_server_free(proto); log_proto_server_options_destroy(&proto_server_options); }
static void test_log_proto_text_server_no_encoding(gboolean input_is_stream) { LogProtoServer *proto; proto = construct_test_proto( /* 32 bytes max line length */ (input_is_stream ? log_transport_mock_stream_new : log_transport_mock_records_new)( "01234567\n" /* line too long */ "0123456789ABCDEF0123456789ABCDEF01234567\n" /* utf8 */ "árvíztűrőtükörfúrógép\n" /* iso-8859-2 */ "\xe1\x72\x76\xed\x7a\x74\xfb\x72\xf5\x74\xfc\x6b\xf6\x72\x66\xfa" /* |árvíztűrőtükörfú| */ "\x72\xf3\x67\xe9\x70\n", /* |rógép| */ -1, /* NUL terminated line */ "01234567\0" "01234567\0\n" "01234567\n\0" "01234567\r\n\0", 40, "01234567\r\n" /* no eol before EOF */ "01234567", -1, LTM_EOF)); assert_proto_server_fetch(proto, "01234567", -1); /* input split due to an oversized input line */ assert_proto_server_fetch(proto, "0123456789ABCDEF0123456789ABCDEF", -1); assert_proto_server_fetch(proto, "01234567", -1); assert_proto_server_fetch(proto, "árvíztűrőtükörfúrógép", -1); assert_proto_server_fetch(proto, "\xe1\x72\x76\xed\x7a\x74\xfb\x72\xf5\x74\xfc\x6b\xf6\x72\x66\xfa" /* |árvíztűrőtükörfú| */ "\x72\xf3\x67\xe9\x70", /* |rógép| */ -1); assert_proto_server_fetch(proto, "01234567", -1); assert_proto_server_fetch(proto, "01234567", -1); assert_proto_server_fetch(proto, "", -1); assert_proto_server_fetch(proto, "01234567", -1); assert_proto_server_fetch(proto, "", -1); assert_proto_server_fetch(proto, "01234567", -1); assert_proto_server_fetch(proto, "", -1); assert_proto_server_fetch(proto, "01234567", -1); assert_proto_server_fetch(proto, "01234567", -1); log_proto_server_free(proto); }
static void log_reader_apply_proto_and_poll_events(LogReader *self, LogProtoServer *proto, PollEvents *poll_events) { if (self->proto) log_proto_server_free(self->proto); if (self->poll_events) poll_events_free(self->poll_events); self->proto = proto; self->poll_events = poll_events; }
Test(log_proto, test_log_proto_framed_server_invalid_header) { LogProtoServer *proto; proto_server_options.max_msg_size = 32; proto = log_proto_framed_server_new( log_transport_mock_stream_new( "1q 0123456789ABCDEF0123456789ABCDEF", -1, LTM_EOF), get_inited_proto_server_options()); assert_proto_server_fetch_failure(proto, LPS_ERROR, "Invalid frame header"); log_proto_server_free(proto); }
Test(log_proto, test_log_proto_framed_server_too_long_line) { LogProtoServer *proto; proto_server_options.max_msg_size = 32; proto = log_proto_framed_server_new( log_transport_mock_stream_new( "48 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF", -1, LTM_EOF), get_inited_proto_server_options()); assert_proto_server_fetch_failure(proto, LPS_ERROR, "Incoming frame larger than log_msg_size()"); log_proto_server_free(proto); }
static void test_log_proto_text_server_io_error_before_eof(void) { LogProtoServer *proto; proto = construct_test_proto( log_transport_mock_stream_new( "01234567", -1, LTM_INJECT_ERROR(EIO), LTM_EOF)); assert_proto_server_fetch(proto, "01234567", -1); assert_proto_server_fetch_failure(proto, LPS_ERROR, NULL); log_proto_server_free(proto); }
Test(log_proto, test_log_proto_framed_server_io_error) { LogProtoServer *proto; proto_server_options.max_msg_size = 32; proto = log_proto_framed_server_new( log_transport_mock_stream_new( "32 0123456789ABCDEF0123456789ABCDEF", -1, LTM_INJECT_ERROR(EIO), LTM_EOF), get_inited_proto_server_options()); assert_proto_server_fetch(proto, "0123456789ABCDEF0123456789ABCDEF", -1); assert_proto_server_fetch_failure(proto, LPS_ERROR, "Error reading RFC6587 style framed data"); log_proto_server_free(proto); }
static void log_reader_apply_proto_and_poll_events(LogReader *self, LogProtoServer *proto, PollEvents *poll_events) { if (self->proto) log_proto_server_free(self->proto); if (self->poll_events) poll_events_free(self->poll_events); self->proto = proto; if (self->proto) log_proto_server_set_wakeup_cb(self->proto, (LogProtoServerWakeupFunc) log_reader_wakeup, self); self->poll_events = poll_events; }
static void test_log_proto_text_server_partial_chars_before_eof(void) { LogProtoServer *proto; log_proto_server_options_set_encoding(&proto_server_options, "utf-8"); proto = construct_test_proto( log_transport_mock_stream_new( /* utf8 */ "\xc3", -1, LTM_EOF)); assert_true(log_proto_server_validate_options(proto), "validate_options() returned failure but it should have succeeded"); assert_proto_server_fetch_failure(proto, LPS_EOF, "EOF read on a channel with leftovers from previous character conversion, dropping input"); log_proto_server_free(proto); }
Test(log_proto, test_log_proto_framed_server_too_long_line_trimmed_one_big_message) { /* Input is bigger than the buffer size. With a small and a bigger (expected to be trimmed) message. * There is a small message and a large message.*/ LogProtoServer *proto; proto_server_options.max_msg_size = 10; proto_server_options.trim_large_messages = TRUE; proto = log_proto_framed_server_new( log_transport_mock_stream_new( "2 ab16 0123456789ABCDEF", -1, LTM_EOF), get_inited_proto_server_options()); assert_proto_server_fetch(proto, "ab", 2); assert_proto_server_fetch(proto, "0123456789", 10); log_proto_server_free(proto); }
Test(log_proto, test_log_proto_framed_server_message_exceeds_buffer) { LogProtoServer *proto; /* should cause the buffer to be extended, shifted, as the first message * resizes the buffer to 16+10 == 26 bytes. */ proto_server_options.max_msg_size = 32; proto = log_proto_framed_server_new( log_transport_mock_records_new( "16 0123456789ABCDE\n16 0123456789ABCDE\n", -1, LTM_EOF), get_inited_proto_server_options()); assert_proto_server_fetch(proto, "0123456789ABCDE\n", -1); assert_proto_server_fetch(proto, "0123456789ABCDE\n", -1); log_proto_server_free(proto); }
static void log_reader_free(LogPipe *s) { LogReader *self = (LogReader *) s; if (self->proto) { log_proto_server_free(self->proto); self->proto = NULL; } log_pipe_unref(self->control); g_sockaddr_unref(self->peer_addr); g_free(self->follow_filename); g_static_mutex_free(&self->pending_proto_lock); g_cond_free(self->pending_proto_cond); log_source_free(s); }
Test(log_proto, test_log_proto_framed_server_too_long_line_trimmed) { LogProtoServer *proto; /* the simplest trimming scenario as a base test */ proto_server_options.max_msg_size = 32; proto_server_options.trim_large_messages = TRUE; proto = log_proto_framed_server_new( log_transport_mock_stream_new( "48 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF", -1, LTM_EOF), get_inited_proto_server_options()); assert_proto_server_fetch(proto, "0123456789ABCDEF0123456789ABCDEF", 32); assert_proto_server_fetch_failure(proto, LPS_EOF, NULL); log_proto_server_free(proto); }
static void test_log_proto_text_server_no_eol_before_eof(void) { LogProtoServer *proto; proto = construct_test_proto( log_transport_mock_stream_new( /* no eol before EOF */ "01234567", -1, LTM_EOF)); assert_proto_server_fetch(proto, "01234567", -1); assert_proto_server_fetch_failure(proto, LPS_EOF, NULL); log_proto_server_free(proto); }
static void test_log_proto_text_server_eol_before_eof(void) { LogProtoServer *proto; proto = construct_test_proto( log_transport_mock_records_new( /* eol before EOF */ "01234\n567\n890\n", -1, LTM_INJECT_ERROR(EIO), LTM_EOF)); assert_proto_server_fetch(proto, "01234", -1); assert_proto_server_fetch(proto, "567", -1); assert_proto_server_fetch(proto, "890", -1); assert_proto_server_fetch_failure(proto, LPS_ERROR, NULL); log_proto_server_free(proto); }
static void test_log_proto_dgram_server_invalid_ucs4(void) { LogProtoServer *proto; proto_server_options.max_msg_size = 32; log_proto_server_options_set_encoding(&proto_server_options, "ucs-4"); proto = log_proto_dgram_server_new( /* 31 bytes record size */ log_transport_mock_endless_records_new( /* invalid ucs4, trailing zeroes at the end */ "\x00\x00\x00\xe1\x00\x00\x00\x72\x00\x00\x00\x76\x00\x00\x00\xed" /* |...á...r...v...í| */ "\x00\x00\x00\x7a\x00\x00\x00\x74\x00\x00\x01\x71\x00\x00\x00", 31, /* |...z...t...ű...r| */ LTM_EOF), get_inited_proto_server_options()); assert_proto_server_fetch_failure(proto, LPS_ERROR, "Byte sequence too short, cannot convert an individual frame in its entirety"); log_proto_server_free(proto); }
static void test_log_proto_text_server_accumulation_terminated_if_buffer_full(gboolean input_is_stream) { LogProtoServer *proto; accumulate_seq = 0; proto = construct_test_proto_with_accumulator( accumulator_join_continuation_lines, (input_is_stream ? log_transport_mock_stream_new : log_transport_mock_records_new)( "0123456789abcdef\n" " 0123456789abcdef\n" " continuation\n", -1, LTM_EOF)); assert_proto_server_fetch(proto, "0123456789abcdef\n 0123456789abcd", -1); assert_proto_server_fetch(proto, "ef\n continuation", -1); log_proto_server_free(proto); }
static void test_log_proto_text_server_not_fixed_encoding(void) { LogProtoServer *proto; log_proto_server_options_set_encoding(&proto_server_options, "utf-8"); /* to test whether a non-easily-reversable charset works too */ proto = construct_test_proto( log_transport_mock_stream_new( /* utf8 */ "árvíztűrőtükörfúrógép\n", -1, LTM_EOF)); assert_true(log_proto_server_validate_options(proto), "validate_options() returned failure but it should have succeeded"); assert_proto_server_fetch(proto, "árvíztűrőtükörfúrógép", -1); assert_proto_server_fetch_failure(proto, LPS_EOF, NULL); log_proto_server_free(proto); }
static void test_log_proto_text_server_multi_read(void) { LogProtoServer *proto; proto = construct_test_proto( log_transport_mock_records_new( "foobar\n", -1, /* no EOL, proto implementation would read another chunk */ "foobaz", -1, LTM_INJECT_ERROR(EIO), LTM_EOF)); assert_proto_server_fetch(proto, "foobar", -1); assert_proto_server_fetch(proto, "foobaz", -1); assert_proto_server_fetch_failure(proto, LPS_ERROR, NULL); log_proto_server_free(proto); }
static void test_log_proto_text_server_invalid_encoding(void) { LogProtoServer *proto; gboolean success; log_proto_server_options_set_encoding(&proto_server_options, "never-ever-is-going-to-be-such-an-encoding"); proto = construct_test_proto( log_transport_mock_stream_new( "", -1, LTM_EOF)); start_grabbing_messages(); success = log_proto_server_validate_options(proto); assert_grabbed_messages_contain("Unknown character set name specified; encoding='never-ever-is-going-to-be-such-an-encoding'", "message about unknown charset missing"); assert_false(success, "validate_options() returned success but it should have failed"); log_proto_server_free(proto); }
static void test_log_proto_text_server_iso8859_2(void) { LogProtoServer *proto; log_proto_server_options_set_encoding(&proto_server_options, "iso-8859-2"); proto = construct_test_proto( log_transport_mock_stream_new( /* iso-8859-2 */ "\xe1\x72\x76\xed\x7a\x74\xfb\x72\xf5\x74\xfc\x6b\xf6\x72\x66\xfa" /* |árvíztűrőtükörfú| */ "\x72\xf3\x67\xe9\x70\n", -1, /* |rógép| */ LTM_EOF)); assert_true(log_proto_server_validate_options(proto), "validate_options() returned failure but it should have succeeded"); assert_proto_server_fetch(proto, "árvíztűrőtükörfúrógép", -1); assert_proto_server_fetch_failure(proto, LPS_EOF, NULL); log_proto_server_free(proto); }
static void test_log_proto_text_server_accumulation_terminated_if_input_is_closed(gboolean input_is_stream) { LogProtoServer *proto; accumulate_seq = 0; proto = construct_test_proto_with_accumulator( accumulator_join_continuation_lines, (input_is_stream ? log_transport_mock_stream_new : log_transport_mock_records_new)( "0 line\n" " line\n" "1 line\n", -1, LTM_EOF)); assert_proto_server_fetch(proto, "0 line\n line", -1); assert_proto_server_fetch(proto, "1 line", -1); log_proto_server_free(proto); }