terom@185: /* terom@185: * Test interoperability of tcp_client/tcp_server terom@185: */ terom@185: #include "../tcp.h" terom@185: #include "test.h" terom@185: terom@185: struct test_tcp_ctx { terom@185: service_t *service; terom@185: bool on_service_error; terom@185: bool on_client_connect; terom@185: bool on_service_client_error; terom@185: terom@185: transport_t *service_client, *client; terom@185: terom@185: char data; terom@185: terom@185: bool eof; terom@185: }; terom@185: terom@185: static void on_service_error (service_t *service, const error_t *err, void *arg) terom@185: { terom@185: struct test_tcp_ctx *ctx = arg; terom@185: terom@185: log_debug("%s", error_msg(err)); terom@185: terom@185: assert(service == ctx->service); terom@185: assert(!ctx->on_service_error); terom@185: terom@185: ctx->on_service_error = true; terom@185: } terom@185: terom@185: static void on_service_client_connect (transport_t *transport, void *arg) terom@185: { terom@185: struct test_tcp_ctx *ctx = arg; terom@185: terom@185: log_debug("%p", transport); terom@185: terom@185: assert(!ctx->service_client); terom@185: terom@185: ctx->service_client = transport; terom@185: } terom@185: terom@185: static void on_service_client_read (transport_t *transport, void *arg) terom@185: { terom@185: struct test_tcp_ctx *ctx = arg; terom@185: char byte; terom@185: int ret; terom@185: error_t err; terom@185: terom@185: log_debug("%p", transport); terom@185: terom@185: assert(ctx->service_client == transport); terom@185: terom@185: if ((ret = transport_read(transport, &byte, sizeof(byte), &err)) == 1) { terom@185: assert(byte == ctx->data); terom@185: terom@185: ctx->data = 0; terom@185: terom@185: } else if (ERROR_CODE(&err) == ERR_EOF) { terom@185: assert(ctx->eof); terom@185: terom@185: ctx->eof = false; terom@185: terom@185: } else { terom@185: FATAL_ERROR(&err, "xxx"); terom@185: } terom@185: } terom@185: terom@185: static void on_service_client_error (transport_t *transport, const error_t *err, void *arg) terom@185: { terom@185: struct test_tcp_ctx *ctx = arg; terom@185: terom@185: log_debug("%p: %s", transport, error_msg(err)); terom@185: terom@185: assert(ctx->service_client = transport); terom@185: terom@185: ctx->on_service_client_error = true; terom@185: } terom@185: terom@185: static void on_client_connect (transport_t *transport, void *arg) terom@185: { terom@185: struct test_tcp_ctx *ctx = arg; terom@185: terom@185: log_debug("%p", transport); terom@185: terom@185: assert(transport == ctx->client); terom@185: terom@185: ctx->on_client_connect = true; terom@185: } terom@185: terom@185: static void on_client_read (transport_t *transport, void *arg) terom@185: { terom@185: struct test_tcp_ctx *ctx = arg; terom@185: char byte; terom@185: int ret; terom@185: error_t err; terom@185: terom@185: log_debug("%p", transport); terom@185: terom@185: assert(transport == ctx->client); terom@185: terom@185: if ((ret = transport_read(transport, &byte, sizeof(byte), &err)) == 1) { terom@185: assert(byte == ctx->data); terom@185: terom@185: ctx->data = 0; terom@185: terom@185: } else if (ERROR_CODE(&err) == ERR_EOF) { terom@185: assert(ctx->eof); terom@185: terom@185: ctx->eof = false; terom@185: terom@185: } else { terom@185: FATAL_ERROR(&err, "xxx"); terom@185: } terom@185: } terom@185: terom@185: static void on_client_error (transport_t *transport, const error_t *err, void *arg) terom@185: { terom@185: struct test_tcp_ctx *ctx = arg; terom@185: terom@185: log_debug("%p", transport); terom@185: terom@185: assert(transport == ctx->client); terom@185: terom@185: // XXX terom@185: } terom@185: terom@185: static struct service_callbacks test_tcp_service_callbacks = { terom@185: .on_error = on_service_error, terom@185: }; terom@185: terom@185: static struct transport_callbacks test_tcp_service_transport_callbacks = { terom@185: .on_connect = on_service_client_connect, terom@185: .on_read = on_service_client_read, terom@185: .on_write = NULL, terom@185: .on_error = on_service_client_error, terom@185: }; terom@185: terom@185: static struct transport_callbacks test_tcp_client_callbacks = { terom@185: .on_connect = on_client_connect, terom@185: .on_read = on_client_read, terom@185: .on_error = on_client_error, terom@185: }; terom@185: terom@185: void test_tcp (void) terom@185: { terom@185: struct test_tcp_ctx ctx; memset(&ctx, 0, sizeof(ctx)); terom@185: struct service_info serv_info = { terom@185: &test_tcp_service_callbacks, &ctx, terom@185: { &test_tcp_service_transport_callbacks, &ctx, TRANSPORT_READ } terom@185: }; terom@185: struct transport_info client_info = { terom@185: &test_tcp_client_callbacks, &ctx, TRANSPORT_READ terom@185: }; terom@185: struct event_base *ev_base = _test_ctx.ev_base; terom@185: error_t err; terom@185: terom@185: // create the service terom@185: assert_success(tcp_listen(&serv_info, &ctx.service, "localhost", "3232", &err)); terom@185: terom@185: // connect client -> server terom@185: assert_success(tcp_connect(&client_info, &ctx.client, "localhost", "3232", &err)); terom@185: event_base_loop(ev_base, EVLOOP_ONCE); terom@185: assert(ctx.service_client); terom@185: assert(ctx.on_client_connect); terom@185: terom@185: // send client -> server terom@185: ctx.data = 'A'; terom@185: terom@185: assert(transport_write(ctx.client, &ctx.data, sizeof(ctx.data), &err) == 1); terom@185: event_base_loop(ev_base, EVLOOP_ONCE); terom@185: assert(!ctx.data); terom@185: terom@185: // send server -> client terom@185: ctx.data = 'B'; terom@185: terom@185: assert(transport_write(ctx.service_client, &ctx.data, sizeof(ctx.data), &err) == 1); terom@185: event_base_loop(ev_base, EVLOOP_ONCE); terom@185: assert(!ctx.data); terom@185: terom@185: // close client-side connection terom@185: ctx.eof = true; terom@185: transport_destroy(ctx.client); terom@185: event_base_loop(ev_base, EVLOOP_ONCE); terom@185: assert(ctx.on_service_client_error || !ctx.eof); terom@185: terom@185: // cleanup terom@185: transport_destroy(ctx.service_client); terom@185: service_destroy(ctx.service); terom@185: } terom@185: