src/test/tcp.c
author Tero Marttila <terom@fixme.fi>
Thu, 28 May 2009 01:17:36 +0300
branchnew-lib-errors
changeset 219 cefec18b8268
parent 185 259b5841a0e6
permissions -rw-r--r--
some of the lib/transport stuff compiles
/*
 * Test interoperability of tcp_client/tcp_server
 */
#include "../tcp.h"
#include "test.h"

struct test_tcp_ctx {
    service_t *service;
    bool on_service_error;
    bool on_client_connect;
    bool on_service_client_error;

    transport_t *service_client, *client;

    char data;

    bool eof;
};

static void on_service_error (service_t *service, const error_t *err, void *arg)
{
    struct test_tcp_ctx *ctx = arg;

    log_debug("%s", error_msg(err));

    assert(service == ctx->service);
    assert(!ctx->on_service_error);
   
    ctx->on_service_error = true;
}

static void on_service_client_connect (transport_t *transport, void *arg)
{
    struct test_tcp_ctx *ctx = arg;

    log_debug("%p", transport);

    assert(!ctx->service_client);

    ctx->service_client = transport;
}

static void on_service_client_read (transport_t *transport, void *arg)
{
    struct test_tcp_ctx *ctx = arg;
    char byte;
    int ret;
    error_t err;

    log_debug("%p", transport);

    assert(ctx->service_client == transport);

    if ((ret = transport_read(transport, &byte, sizeof(byte), &err)) == 1) {
        assert(byte == ctx->data);

        ctx->data = 0;

    } else if (ERROR_CODE(&err) == ERR_EOF) {
        assert(ctx->eof);

        ctx->eof = false;

    } else {
        FATAL_ERROR(&err, "xxx");
    }
}

static void on_service_client_error (transport_t *transport, const error_t *err, void *arg)
{
    struct test_tcp_ctx *ctx = arg;

    log_debug("%p: %s", transport, error_msg(err));
    
    assert(ctx->service_client = transport);

    ctx->on_service_client_error = true;
}

static void on_client_connect (transport_t *transport, void *arg)
{
    struct test_tcp_ctx *ctx = arg;

    log_debug("%p", transport);

    assert(transport == ctx->client);

    ctx->on_client_connect = true;
}

static void on_client_read (transport_t *transport, void *arg)
{
    struct test_tcp_ctx *ctx = arg;
    char byte;
    int ret;
    error_t err;

    log_debug("%p", transport);

    assert(transport == ctx->client);

    if ((ret = transport_read(transport, &byte, sizeof(byte), &err)) == 1) {
        assert(byte == ctx->data);

        ctx->data = 0;

    } else if (ERROR_CODE(&err) == ERR_EOF) {
        assert(ctx->eof);
        
        ctx->eof = false;

    } else {
        FATAL_ERROR(&err, "xxx");
    }
}

static void on_client_error (transport_t *transport, const error_t *err, void *arg)
{
    struct test_tcp_ctx *ctx = arg;

    log_debug("%p", transport);

    assert(transport == ctx->client);

    // XXX
}

static struct service_callbacks test_tcp_service_callbacks = {
    .on_error   = on_service_error,
};

static struct transport_callbacks test_tcp_service_transport_callbacks = {
    .on_connect = on_service_client_connect,
    .on_read    = on_service_client_read,
    .on_write   = NULL,
    .on_error   = on_service_client_error,
};

static struct transport_callbacks test_tcp_client_callbacks = {
    .on_connect = on_client_connect,
    .on_read    = on_client_read,
    .on_error   = on_client_error,
};

void test_tcp (void)
{
    struct test_tcp_ctx ctx; memset(&ctx, 0, sizeof(ctx));
    struct service_info serv_info = { 
        &test_tcp_service_callbacks, &ctx, 
        { &test_tcp_service_transport_callbacks, &ctx, TRANSPORT_READ } 
    };
    struct transport_info client_info = {
        &test_tcp_client_callbacks, &ctx, TRANSPORT_READ
    };
    struct event_base *ev_base = _test_ctx.ev_base;
    error_t err;
    
    // create the service
    assert_success(tcp_listen(&serv_info, &ctx.service, "localhost", "3232", &err));
    
    // connect client -> server
    assert_success(tcp_connect(&client_info, &ctx.client, "localhost", "3232", &err));
    event_base_loop(ev_base, EVLOOP_ONCE);
    assert(ctx.service_client);
    assert(ctx.on_client_connect);

    // send client -> server
    ctx.data = 'A';

    assert(transport_write(ctx.client, &ctx.data, sizeof(ctx.data), &err) == 1);
    event_base_loop(ev_base, EVLOOP_ONCE);
    assert(!ctx.data);
    
    // send server -> client
    ctx.data = 'B';

    assert(transport_write(ctx.service_client, &ctx.data, sizeof(ctx.data), &err) == 1);
    event_base_loop(ev_base, EVLOOP_ONCE);
    assert(!ctx.data);
    
    // close client-side connection
    ctx.eof = true;
    transport_destroy(ctx.client);
    event_base_loop(ev_base, EVLOOP_ONCE);
    assert(ctx.on_service_client_error || !ctx.eof);

    // cleanup
    transport_destroy(ctx.service_client);
    service_destroy(ctx.service);
}