Added SILC Buffer Stream API
[runtime.git] / lib / silcutil / tests / test_silcbufferstream.c
diff --git a/lib/silcutil/tests/test_silcbufferstream.c b/lib/silcutil/tests/test_silcbufferstream.c
new file mode 100644 (file)
index 0000000..488a4de
--- /dev/null
@@ -0,0 +1,377 @@
+/* SILC Buffer Stream tests */
+
+#include "silcruntime.h"
+
+SilcSchedule schedule;
+
+typedef struct {
+  SilcFSM fsm;
+  SilcFSMEventStruct sema;
+  SilcFSMEventStruct s_sema;
+  SilcFSMEventStruct c_sema;
+  SilcFSMThreadStruct thread;
+  SilcNetListener server;
+  SilcStream client_stream;
+  SilcStream cbuf;
+  int c_num_buf;
+  SilcResult client_status;
+  SilcStream server_stream;
+  SilcStream sbuf;
+  int s_num_buf;
+  SilcResult server_status;
+  SilcBool success;
+} *Foo;
+
+SILC_FSM_STATE(test_st_start);
+SILC_FSM_STATE(test_st_second);
+SILC_FSM_STATE(test_st_finish);
+
+SILC_FSM_STATE(test_st_connect);
+SILC_FSM_STATE(test_st_connected);
+
+SILC_FSM_STATE(test_st_s_send_buffers);
+SILC_FSM_STATE(test_st_s_receive_buffers);
+SILC_FSM_STATE(test_st_c_send_buffers);
+SILC_FSM_STATE(test_st_c_receive_buffers);
+
+static void test_accept_connection(SilcResult status, SilcStream stream,
+                                  void *context)
+{
+  Foo f = context;
+  SILC_LOG_DEBUG(("Accepted new connection"));
+  f->client_status = status;
+  f->client_stream = stream;
+  SILC_FSM_EVENT_SIGNAL(&f->sema);
+}
+
+static void test_connected(SilcResult status, SilcStream stream,
+                          void *context)
+{
+  Foo f = context;
+  SILC_LOG_DEBUG(("Connected to server"));
+  f->server_status = status;
+  f->server_stream = stream;
+  SILC_FSM_CALL_CONTINUE(&f->thread);
+}
+
+static void receive_s_buffer(SilcResult status, SilcStream stream,
+                            SilcBuffer buffer, void *context)
+{
+  Foo f = context;
+  SILC_LOG_DEBUG(("Received buffer"));
+  silc_buffer_free(buffer);
+  SILC_FSM_EVENT_SIGNAL(&f->s_sema);
+}
+
+static void receive_c_buffer(SilcResult status, SilcStream stream,
+                            SilcBuffer buffer, void *context)
+{
+  Foo f = context;
+  SILC_LOG_DEBUG(("Received buffer"));
+  silc_buffer_free(buffer);
+  SILC_FSM_EVENT_SIGNAL(&f->c_sema);
+}
+
+SILC_FSM_STATE(test_st_connect)
+{
+  Foo f = fsm_context;
+
+  SILC_LOG_DEBUG(("test_st_connect"));
+  SILC_LOG_DEBUG(("Connecting to server"));
+
+  silc_fsm_next(fsm, test_st_connected);
+  SILC_FSM_CALL(silc_net_tcp_connect(NULL, "localhost", 5000,
+                                    silc_fsm_get_schedule(fsm),
+                                    test_connected, f));
+}
+
+SILC_FSM_STATE(test_st_connected)
+{
+  Foo f = fsm_context;
+  const char *host, *ip;
+  SilcUInt16 port;
+
+  SILC_LOG_DEBUG(("test_st_connected"));
+
+  if (f->server_status != SILC_OK) {
+    SILC_LOG_DEBUG(("Creating connection failed"));
+    return SILC_FSM_FINISH;
+  }
+
+  silc_socket_stream_get_info(f->server_stream, NULL, &host, &ip, &port);
+  SILC_LOG_DEBUG(("Connected to server %s, %s:%d", host, ip, port));
+
+  f->sbuf = silc_buffer_stream_create(f->server_stream,
+                                     receive_c_buffer, f);
+  if (!f->sbuf) {
+    silc_fsm_next(fsm, test_st_finish);
+    return SILC_FSM_CONTINUE;
+  }
+
+  silc_fsm_next(fsm, test_st_c_receive_buffers);
+  return SILC_FSM_CONTINUE;
+}
+
+SILC_FSM_STATE(test_st_start)
+{
+  Foo f = fsm_context;
+  int ports[3];
+  SilcUInt16 *ret_ports;
+  SilcUInt32 port_count;
+
+  SILC_LOG_DEBUG(("test_st_start"));
+
+  SILC_LOG_DEBUG(("Creating network listener to ports 2000, 3000 and 4000"));
+  ports[0] = 2000;
+  ports[1] = 3000;
+  ports[2] = 4000;
+  f->server = silc_net_tcp_create_listener2(NULL, ports, 3, FALSE, TRUE, TRUE,
+                                    silc_fsm_get_schedule(fsm),
+                                    test_accept_connection, f);
+  if (!f->server) {
+    /** Creating network listener failed */
+    SILC_LOG_DEBUG(("Listener creation failed"));
+    silc_fsm_next(fsm, test_st_finish);
+    return SILC_FSM_CONTINUE;
+  }
+
+  ret_ports = silc_net_listener_get_port(f->server, &port_count);
+  if (!ret_ports) {
+    SILC_LOG_DEBUG(("Listener does not work"));
+    silc_fsm_next(fsm, test_st_finish);
+    return SILC_FSM_CONTINUE;
+  }
+  SILC_LOG_DEBUG(("Bound to port %d", ret_ports[0]));
+  SILC_LOG_DEBUG(("Bound to port %d", ret_ports[1]));
+  SILC_LOG_DEBUG(("Bound to port %d", ret_ports[2]));
+  silc_free(ret_ports);
+
+  /* Close this listener and create new one */
+  silc_net_close_listener(f->server);
+
+  SILC_LOG_DEBUG(("Creating network listener"));
+  f->server = silc_net_tcp_create_listener(NULL, 0, 5000, TRUE, TRUE,
+                                    silc_fsm_get_schedule(fsm),
+                                    test_accept_connection, f);
+  if (!f->server) {
+    /** Creating network listener failed */
+    SILC_LOG_DEBUG(("Listener creation failed"));
+    silc_fsm_next(fsm, test_st_finish);
+    return SILC_FSM_CONTINUE;
+  }
+
+  /* Create thread to connect to the listener */
+  silc_fsm_thread_init(&f->thread, fsm, f, NULL, NULL, FALSE);
+  silc_fsm_start(&f->thread, test_st_connect);
+
+  /** Start waiting connection */
+  SILC_LOG_DEBUG(("Start waiting for incoming connections"));
+  silc_fsm_event_init(&f->sema, fsm);
+  silc_fsm_next(fsm, test_st_second);
+  return SILC_FSM_CONTINUE;
+}
+
+SILC_FSM_STATE(test_st_second)
+{
+  Foo f = fsm_context;
+  const char *ip, *host;
+  SilcUInt16 port;
+
+  SILC_LOG_DEBUG(("test_st_second"));
+
+  SILC_FSM_EVENT_WAIT(&f->sema);
+
+  if (f->client_status != SILC_OK) {
+    /** Accepting new connection failed */
+    SILC_LOG_DEBUG(("Accepting failed %d", f->client_status));
+    silc_fsm_next(fsm, test_st_finish);
+    return SILC_FSM_CONTINUE;
+  }
+
+  silc_socket_stream_get_info(f->client_stream, NULL, &host, &ip, &port);
+  SILC_LOG_DEBUG(("Accepted new connection %s, %s:%d", host, ip, port));
+
+  f->cbuf = silc_buffer_stream_create(f->client_stream,
+                                     receive_s_buffer, f);
+  if (!f->cbuf) {
+    silc_fsm_next(fsm, test_st_finish);
+    return SILC_FSM_CONTINUE;
+  }
+
+  silc_fsm_next(fsm, test_st_s_send_buffers);
+  return SILC_FSM_CONTINUE;
+}
+
+SILC_FSM_STATE(test_st_s_send_buffers)
+{
+  Foo f = fsm_context;
+  SilcBuffer buffer;
+  int i;
+
+  SILC_LOG_DEBUG(("test_st_s_send_buffers"));
+
+  for (i = 0; i < 10; i++) {
+    buffer = silc_buffer_alloc_size(99 * (i + 1));
+    if (!buffer) {
+      silc_fsm_next(fsm, test_st_finish);
+      return SILC_FSM_CONTINUE;
+    }
+
+    SILC_LOG_HEXDUMP(("Send buffer %d to client", i + 1),
+                    silc_buffer_data(buffer), silc_buffer_len(buffer));
+
+    if (!silc_buffer_stream_send(f->cbuf, buffer)) {
+      silc_fsm_next(fsm, test_st_finish);
+      return SILC_FSM_CONTINUE;
+    }
+
+    silc_buffer_free(buffer);
+  }
+
+  silc_fsm_next(fsm, test_st_s_receive_buffers);
+  return SILC_FSM_CONTINUE;
+}
+
+SILC_FSM_STATE(test_st_s_receive_buffers)
+{
+  Foo f = fsm_context;
+
+  SILC_LOG_DEBUG(("test_st_s_receive_buffers"));
+
+  SILC_FSM_EVENT_WAIT(&f->s_sema);
+
+  f->s_num_buf++;
+  SILC_LOG_DEBUG(("Received buffer %d", f->s_num_buf));
+  if (f->s_num_buf < 10)
+    return SILC_FSM_CONTINUE;
+
+  /** Wait thread to terminate */
+  f->success = TRUE;
+  silc_fsm_next(fsm, test_st_finish);
+  return SILC_FSM_CONTINUE;
+}
+
+SILC_FSM_STATE(test_st_c_receive_buffers)
+{
+  Foo f = fsm_context;
+
+  SILC_LOG_DEBUG(("test_st_c_receive_buffers"));
+
+  SILC_FSM_EVENT_WAIT(&f->c_sema);
+
+  f->c_num_buf++;
+  SILC_LOG_DEBUG(("Received buffer %d", f->c_num_buf));
+  if (f->c_num_buf < 10)
+    return SILC_FSM_CONTINUE;
+
+  silc_fsm_next(fsm, test_st_c_send_buffers);
+  return SILC_FSM_CONTINUE;
+}
+
+SILC_FSM_STATE(test_st_c_send_buffers)
+{
+  Foo f = fsm_context;
+  SilcBuffer buffer;
+  int i;
+
+  SILC_LOG_DEBUG(("test_st_c_send_buffers"));
+
+  for (i = 0; i < 10; i++) {
+    buffer = silc_buffer_alloc_size(13 * (i + 1));
+    if (!buffer)
+      continue;
+
+    SILC_LOG_HEXDUMP(("Send buffer %d to server", i + 1),
+                    silc_buffer_data(buffer), silc_buffer_len(buffer));
+
+    if (!silc_buffer_stream_send(f->sbuf, buffer)) {
+      silc_fsm_next(fsm, test_st_finish);
+      return SILC_FSM_CONTINUE;
+    }
+
+    silc_buffer_free(buffer);
+  }
+
+  return SILC_FSM_FINISH;
+}
+
+SILC_FSM_STATE(test_st_finish)
+{
+  Foo f = fsm_context;
+
+  SILC_LOG_DEBUG(("test_st_finish"));
+
+  if (f->sbuf)
+    silc_stream_destroy(f->sbuf);
+  if (f->cbuf)
+    silc_stream_destroy(f->cbuf);
+  if (f->server_stream) {
+    silc_stream_close(f->server_stream);
+    silc_stream_destroy(f->server_stream);
+  }
+  if (f->client_stream) {
+    silc_stream_close(f->client_stream);
+    silc_stream_destroy(f->client_stream);
+  }
+
+  SILC_LOG_DEBUG(("Closing network listener"));
+  silc_net_close_listener(f->server);
+
+  SILC_LOG_DEBUG(("Finish machine"));
+  return SILC_FSM_FINISH;
+}
+
+static void destructor(SilcFSM fsm, void *fsm_context,
+                      void *destructor_context)
+{
+  SILC_LOG_DEBUG(("FSM destructor, stopping scheduler"));
+  silc_fsm_free(fsm);
+  silc_schedule_stop(schedule);
+}
+
+int main(int argc, char **argv)
+{
+  SilcBool success = FALSE;
+  SilcFSM fsm;
+  Foo f;
+
+  if (argc > 1 && !strcmp(argv[1], "-d")) {
+    silc_log_debug(TRUE);
+    silc_log_debug_hexdump(TRUE);
+    silc_log_set_debug_string("*net*,*stream*,*errno*");
+  }
+
+  SILC_LOG_DEBUG(("Allocating scheduler"));
+  schedule = silc_schedule_init(0, NULL, NULL, NULL);
+
+  f = silc_calloc(1, sizeof(*f));
+  if (!f)
+    goto err;
+
+  SILC_LOG_DEBUG(("Allocating FSM context"));
+  fsm = silc_fsm_alloc(f, destructor, NULL, schedule);
+  if (!fsm)
+    goto err;
+  silc_fsm_start(fsm, test_st_start);
+  f->fsm = fsm;
+
+  silc_fsm_event_init(&f->s_sema, fsm);
+  silc_fsm_event_init(&f->c_sema, fsm);
+
+  SILC_LOG_DEBUG(("Running scheduler"));
+  silc_schedule(schedule);
+
+  if (!f->success)
+    goto err;
+
+  silc_schedule_uninit(schedule);
+  silc_free(f);
+
+  success = TRUE;
+
+ err:
+  SILC_LOG_DEBUG(("Testing was %s", success ? "SUCCESS" : "FAILURE"));
+  fprintf(stderr, "Testing was %s\n", success ? "SUCCESS" : "FAILURE");
+
+  return !success;
+}