add a crude test_tcp, fix some tcp_server bugs, add missing service_destroy function
--- a/src/service.c Thu May 07 18:11:50 2009 +0300
+++ b/src/service.c Thu May 07 18:48:38 2009 +0300
@@ -23,3 +23,13 @@
// just call the user callback
service->info.cb_tbl->on_error(service, err, service->info.cb_arg);
}
+
+void service_destroy (service_t *service)
+{
+ const struct service_type *type = object_type(&service->base_obj, &service_type_type);
+
+ // invoke method
+ type->methods.deinit(service);
+
+ free(service);
+}
--- a/src/tcp_server.c Thu May 07 18:11:50 2009 +0300
+++ b/src/tcp_server.c Thu May 07 18:48:38 2009 +0300
@@ -19,7 +19,7 @@
*/
const struct service_type tcp_server_type = {
.base_type = {
- .parent = NULL,
+ .parent = &service_type_type,
},
.methods = {
.deinit = tcp_server__deinit,
@@ -99,7 +99,7 @@
evutil_socket_t sock;
// create the sock
- if ((sock = tcp_sock_create(addr, err)))
+ if ((sock = tcp_sock_create(addr, err)) < 0)
goto error;
// bind it
@@ -245,6 +245,8 @@
// ok
*service_ptr = &serv->base_service;
+ return SUCCESS;
+
error:
tcp_server_destroy(serv);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/test/tcp.c Thu May 07 18:48:38 2009 +0300
@@ -0,0 +1,191 @@
+/*
+ * 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);
+}
+
--- a/src/test/test_list.inc Thu May 07 18:11:50 2009 +0300
+++ b/src/test/test_list.inc Thu May 07 18:48:38 2009 +0300
@@ -31,6 +31,8 @@
TEST ( transport_test )
+TEST ( tcp )
+
TEST ( line_proto )
TEST ( irc_queue )