summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShibata Makoto <shibata@mac.tec.toyota.co.jp>2013-07-17 19:44:53 +0900
committerShibata Makoto <shibata@mac.tec.toyota.co.jp>2013-07-17 19:47:16 +0900
commitde598a444a2dba333c90eca39ea6734a09be3300 (patch)
treeb06442c253f8d9d1fe88396c7438843c1e80ca4d
downloadico-uxf-utilities-de598a444a2dba333c90eca39ea6734a09be3300.tar.gz
ico-uxf-utilities-de598a444a2dba333c90eca39ea6734a09be3300.tar.bz2
ico-uxf-utilities-de598a444a2dba333c90eca39ea6734a09be3300.zip
Import initial.
Change-Id: I4f2d6a1747e069582626f68346ae97744a5584c4 Signed-off-by: Shibata Makoto <shibata@mac.tec.toyota.co.jp>
-rw-r--r--Makefile.am4
-rwxr-xr-xautogen.sh9
-rw-r--r--configure.ac45
-rw-r--r--include/ico_uws.h198
-rw-r--r--include/ico_uws_private.h180
-rw-r--r--packaging/ico-uxf-utilities.changes2
-rw-r--r--packaging/ico-uxf-utilities.spec58
-rw-r--r--src/Makefile.am17
-rw-r--r--src/ico_uws.c1410
-rw-r--r--test/Makefile.am37
-rwxr-xr-xtest/run_test.sh331
-rw-r--r--test/tst_ico_uws.h41
-rw-r--r--test/tst_ico_uws_client.c368
-rw-r--r--test/tst_ico_uws_multi_client.c548
-rw-r--r--test/tst_ico_uws_multi_server.c541
-rw-r--r--test/tst_ico_uws_server.c328
16 files changed, 4117 insertions, 0 deletions
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..0b75466
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,4 @@
+SUBDIRS = src test
+
+DIST_SUBDIRS = src test
+
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..916169a
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,9 @@
+#! /bin/sh
+
+test -n "$srcdir" || srcdir=`dirname "$0"`
+test -n "$srcdir" || srcdir=.
+(
+ cd "$srcdir" &&
+ autoreconf --force -v --install
+) || exit
+test -n "$NOCONFIGURE" || "$srcdir/configure" "$@"
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..40e85fd
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,45 @@
+AC_PREREQ([2.68])
+AC_INIT([ico-uxf-utilities],
+ [0.2.01],
+ [https://BUG-REPORT-ADDRESS])
+
+AC_CONFIG_HEADERS([config.h])
+
+AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz])
+
+AM_SILENT_RULES([yes])
+
+# Check for programs
+AC_PROG_CC
+
+# Initialize libtool
+LT_PREREQ([2.2])
+LT_INIT([disable-static])
+
+PKG_PROG_PKG_CONFIG()
+
+PKG_CHECK_MODULES([GLIB], [glib-2.0])
+PKG_CHECK_MODULES([DLOG], [dlog])
+OPT_CFLAGS="$GLIB_CFLAGS $DLOG_CFLAGS"
+OPT_LIBS="$GLIB_LIBS $DLOG_LIBS"
+AC_SUBST(OPT_CFLAGS)
+AC_SUBST(OPT_LIBS)
+
+AC_CHECK_HEADERS([execinfo.h])
+
+AC_CHECK_FUNCS([mkostemp strchrnul])
+
+if test "x$GCC" = "xyes"; then
+ my_common_gcc_flags="-Wall -Wextra -Wno-unused-parameter \
+ -Wno-missing-field-initializers -g -fvisibility=hidden"
+ GCC_CFLAGS="$my_common_gcc_flags \
+ -Wstrict-prototypes -Wmissing-prototypes"
+ GCC_CXXFLAGS="$my_common_gcc_flags"
+fi
+AC_SUBST(GCC_CFLAGS)
+AC_SUBST(GCC_CXXFLAGS)
+
+AC_CONFIG_FILES([Makefile
+ src/Makefile
+ test/Makefile])
+AC_OUTPUT
diff --git a/include/ico_uws.h b/include/ico_uws.h
new file mode 100644
index 0000000..bc53f68
--- /dev/null
+++ b/include/ico_uws.h
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2013, TOYOTA MOTOR CORPORATION.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0. The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+/**
+ * @brief header file of library for communicate
+ *
+ * @date June-7-2013
+ */
+
+#ifndef __ICO_UWS_H__
+#define __ICO_UWS_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*============================================================================*/
+/* definition */
+/*============================================================================*/
+struct ico_uws_context;
+
+typedef enum {
+ ICO_UWS_STATE_CONNECTING = 0,
+ ICO_UWS_STATE_OPEN = 1,
+ ICO_UWS_STATE_CLOSING = 2,
+ ICO_UWS_STATE_CLOSED = 3,
+ ICO_UWS_STATE_UNKNOWN = -1
+} ico_uws_state_e;
+
+typedef enum {
+ ICO_UWS_EVT_OPEN = 100,
+ ICO_UWS_EVT_ERROR = 101,
+ ICO_UWS_EVT_CLOSE = 102,
+ ICO_UWS_EVT_RECEIVE = 103,
+ ICO_UWS_EVT_ADD_FD = 104,
+ ICO_UWS_EVT_DEL_FD = 105
+} ico_uws_evt_e;
+
+typedef enum {
+ ICO_UWS_ERR_NONE = 0, /**< success */
+ ICO_UWS_ERR_CREATE = -201,
+ ICO_UWS_ERR_CONNECT = -202,
+ ICO_UWS_ERR_CLOSED = -203,
+ ICO_UWS_ERR_SEND = -204,
+ ICO_UWS_ERR_INVALID_PARAM = -205,
+ ICO_UWS_ERR_OUT_OF_MEMORY = -206,
+ ICO_UWS_ERR_UNKNOWN = -300,
+} ico_uws_error_e;
+
+typedef union {
+ struct {
+ void *recv_data;
+ size_t recv_len;
+ } _ico_uws_message;
+ struct {
+ ico_uws_error_e code;
+ } _ico_uws_error;
+ struct {
+ int fd;
+ } _ico_uws_fd;
+} ico_uws_detail;
+
+typedef void (*ico_uws_evt_cb)
+ (const struct ico_uws_context *context,
+ const ico_uws_evt_e event,
+ const void *id,
+ const ico_uws_detail *detail,
+ void *user_data);
+
+/*============================================================================*/
+/* functions */
+/*============================================================================*/
+/*--------------------------------------------------------------------------*/
+/**
+ * @brief ico_uws_create_context
+ * Create ico_uws context.
+ * This API does not support secure access ("wss://") and
+ * the multi protocols.
+ * (If user sets "wss://", this function processes as "ws://".)
+ *
+ * @param[in] uri the uri to which to connect
+ * server sets the string ":(port)"
+ * client sets the string "ws://(host):(port)"
+ * @param[in] protocol the protocol name
+ * @return context
+ * @retval ico_uws context success
+ * @retval NULL error
+ */
+/*--------------------------------------------------------------------------*/
+struct ico_uws_context *ico_uws_create_context(const char *uri,
+ const char *protocol);
+
+/*--------------------------------------------------------------------------*/
+/**
+ * @brief ico_uws_close
+ * Close the connection and destroy the ico_uws context.
+ *
+ * @param[in] context ico_uws context
+ * @return none
+ */
+/*--------------------------------------------------------------------------*/
+void ico_uws_close(struct ico_uws_context *context);
+
+/*--------------------------------------------------------------------------*/
+/**
+ * @brief ico_uws_send
+ * Send data to which to connect.
+ * User needs to call the function "ico_uws_service"
+ * before calling this function.
+ *
+ * @param[in] context ico_uws context
+ * @param[in] id the id to connected to (callback notifies)
+ * @param[in] data the data to send
+ * @param[in] len count of the data bytes
+ * @return none
+ * @see ico_uws_service
+ */
+/*--------------------------------------------------------------------------*/
+void ico_uws_send(struct ico_uws_context *context, void *id,
+ unsigned char *data, size_t len);
+
+/*--------------------------------------------------------------------------*/
+/**
+ * @brief ico_uws_service
+ * Service any pending websocket activity.
+ * This function deals with any pending websocket traffic,
+ * so you need to call this function periodically.
+ *
+ * @param[in] context ico_uws context
+ * @return none
+ */
+/*--------------------------------------------------------------------------*/
+void ico_uws_service(struct ico_uws_context *context);
+
+/*--------------------------------------------------------------------------*/
+/**
+ * @brief ico_uws_get_uri
+ * Get the uri that is connecting to now.
+ *
+ * @param[in] context ico_uws context
+ * @return uri
+ * @retval data of string success
+ * @retval NULL error
+ */
+/*--------------------------------------------------------------------------*/
+char *ico_uws_get_uri(struct ico_uws_context *context);
+
+/*--------------------------------------------------------------------------*/
+/**
+ * @brief ico_uws_get_ready_state
+ * Get the state of connection.
+ *
+ * @param[in] context ico_uws context
+ * @return state
+ * @retval >= 0 success
+ * @retval ICO_UWS_STATE_UNKNOWN error
+ */
+/*--------------------------------------------------------------------------*/
+ico_uws_state_e ico_uws_get_ready_state(struct ico_uws_context *context);
+
+/*--------------------------------------------------------------------------*/
+/**
+ * @brief ico_uws_set_event_cb
+ * Set the event callback function.
+ *
+ * @param[in] context ico_uws context
+ * @param[in] callback callback function
+ * @param[in] user_data user data
+ * @return result
+ * @retval ICO_UWS_ERR_NONE success
+ * @retval others error
+ */
+/*--------------------------------------------------------------------------*/
+int ico_uws_set_event_cb(struct ico_uws_context *context, ico_uws_evt_cb callback,
+ void *user_data);
+
+/*--------------------------------------------------------------------------*/
+/**
+ * @brief ico_uws_unset_event_cb
+ * Unset the event callback function.
+ *
+ * @param[in] context ico_uws context
+ * @return none
+ */
+/*--------------------------------------------------------------------------*/
+void ico_uws_unset_event_cb(struct ico_uws_context *context);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ICO_UWS_H__ */
diff --git a/include/ico_uws_private.h b/include/ico_uws_private.h
new file mode 100644
index 0000000..dec4dc1
--- /dev/null
+++ b/include/ico_uws_private.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2013, TOYOTA MOTOR CORPORATION.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0. The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+/**
+ * @brief private header file of library for communicate
+ *
+ * @date June-7-2013
+ */
+
+#ifndef __ICO_UWS_PRIVATE_H__
+#define __ICO_UWS_PRIVATE_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*===========================================================================*/
+/* variable & table */
+/*===========================================================================*/
+#define ICO_UWS_MAX_NUM 200 /**< max num of list's data */
+#define ICO_UWS_MAX_FDS 4 /**< max num of file descriptors */
+
+/* libwebsockets's protocol number */
+enum ico_apf_protocols
+{
+ PROTOCOL_HTTP = 0, /* always first */
+ PROTOCOL_ICO_UWS, /* for ico_uws communication */
+ PROTOCOL_END /* final */
+};
+
+/* structure for managing the ico_uws_context */
+struct ico_uws_mng_context {
+ struct ico_uws_mng_context *next;
+ struct ico_uws_context *context;
+};
+
+/* structure for managing the ico_uws_context's list */
+struct ico_uws_mng_context_list {
+ struct ico_uws_mng_context *first;
+ struct ico_uws_mng_context *last;
+ struct ico_uws_mng_context *free;
+};
+
+/* structure of connection info */
+struct ico_uws_connect {
+ struct ico_uws_connect *next;
+ struct libwebsocket *wsi;
+};
+
+/* ico uws context */
+struct ico_uws_context {
+ struct libwebsocket_context *ws_context;
+
+ /* connection information list */
+ struct ico_uws_connect *con_list_first;
+ struct ico_uws_connect *con_list_last;
+ struct ico_uws_connect *con_list_free;
+
+ char uri[128];
+ int port;
+ ico_uws_state_e state;
+ struct {
+ int fd;
+ void *wsi;
+ } callback_fd_list[ICO_UWS_MAX_FDS];
+
+ struct libwebsocket_protocols protocols[PROTOCOL_END + 1];
+
+ ico_uws_evt_cb callback;
+ void *user_data;
+};
+
+/*============================================================================*/
+/* global API */
+/*============================================================================*/
+#if defined(__GNUC__) && __GNUC__ >= 4
+#define ICO_API __attribute__ ((visibility("default")))
+#else
+#define ICO_API
+#endif
+
+/*============================================================================*/
+/* log macro */
+/*============================================================================*/
+#ifndef _NO_USE_DLOG
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "ICO_UWS"
+#include <dlog.h>
+
+static int _ico_uws_debug = 0;
+
+#define _ERR(fmt, arg...) \
+ do { \
+ fprintf(stderr, "ico_uws E: %s:%d [ "fmt" ]\n", \
+ __FUNCTION__, \
+ __LINE__, \
+ ##arg); \
+ LOGE("%s:%d " fmt, __FUNCTION__, __LINE__, ##arg); \
+ } while (0)
+
+#define _WARN(fmt, arg...) \
+ do { \
+ LOGW("%s:%d " fmt, __FUNCTION__, __LINE__, ##arg); \
+ } while (0)
+
+#define _INFO(fmt, arg...) \
+ do { \
+ LOGI("%s:%d " fmt, __FUNCTION__, __LINE__, ##arg); \
+ } while (0)
+
+#define _DBG(fmt, arg...) \
+ do { \
+ if (_ico_uws_debug == 0) { \
+ if (getenv("ICO_UWS_DEBUG")) \
+ _ico_uws_debug = 1; \
+ else \
+ _ico_uws_debug = -1; \
+ } \
+ if (_ico_uws_debug > 0) { \
+ LOGD("%s:%d " fmt, __FUNCTION__, __LINE__, ##arg); \
+ } \
+ } while (0)
+
+#else
+
+#define _ERR(fmt, arg...) \
+ do { \
+ fprintf(stderr, \
+ "ico_uws E: %s:%d [ "fmt" ]\n", \
+ __FUNCTION__, \
+ __LINE__, \
+ ##arg); \
+ } while (0)
+
+#define _WARN(fmt, arg...) \
+ do { \
+ fprintf(stderr, \
+ "ico_uws W: %s:%d [ "fmt" ]\n", \
+ __FUNCTION__, \
+ __LINE__, \
+ ##arg); \
+ } while (0)
+
+
+#define _INFO(fmt, arg...) \
+ do { \
+ fprintf(stderr, \
+ "ico_uws I: %s:%d [ "fmt" ]\n", \
+ __FUNCTION__, \
+ __LINE__, \
+ ##arg); \
+ } while (0)
+
+#define _DBG(fmt, arg...) \
+ do { \
+ if (getenv("ICO_UWS_DEBUG")) { \
+ fprintf(stderr, \
+ "ico_uws D: %s:%d [ "fmt" ]\n", \
+ __FUNCTION__, \
+ __LINE__, \
+ ##arg); \
+ } \
+ } while (0)
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ICO_UWS_PRIVATE_H__ */
diff --git a/packaging/ico-uxf-utilities.changes b/packaging/ico-uxf-utilities.changes
new file mode 100644
index 0000000..16fe129
--- /dev/null
+++ b/packaging/ico-uxf-utilities.changes
@@ -0,0 +1,2 @@
+* Wed Jul 17 2013 Shibata Makoto <shibata@mac.tec.toyota.co.jp> f508b53
+- Import initial.
diff --git a/packaging/ico-uxf-utilities.spec b/packaging/ico-uxf-utilities.spec
new file mode 100644
index 0000000..3432960
--- /dev/null
+++ b/packaging/ico-uxf-utilities.spec
@@ -0,0 +1,58 @@
+Name: ico-uxf-utilities
+Summary: common utilities for ico uifw
+Version: 0.2.01
+Release: 1.1
+Group: TO_BE/FILLED_IN
+License: Apache License, Version 2.0
+URL: ""
+Source0: %{name}-%{version}.tar.bz2
+
+BuildRequires: libwebsockets-devel >= 1.2
+BuildRequires: libdlog-devel
+BuildRequires: pkgconfig(glib-2.0)
+Requires: libwebsockets >= 1.2
+Requires: libdlog
+
+%description
+common utilities for ico uifw.
+
+%package devel
+Summary: Development files for %{name}
+Group: Development/Utility/Libraries
+Requires: %{name} = %{version}-%{release}
+Requires: libwebsockets-devel
+
+%description devel
+Development files for inter application communications.
+
+%prep
+%setup -q -n %{name}-%{version}
+
+%build
+autoreconf --install
+
+%autogen
+
+%configure
+make %{?_smp_mflags}
+
+%install
+rm -rf %{buildroot}
+%make_install
+
+mkdir -p %{buildroot}/usr/lib/
+
+# include
+mkdir -p %{buildroot}/%{_includedir}/ico-util/
+cp -f include/ico_uws.h %{buildroot}/%{_includedir}/ico-util/
+
+%post
+
+%files
+
+%{_libdir}/*.so.*
+
+%files devel
+%defattr(-,root,root,-)
+%{_includedir}/ico-util/ico_uws.h
+%{_libdir}/*.so
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..63c73e1
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,17 @@
+lib_LTLIBRARIES = libico-util-com.la
+
+libico_util_com_la_CFLAGS = -I../include $(OPT_CFLAGS)
+libico_util_com_la_LIBADD = $(OPT_LIBS) -lwebsockets
+libico_util_com_la_LDFLAGS = -version-info 0:1:0
+libico_util_com_la_SOURCES = \
+ ico_uws.c
+
+AM_CFLAGS = $(GCC_CFLAGS)
+AM_CPPFLAGS = $(GCC_CFLAGS) \
+ -DDATADIR='"$(datadir)"' \
+ -DMODULEDIR='"$(moduledir)"' \
+ -DLIBEXECDIR='"$(libexecdir)"'
+AM_LDFLAGS = -module -avoid-version -rpath $(libdir) -lwebsockets
+
+.FORCE :
+
diff --git a/src/ico_uws.c b/src/ico_uws.c
new file mode 100644
index 0000000..eb36701
--- /dev/null
+++ b/src/ico_uws.c
@@ -0,0 +1,1410 @@
+/*
+ * Copyright (c) 2013, TOYOTA MOTOR CORPORATION.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0. The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+/**
+ * @brief library for communicate
+ *
+ * @date June-26-2013
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <unistd.h>
+
+#include <libwebsockets.h>
+#include "ico_uws.h"
+#include "ico_uws_private.h"
+
+/*===========================================================================*/
+/* definition */
+/*===========================================================================*/
+#define URI_WS "ws://"
+#define URI_WS_SECURE "wss://"
+
+/* buffer of reserved data that failed to send */
+#define DATA_LEN LWS_SEND_BUFFER_PRE_PADDING + 1024 + \
+ LWS_SEND_BUFFER_POST_PADDING
+
+/*===========================================================================*/
+/* define static function prototype */
+/*===========================================================================*/
+static struct ico_uws_connect *add_ws_instance(struct ico_uws_context *context,
+ struct libwebsocket *wsi);
+static void del_ws_instance(struct ico_uws_context *context,
+ const struct libwebsocket *wsi);
+static void del_connect_list(struct ico_uws_context *context);
+static int add_context(struct ico_uws_context *context);
+static struct ico_uws_context *get_context_by_wsctx(
+ struct libwebsocket_context *ws_context);
+static struct ico_uws_context *get_context_by_wsi(struct libwebsocket *wsi);
+static void del_context(struct ico_uws_context *context);
+static void del_context_list(void);
+static int exec_callback(const struct ico_uws_context *context,
+ const ico_uws_evt_e event,
+ const void *id,
+ const ico_uws_detail *detail,
+ const void *user_data);
+static int server_http_callback(struct libwebsocket_context *ws_context,
+ struct libwebsocket *wsi,
+ enum libwebsocket_callback_reasons reason,
+ void *user, void *in, size_t len);
+static int client_http_callback(struct libwebsocket_context *ws_context,
+ struct libwebsocket *wsi,
+ enum libwebsocket_callback_reasons reason,
+ void *user, void *in, size_t len);
+static int server_uws_callback(struct libwebsocket_context *ws_context,
+ struct libwebsocket *wsi,
+ enum libwebsocket_callback_reasons reason,
+ void *user, void *in, size_t len);
+static int client_uws_callback(struct libwebsocket_context *ws_context,
+ struct libwebsocket *wsi,
+ enum libwebsocket_callback_reasons reason,
+ void *user, void *in, size_t len);
+static struct ico_uws_context *create_server(const char *uri,
+ const char *protocol);
+static struct ico_uws_context *create_client(const char *uri,
+ const char *protocol);
+
+/*===========================================================================*/
+/* variable & table */
+/*===========================================================================*/
+/* ico_uws_context */
+struct context_info_t {
+ struct context_info_t *next;
+ struct ico_uws_context *context;
+};
+static struct context_info_t *ctx_list_first = NULL;
+static struct context_info_t *ctx_list_last = NULL;
+static struct context_info_t *ctx_list_free = NULL;
+
+/* pthread mutex initialize */
+static pthread_mutex_t in_out_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t creating_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* current creating context */
+static struct ico_uws_context *current_creating_context = NULL;
+
+/*===========================================================================*/
+/* static function */
+/*===========================================================================*/
+/*--------------------------------------------------------------------------*/
+/**
+ * @brief add_ws_instance
+ * Add wsi into the ico_uws_connect list.
+ *
+ * @param[in] context ico_uws context
+ * @param[in] wsi libwebsocket instance
+ * @return ico_uws_connect pointer
+ * @retval pointer of list success
+ * @retval NULL error
+ */
+/*--------------------------------------------------------------------------*/
+static struct ico_uws_connect *
+add_ws_instance(struct ico_uws_context *context, struct libwebsocket *wsi)
+{
+ int id;
+ struct ico_uws_connect *con_table;
+ ico_uws_detail detail;
+
+ _DBG("add websocket instance called");
+ if (context == NULL || wsi == NULL) {
+ _WARN("context or wsi is NULL");
+ return NULL;
+ }
+
+ /* mutex lock */
+ pthread_mutex_lock(&in_out_mutex);
+ con_table = context->con_list_first;
+ /* search free table */
+ for (id = 0; id < ICO_UWS_MAX_NUM; id++) {
+ if (con_table == NULL) break;
+ con_table = con_table->next;
+ }
+
+ /* list is full */
+ if (id == ICO_UWS_MAX_NUM) {
+ /* mutex unlock */
+ pthread_mutex_unlock(&in_out_mutex);
+ detail._ico_uws_error.code = ICO_UWS_ERR_UNKNOWN;
+ _ERR("list is full (%d)", detail._ico_uws_error.code);
+ exec_callback(NULL, ICO_UWS_EVT_ERROR, NULL, &detail, NULL);
+ return NULL;
+ }
+
+ /* create and set wsi */
+ if (context->con_list_free == NULL) {
+ /* free table does not exist */
+ con_table = calloc(1, sizeof(struct ico_uws_connect));
+ if (con_table == NULL) {
+ /* mutex unlock */
+ pthread_mutex_unlock(&in_out_mutex);
+ detail._ico_uws_error.code = ICO_UWS_ERR_OUT_OF_MEMORY;
+ _ERR("no memory for ico_uws_connect (%d)",
+ detail._ico_uws_error.code);
+ exec_callback(NULL, ICO_UWS_EVT_ERROR, NULL, &detail, NULL);
+ return NULL;
+ }
+ }
+ else {
+ /* use free area */
+ con_table = context->con_list_free;
+ context->con_list_free = con_table->next;
+ }
+ /* add wsi */
+ con_table->wsi = wsi;
+ _DBG("add wsi to the connect info table success");
+
+ /* add table to list */
+ con_table->next = NULL;
+ if (context->con_list_first == NULL) {
+ context->con_list_first = con_table;
+ }
+ else {
+ context->con_list_last->next = con_table;
+ }
+ context->con_list_last = con_table;
+ /* mutex unlock */
+ pthread_mutex_unlock(&in_out_mutex);
+
+ return con_table;
+}
+
+/*--------------------------------------------------------------------------*/
+/**
+ * @brief del_ws_instance
+ * Delete wsi from the ico_uws_connect list.
+ *
+ * @param[in] context ico_uws context
+ * @param[in] wsi libwebsocket instance
+ * @return none
+ */
+/*--------------------------------------------------------------------------*/
+static void
+del_ws_instance(struct ico_uws_context *context,
+ const struct libwebsocket *wsi)
+{
+ int id;
+ struct ico_uws_connect *con_table, *prev_con_table;
+
+ if (context == NULL || wsi == NULL) {
+ _WARN("context or wsi is NULL");
+ return;
+ }
+
+ /* mutex lock */
+ pthread_mutex_lock(&in_out_mutex);
+ con_table = context->con_list_first;
+ prev_con_table = NULL;
+ /* search wsi */
+ for (id = 0; id < ICO_UWS_MAX_NUM; id++) {
+ if (con_table == NULL) break;
+ if (con_table->wsi == wsi) {
+ /* update list */
+ if (prev_con_table == NULL) {
+ context->con_list_first = con_table->next;
+ }
+ else {
+ prev_con_table->next = con_table->next;
+ }
+ /* update list's last */
+ if (context->con_list_last == con_table) {
+ context->con_list_last = prev_con_table;
+ }
+ /* clear data */
+ con_table->wsi = NULL;
+ _DBG("delete wsi from the connect info table success");
+ /* add to free list */
+ con_table->next = context->con_list_free;
+ context->con_list_free = con_table;
+ break;
+ }
+ prev_con_table = con_table;
+ con_table = con_table->next;
+ }
+
+ /* mutex unlock */
+ pthread_mutex_unlock(&in_out_mutex);
+
+ return;
+}
+
+/*--------------------------------------------------------------------------*/
+/**
+ * @brief del_connect_list
+ * Delete connect information list.
+ *
+ * @param[in] context ico_uws context
+ * @return none
+ */
+/*--------------------------------------------------------------------------*/
+static void
+del_connect_list(struct ico_uws_context *context)
+{
+ int id;
+ struct ico_uws_connect *con_table;
+
+ _DBG("delete connect information list");
+ /* mutex lock */
+ pthread_mutex_lock(&in_out_mutex);
+ for (id = 0; id < ICO_UWS_MAX_NUM; id++) {
+ con_table = context->con_list_first;
+ if (con_table == NULL) break;
+ if (con_table->wsi != NULL) con_table->wsi = NULL;
+ context->con_list_first = con_table->next;
+ free(con_table);
+ }
+
+ for (id = 0; id < ICO_UWS_MAX_NUM; id++) {
+ con_table = context->con_list_free;
+ if (con_table == NULL) break;
+ if (con_table->wsi != NULL) con_table->wsi = NULL;
+ context->con_list_free = con_table->next;
+ free(con_table);
+ }
+ /* mutex unlock */
+ pthread_mutex_unlock(&in_out_mutex);
+
+ return;
+}
+
+/*--------------------------------------------------------------------------*/
+/**
+ * @brief add_context
+ * Add ico_uws context to the local list.
+ *
+ * @param[in] context ico_uws context
+ * @return result
+ * @retval ICO_UWS_ERR_NONE success
+ * @retval < 0 error
+ */
+/*--------------------------------------------------------------------------*/
+static int
+add_context(struct ico_uws_context *context)
+{
+ int id;
+ struct context_info_t *ctx_table;
+ ico_uws_detail detail;
+
+ if (context == NULL) {
+ detail._ico_uws_error.code = ICO_UWS_ERR_INVALID_PARAM;
+ _ERR("invalid param (%d)", detail._ico_uws_error.code);
+ exec_callback(NULL, ICO_UWS_EVT_ERROR, NULL, &detail, NULL);
+ return detail._ico_uws_error.code;
+ }
+
+ /* mutex lock */
+ pthread_mutex_lock(&in_out_mutex);
+ ctx_table = ctx_list_first;
+ /* search free table */
+ for (id = 0; id < ICO_UWS_MAX_NUM; id++) {
+ if (ctx_table == NULL) break;
+ ctx_table = ctx_table->next;
+ }
+
+ /* local list is full */
+ if (id == ICO_UWS_MAX_NUM) {
+ /* mutex unlock */
+ pthread_mutex_unlock(&in_out_mutex);
+ detail._ico_uws_error.code = ICO_UWS_ERR_UNKNOWN;
+ _ERR("list is full (%d)", detail._ico_uws_error.code);
+ exec_callback(NULL, ICO_UWS_EVT_ERROR, NULL, &detail, NULL);
+ return detail._ico_uws_error.code;
+ }
+
+ /* create and set context */
+ if (ctx_list_free == NULL) {
+ /* free table does not exist */
+ ctx_table = calloc(1, sizeof(struct context_info_t));
+ if (ctx_table == NULL) {
+ /* mutex unlock */
+ pthread_mutex_unlock(&in_out_mutex);
+ detail._ico_uws_error.code = ICO_UWS_ERR_OUT_OF_MEMORY;
+ _ERR("no memory for ico_uws_connect (%d)",
+ detail._ico_uws_error.code);
+ exec_callback(NULL, ICO_UWS_EVT_ERROR, NULL, &detail, NULL);
+ return detail._ico_uws_error.code;
+ }
+ }
+ else {
+ /* use free area */
+ ctx_table = ctx_list_free;
+ ctx_list_free = ctx_table->next;
+ }
+ /* add data */
+ ctx_table->context = context;
+ _DBG("add context to the local list success");
+
+ /* add table to list */
+ ctx_table->next = NULL;
+ if (ctx_list_first == NULL) {
+ ctx_list_first = ctx_table;
+ }
+ else {
+ ctx_list_last->next = ctx_table;
+ }
+ ctx_list_last = ctx_table;
+ /* mutex unlock */
+ pthread_mutex_unlock(&in_out_mutex);
+
+ return ICO_UWS_ERR_NONE;
+}
+
+/*--------------------------------------------------------------------------*/
+/**
+ * @brief get_context_by_wsctx
+ * Get ico_uws_context from the local list by websocket context.
+ *
+ * @param[in] ws_context libwebsocket context
+ * @return ico_uws context
+ * @retval context ico_uws context's address
+ * @retval NULL error
+ */
+/*--------------------------------------------------------------------------*/
+static struct ico_uws_context *
+get_context_by_wsctx(struct libwebsocket_context *ws_context)
+{
+ struct context_info_t *ctx_table;
+ struct ico_uws_context *context;
+ int id;
+
+ context = NULL;
+ /* mutex lock */
+ pthread_mutex_lock(&in_out_mutex);
+ ctx_table = ctx_list_first;
+ for (id = 0; id < ICO_UWS_MAX_NUM; id++) {
+ if (ctx_table == NULL) {
+ /* mutex unlock */
+ pthread_mutex_unlock(&in_out_mutex);
+ _DBG("ws_context(0x%08x) does not exist in the local list", (int)ws_context);
+ return current_creating_context;
+ }
+ if (ctx_table->context->ws_context == ws_context) {
+ context = ctx_table->context;
+ _DBG("get context success (ctx: 0x%08x)", (int)context);
+ break;
+ }
+ ctx_table = ctx_table->next;
+ }
+ /* mutex unlock */
+ pthread_mutex_unlock(&in_out_mutex);
+
+ return context;
+}
+
+/*--------------------------------------------------------------------------*/
+/**
+ * @brief get_context_by_wsi
+ * Get ico_uws_context from the local list by websocket instance.
+ *
+ * @param[in] wsi libwebsocket instance
+ * @return ico_uws context
+ * @retval context ico_uws context's address
+ * @retval NULL error
+ */
+/*--------------------------------------------------------------------------*/
+static struct ico_uws_context *
+get_context_by_wsi(struct libwebsocket *wsi)
+{
+ struct context_info_t *ctx_table;
+ struct ico_uws_connect *con_table;
+ struct ico_uws_context *context;
+ int id, con_id;
+
+ context = NULL;
+ /* mutex lock */
+ pthread_mutex_lock(&in_out_mutex);
+ ctx_table = ctx_list_first;
+ for (id = 0; id < ICO_UWS_MAX_NUM; id++) {
+ if (ctx_table == NULL) {
+ /* mutex unlock */
+ pthread_mutex_unlock(&in_out_mutex);
+ _DBG("context does not exist in the local list");
+ return current_creating_context;
+ }
+ con_table = ctx_table->context->con_list_first;
+ for (con_id = 0; con_id < ICO_UWS_MAX_NUM; con_id++) {
+ if (con_table == NULL) break;
+ if (con_table->wsi == wsi) {
+ context = ctx_table->context;
+ _DBG("get context success (ctx: 0x%08x)", (int)context);
+ break;
+ }
+ con_table = con_table->next;
+ }
+ if (context != NULL) break;
+ ctx_table = ctx_table->next;
+ }
+ /* mutex unlock */
+ pthread_mutex_unlock(&in_out_mutex);
+
+ return context;
+}
+
+/*--------------------------------------------------------------------------*/
+/**
+ * @brief del_context
+ * Delete the uws context's table from the local list.
+ *
+ * @param[in] context ico_uws context
+ * @return none
+ */
+/*--------------------------------------------------------------------------*/
+static void
+del_context(struct ico_uws_context *context)
+{
+ int id;
+ struct context_info_t *ctx_table, *prev_ctx_table;
+
+ if (context == NULL) {
+ _WARN("context is NULL");
+ return;
+ }
+
+ /* mutex lock */
+ pthread_mutex_lock(&in_out_mutex);
+ ctx_table = ctx_list_first;
+ prev_ctx_table = NULL;
+ /* search wsi */
+ for (id = 0; id < ICO_UWS_MAX_NUM; id++) {
+ if (ctx_table == NULL) break;
+ if (ctx_table->context == context) {
+ /* update list */
+ if (prev_ctx_table == NULL) {
+ ctx_list_first = ctx_table->next;
+ }
+ else {
+ prev_ctx_table->next = ctx_table->next;
+ }
+ /* update list's last */
+ if (ctx_list_last == ctx_table) {
+ ctx_list_last = prev_ctx_table;
+ }
+ /* clear data */
+ free(ctx_table->context);
+ ctx_table->context = NULL;
+ _DBG("delete context success");
+ /* add to free list */
+ ctx_table->next = ctx_list_free;
+ ctx_list_free = ctx_table;
+ break;
+ }
+ prev_ctx_table = ctx_table;
+ ctx_table = ctx_table->next;
+ }
+
+ /* mutex unlock */
+ pthread_mutex_unlock(&in_out_mutex);
+
+ return;
+}
+
+/*--------------------------------------------------------------------------*/
+/**
+ * @brief del_context_list
+ * Delete the local uws context's list.
+ *
+ * @param none
+ * @return none
+ */
+/*--------------------------------------------------------------------------*/
+static void
+del_context_list(void)
+{
+ int id;
+ struct context_info_t *ctx_table;
+
+ _DBG("delete context info list");
+ /* mutex lock */
+ pthread_mutex_lock(&in_out_mutex);
+ for (id = 0; id < ICO_UWS_MAX_NUM; id++) {
+ ctx_table = ctx_list_first;
+ if (ctx_table == NULL) break;
+
+ ctx_list_first = ctx_table->next;
+ free(ctx_table);
+ _DBG("delete context info table success");
+ }
+
+ for (id = 0; id < ICO_UWS_MAX_NUM; id++) {
+ ctx_table = ctx_list_free;
+ if (ctx_table == NULL) break;
+
+ ctx_list_free = ctx_table->next;
+ free(ctx_table);
+ _DBG("delete context info free table success");
+ }
+ /* mutex unlock */
+ pthread_mutex_unlock(&in_out_mutex);
+
+ return;
+}
+
+/*--------------------------------------------------------------------------*/
+/**
+ * @brief exec_callback
+ * Execute callback function.
+ *
+ * @param[in] context ico_uws context
+ * @param[in] event event code
+ * @param[in] id unique id
+ * @param[in] detail detail information
+ * @param[in] user_data user data
+ * @return result
+ * @retval ICO_UWS_ERR_NONE success (called callback function)
+ * @retval ICO_UWS_ERR_INVALID_PARAM error (no context or no callback function)
+ */
+/*--------------------------------------------------------------------------*/
+static int
+exec_callback(const struct ico_uws_context *context,
+ const ico_uws_evt_e event,
+ const void *id, const ico_uws_detail *detail,
+ const void *user_data)
+{
+ if (context == NULL || context->callback == NULL) {
+ _DBG("callback function does not exist");
+ /* always success */
+ return ICO_UWS_ERR_CONNECT;
+ }
+
+ _DBG("exec_callback (event: %d)", event);
+ context->callback(context, event, id, detail, context->user_data);
+
+ /* always success */
+ return ICO_UWS_ERR_NONE;
+}
+
+/*--------------------------------------------------------------------------*/
+/**
+ * @brief server_http_callback
+ * HTTP server callback function.
+ *
+ * @param[in] ws_context libwebsocket context
+ * @param[in] wsi libwebsocket instance
+ * @param[in] reason callback reason
+ * @param[in] user user data
+ * @param[in] in data (used for some callback reasons)
+ * @param[in] len size (used for some callback reasons)
+ * @return result
+ * @retval ICO_UWS_ERR_NONE success (this function is always success)
+ */
+/*--------------------------------------------------------------------------*/
+static int
+server_http_callback(struct libwebsocket_context *ws_context,
+ struct libwebsocket *wsi,
+ enum libwebsocket_callback_reasons reason,
+ void *user, void *in, size_t len)
+{
+ struct ico_uws_context *context = get_context_by_wsctx(ws_context);
+ ico_uws_detail detail;
+ int i;
+
+ switch (reason) {
+ case LWS_CALLBACK_FILTER_NETWORK_CONNECTION:
+ _DBG("server http cb: filter network connection");
+ break;
+ case LWS_CALLBACK_ADD_POLL_FD:
+ detail._ico_uws_fd.fd = libwebsocket_get_socket_fd(wsi);
+ _DBG("server http cb: add connection socket (%d)", detail._ico_uws_fd.fd);
+ if ((exec_callback(context, ICO_UWS_EVT_ADD_FD, (void *)wsi, &detail, NULL)
+ != ICO_UWS_ERR_NONE) && (context != NULL)) {
+ for (i = 0; i < ICO_UWS_MAX_FDS; i++) {
+ if (context->callback_fd_list[i].fd == 0) break;
+ }
+ if (i < ICO_UWS_MAX_FDS) {
+ context->callback_fd_list[i].fd = detail._ico_uws_fd.fd;
+ context->callback_fd_list[i].wsi = (void *)wsi;
+ }
+ }
+ break;
+ case LWS_CALLBACK_DEL_POLL_FD:
+ detail._ico_uws_fd.fd = libwebsocket_get_socket_fd(wsi);
+ _DBG("server http cb: delete connection socket (%d)", detail._ico_uws_fd.fd);
+ if (context) {
+ for (i = 0; i < ICO_UWS_MAX_FDS; i++) {
+ if (context->callback_fd_list[i].fd == detail._ico_uws_fd.fd) {
+ context->callback_fd_list[i].fd = 0;
+ }
+ }
+ }
+ exec_callback(context, ICO_UWS_EVT_DEL_FD, (void *)wsi,
+ &detail, NULL);
+ break;
+ default:
+ _DBG("server http cb: unhandled callback: %d", reason);
+ break;
+ }
+
+ /* always success */
+ return ICO_UWS_ERR_NONE;
+}
+
+/*--------------------------------------------------------------------------*/
+/**
+ * @brief client_http_callback
+ * HTTP client callback function.
+ *
+ * @param[in] ws_context libwebsocket context
+ * @param[in] wsi libwebsocket instance
+ * @param[in] reason callback reason
+ * @param[in] user user data
+ * @param[in] in data (used for some callback reasons)
+ * @param[in] len size (used for some callback reasons)
+ * @return result
+ * @retval ICO_UWS_ERR_NONE success (this function is always success)
+ */
+/*--------------------------------------------------------------------------*/
+static int
+client_http_callback(struct libwebsocket_context *ws_context,
+ struct libwebsocket *wsi,
+ enum libwebsocket_callback_reasons reason,
+ void *user, void *in, size_t len)
+{
+ struct ico_uws_context *context = get_context_by_wsi(wsi);
+ ico_uws_detail detail;
+ int fd;
+ int i;
+
+ switch (reason) {
+ case LWS_CALLBACK_FILTER_NETWORK_CONNECTION:
+ _DBG("client http cb: filter network connection");
+ break;
+ case LWS_CALLBACK_ADD_POLL_FD:
+ fd = libwebsocket_get_socket_fd(wsi);
+ detail._ico_uws_fd.fd = fd;
+ _DBG("client http cb: add connection socket (%d)", detail._ico_uws_fd.fd);
+ if ((exec_callback(context, ICO_UWS_EVT_ADD_FD, (void *)wsi, &detail, NULL)
+ != ICO_UWS_ERR_NONE) && (context != NULL)) {
+ for (i = 0; i < ICO_UWS_MAX_FDS; i++) {
+ if (context->callback_fd_list[i].fd == 0) break;
+ }
+ if (i < ICO_UWS_MAX_FDS) {
+ context->callback_fd_list[i].fd = detail._ico_uws_fd.fd;
+ context->callback_fd_list[i].wsi = (void *)wsi;
+ }
+ }
+ break;
+ case LWS_CALLBACK_DEL_POLL_FD:
+ fd = libwebsocket_get_socket_fd(wsi);
+ detail._ico_uws_fd.fd = fd;
+ _DBG("client http cb: delete connection socket (%d)", detail._ico_uws_fd.fd);
+ if (context) {
+ for (i = 0; i < ICO_UWS_MAX_FDS; i++) {
+ if (context->callback_fd_list[i].fd == detail._ico_uws_fd.fd) {
+ context->callback_fd_list[i].fd = 0;
+ }
+ }
+ }
+ exec_callback(context, ICO_UWS_EVT_DEL_FD, (void *)wsi,
+ &detail, NULL);
+ break;
+ default:
+ _DBG("client http cb: unhandled callback: %d", reason);
+ break;
+ }
+
+ /* always success */
+ return ICO_UWS_ERR_NONE;
+}
+
+/*--------------------------------------------------------------------------*/
+/**
+ * @brief server_uws_callback
+ * Server callback function for ico_uws.
+ *
+ * @param[in] ws_context libwebsocket context
+ * @param[in] wsi libwebsocket instance
+ * @param[in] reason callback reason
+ * @param[in] user user data
+ * @param[in] in data (used for some callback reasons)
+ * @param[in] len size (used for some callback reasons)
+ * @return result
+ * @retval ICO_UWS_ERR_NONE success
+ * @retval ICO_UWS_ERR_CLOSED connection closed
+ */
+/*--------------------------------------------------------------------------*/
+static int
+server_uws_callback(struct libwebsocket_context *ws_context,
+ struct libwebsocket *wsi,
+ enum libwebsocket_callback_reasons reason,
+ void *user, void *in, size_t len)
+{
+ struct ico_uws_context *context = get_context_by_wsctx(ws_context);
+ ico_uws_detail detail;
+ int ret = ICO_UWS_ERR_NONE;
+
+ switch (reason) {
+ case LWS_CALLBACK_ESTABLISHED:
+ /* server connection is established */
+ _DBG("server cb: established");
+ if (context != NULL) {
+ add_ws_instance(context, wsi);
+ context->state = ICO_UWS_STATE_OPEN;
+ }
+ exec_callback(context, ICO_UWS_EVT_OPEN, (void *)wsi,
+ NULL, NULL);
+ (void)libwebsocket_callback_on_writable(ws_context, wsi);
+ break;
+ case LWS_CALLBACK_RECEIVE:
+ /* receive data */
+ _DBG("server cb: receive data");
+ detail._ico_uws_message.recv_data = in;
+ detail._ico_uws_message.recv_len = len;
+ exec_callback(context, ICO_UWS_EVT_RECEIVE, (void *)wsi,
+ &detail, NULL);
+ break;
+ case LWS_CALLBACK_SERVER_WRITEABLE:
+ _DBG("server cb: server writable");
+ break;
+ case LWS_CALLBACK_CLOSED:
+ /* websocket session ends */
+ _DBG("server cb: websocket session ends");
+ if (context != NULL) {
+ context->state = ICO_UWS_STATE_CLOSED;
+ del_ws_instance(context, wsi);
+ }
+ exec_callback(context, ICO_UWS_EVT_CLOSE, (void *)wsi, NULL, NULL);
+ ret = ICO_UWS_ERR_CLOSED;
+ break;
+ default:
+ /* unhandled callback reason */
+ _DBG("server cb: unhandled callback %d", reason);
+ break;
+ }
+
+ return ret;
+}
+
+/*--------------------------------------------------------------------------*/
+/**
+ * @brief client_uws_callback
+ * Client callback function for ico_uws.
+ *
+ * @param[in] ws_context libwebsocket context
+ * @param[in] wsi libwebsocket instance
+ * @param[in] reason callback reason
+ * @param[in] user user data
+ * @param[in] in data (used for some callback reasons)
+ * @param[in] len size (used for some callback reasons)
+ * @return result
+ * @retval ICO_UWS_ERR_NONE success
+ * @retval ICO_UWS_ERR_CLOSED connection closed
+ */
+/*--------------------------------------------------------------------------*/
+static int
+client_uws_callback(struct libwebsocket_context *ws_context,
+ struct libwebsocket *wsi,
+ enum libwebsocket_callback_reasons reason,
+ void *user, void *in, size_t len)
+{
+ struct ico_uws_context *context = get_context_by_wsi(wsi);
+ ico_uws_detail detail;
+ int ret = ICO_UWS_ERR_NONE;
+
+ switch (reason) {
+ case LWS_CALLBACK_CLIENT_ESTABLISHED:
+ /* client connection is established */
+ _DBG("client cb: client established");
+ if (context != NULL) {
+ add_ws_instance(context, wsi);
+ context->state = ICO_UWS_STATE_OPEN;
+ }
+ exec_callback(context, ICO_UWS_EVT_OPEN, (void *)wsi,
+ NULL, NULL);
+ (void)libwebsocket_callback_on_writable(ws_context, wsi);
+ break;
+ case LWS_CALLBACK_CLIENT_RECEIVE:
+ /* receive data */
+ _DBG("client cb: client receive");
+ detail._ico_uws_message.recv_data = in;
+ detail._ico_uws_message.recv_len = len;
+ exec_callback(context, ICO_UWS_EVT_RECEIVE, (void *)wsi,
+ &detail, NULL);
+ break;
+ case LWS_CALLBACK_CLIENT_WRITEABLE:
+ _DBG("client cb: client writable");
+ break;
+ case LWS_CALLBACK_CLOSED:
+ /* websocket session ends */
+ _DBG("client cb: websocket session ends");
+ if (context != NULL) {
+ context->state = ICO_UWS_STATE_CLOSED;
+ del_ws_instance(context, wsi);
+ }
+ exec_callback(context, ICO_UWS_EVT_CLOSE, (void *)wsi, NULL, NULL);
+ ret = ICO_UWS_ERR_CLOSED;
+ break;
+ default:
+ _DBG("client cb: unhandled callback %d", reason);
+ break;
+ }
+
+ return ret;
+}
+
+/*--------------------------------------------------------------------------*/
+/**
+ * @brief create_server
+ * Create server's ico_uws context.
+ *
+ * @param[in] uri the uri to which to connect
+ * @param[in] protocol the protocol name
+ * @return context
+ * @retval ico_uws context success
+ * @retval NULL error
+ */
+/*--------------------------------------------------------------------------*/
+static struct ico_uws_context *
+create_server(const char *uri, const char *protocol)
+{
+ struct lws_context_creation_info ws_info;
+ struct ico_uws_context *srv_context = NULL;
+ ico_uws_detail detail;
+ char *cpy_uri = NULL;
+ int port = 0;
+ int id;
+
+ _DBG("create_server (uri: %s)", uri);
+ /* create ico_uws_context */
+ srv_context = (struct ico_uws_context *)
+ malloc(sizeof(struct ico_uws_context));
+ if (srv_context == NULL) {
+ detail._ico_uws_error.code = ICO_UWS_ERR_OUT_OF_MEMORY;
+ _ERR("no memory for ico_uws_context (%d)",
+ detail._ico_uws_error.code);
+ exec_callback(NULL, ICO_UWS_EVT_ERROR, NULL, &detail, NULL);
+ return NULL;
+ }
+ memset(srv_context, 0, sizeof(*srv_context));
+
+ /* set port number */
+ cpy_uri = strdup((char *)uri);
+ port = atoi(&cpy_uri[1]); /* delete colon(:) */
+ free(cpy_uri);
+
+ /* set protocol info */
+ for (id = PROTOCOL_HTTP; id <= PROTOCOL_END; id++) {
+ const char *name = NULL;
+ void *callback = NULL;
+ size_t size = 0;
+ switch (id) {
+ case PROTOCOL_HTTP:
+ name = "http_only";
+ callback = server_http_callback;
+ break;
+ case PROTOCOL_ICO_UWS:
+ name = (const char *)strdup((char *)protocol);
+ callback = server_uws_callback;
+ break;
+ case PROTOCOL_END:
+ /* End of list's name and callback is NULL */
+ default:
+ /* never reach here */
+ break;
+ }
+ srv_context->protocols[id].name = name;
+ srv_context->protocols[id].callback = callback;
+ srv_context->protocols[id].per_session_data_size = size;
+ }
+
+ /* clear libwebsocket info */
+ memset(&ws_info, 0, sizeof(ws_info));
+ /* set lws_context_creation_info */
+ ws_info.port = port;
+ ws_info.iface = NULL; /* to bind the listen socket to all */
+ ws_info.protocols = srv_context->protocols;
+ ws_info.extensions = libwebsocket_get_internal_extensions();
+ ws_info.ssl_cert_filepath = NULL;
+ ws_info.ssl_private_key_filepath = NULL;
+ ws_info.ssl_ca_filepath = NULL;
+ ws_info.ssl_cipher_list = NULL;
+ ws_info.gid = -1;
+ ws_info.uid = -1;
+ ws_info.options = 0; /* no special options */
+ ws_info.user = NULL;
+ ws_info.ka_time = 0;
+ ws_info.ka_probes = 0;
+ ws_info.ka_interval = 0;
+
+ /* create a server context */
+ pthread_mutex_lock(&creating_mutex);
+ current_creating_context = srv_context;
+ srv_context->ws_context = libwebsocket_create_context(&ws_info);
+ current_creating_context = NULL;
+ pthread_mutex_unlock(&creating_mutex);
+
+ if (srv_context->ws_context == NULL) {
+ /* create context failed */
+ detail._ico_uws_error.code = ICO_UWS_ERR_CREATE;
+ _ERR("libwebsocket create context failed (%d)",
+ detail._ico_uws_error.code);
+ exec_callback(NULL, ICO_UWS_EVT_ERROR, NULL, &detail, NULL);
+ free(srv_context);
+ return NULL;
+ }
+ /* set data */
+ strcpy((char *)(srv_context->uri), uri);
+ srv_context->state = ICO_UWS_STATE_CONNECTING;
+ /* add to the local list */
+ add_context(srv_context);
+ /* server created */
+ _DBG("server created and listening on port %d", port);
+
+ return srv_context;
+}
+
+/*--------------------------------------------------------------------------*/
+/**
+ * @brief create_client
+ * Create client's ico_uws context.
+ *
+ * @param[in] uri the uri to which to connect
+ * @param[in] protocol the protocol name
+ * @return context
+ * @retval ico_uws context success
+ * @retval NULL error
+ */
+/*--------------------------------------------------------------------------*/
+static struct ico_uws_context *
+create_client(const char *uri, const char *protocol)
+{
+ struct lws_context_creation_info ws_info;
+ struct ico_uws_context *clt_context = NULL;
+ ico_uws_detail detail;
+ char *split_mark = ":/";
+ char *cpy_uri = NULL;
+ char *address = NULL;
+ int port = 0;
+ int id;
+
+ struct libwebsocket *wsi;
+ int use_ssl = 0; /* not use ssl */
+ int ietf_version = -1; /* -1: default value */
+ char *host = NULL; /* host name */
+ char *origin = NULL; /* socket name */
+
+ _DBG("create_client (uri: %s)", uri);
+ /* create ico_uws_context */
+ clt_context = (struct ico_uws_context *)
+ malloc(sizeof(struct ico_uws_context));
+ if (clt_context == NULL) {
+ detail._ico_uws_error.code = ICO_UWS_ERR_OUT_OF_MEMORY;
+ _ERR("no memory for ico_uws_context (%d)", detail._ico_uws_error.code);
+ exec_callback(NULL, ICO_UWS_EVT_ERROR, NULL, &detail, NULL);
+ return NULL;
+ }
+ memset(clt_context, 0, sizeof(*clt_context));
+
+ /* set protocol info */
+ for (id = PROTOCOL_HTTP; id <= PROTOCOL_END; id++) {
+ const char *name = NULL;
+ void *callback = NULL;
+ size_t size = 0;
+ switch (id) {
+ case PROTOCOL_HTTP:
+ name = "http_only";
+ callback = client_http_callback;
+ break;
+ case PROTOCOL_ICO_UWS:
+ name = (const char *)strdup((char *)protocol);
+ callback = client_uws_callback;
+ break;
+ case PROTOCOL_END:
+ /* End of list's name and callback is NULL */
+ default:
+ /* never reach here */
+ break;
+ }
+ clt_context->protocols[id].name = name;
+ clt_context->protocols[id].callback = callback;
+ clt_context->protocols[id].per_session_data_size = size;
+ }
+
+ /* clear libwebsocket info */
+ memset(&ws_info, 0, sizeof(ws_info));
+ /* set lws_context_creation_info */
+ ws_info.port = CONTEXT_PORT_NO_LISTEN;
+ ws_info.iface = NULL; /* to bind the listen socket to all */
+ ws_info.protocols = clt_context->protocols;
+ ws_info.extensions = libwebsocket_get_internal_extensions();
+ ws_info.ssl_cert_filepath = NULL;
+ ws_info.ssl_private_key_filepath = NULL;
+ ws_info.ssl_ca_filepath = NULL;
+ ws_info.ssl_cipher_list = NULL;
+ ws_info.gid = -1;
+ ws_info.uid = -1;
+ ws_info.options = 0; /* no special options */
+ ws_info.user = NULL;
+ ws_info.ka_time = 0;
+ ws_info.ka_probes = 0;
+ ws_info.ka_interval = 0;
+
+ /* create a client context */
+ pthread_mutex_lock(&creating_mutex);
+ current_creating_context = clt_context;
+
+ clt_context->ws_context = libwebsocket_create_context(&ws_info);
+ if (clt_context->ws_context == NULL) {
+ /* create context failed */
+ current_creating_context = NULL;
+ pthread_mutex_unlock(&creating_mutex);
+ detail._ico_uws_error.code = ICO_UWS_ERR_CREATE;
+ _ERR("libwebsocket create context failed (%d)",
+ detail._ico_uws_error.code);
+ exec_callback(NULL, ICO_UWS_EVT_ERROR, NULL, &detail, NULL);
+ free(clt_context);
+ return NULL;
+ }
+
+ /* alloc */
+ cpy_uri = strdup((char *)uri);
+ /* split uri and set address, port */
+ strtok(cpy_uri, split_mark); /* delet tag */
+ address = strtok(NULL, split_mark);
+ port = atoi(strtok(NULL, split_mark));
+
+ /* create a client websocket instance */
+ host = address;
+ wsi = libwebsocket_client_connect(clt_context->ws_context,
+ address, port,
+ use_ssl, "/", host, origin,
+ protocol, ietf_version);
+ current_creating_context = NULL;
+ pthread_mutex_unlock(&creating_mutex);
+
+ clt_context->state = ICO_UWS_STATE_CONNECTING;
+ /* free */
+ free(cpy_uri);
+ if (wsi == NULL) {
+ /* client connect failed */
+ detail._ico_uws_error.code = ICO_UWS_ERR_CONNECT;
+ _ERR("libwebsocket client connect failed (%d)",
+ detail._ico_uws_error.code);
+ exec_callback(NULL, ICO_UWS_EVT_ERROR, NULL, &detail, NULL);
+ libwebsocket_context_destroy(clt_context->ws_context);
+ free(clt_context);
+ return NULL;
+ }
+ /* set data */
+ add_ws_instance(clt_context, wsi);
+ strcpy((char *)(clt_context->uri), uri);
+ clt_context->state = ICO_UWS_STATE_OPEN;
+ /* add to the local list */
+ add_context(clt_context);
+ /* client connected */
+ _DBG("client connected address: %s, port: %d", address, port);
+
+ return clt_context;
+}
+
+/*===========================================================================*/
+/* public interface function */
+/*===========================================================================*/
+/*--------------------------------------------------------------------------*/
+/**
+ * @brief ico_uws_create_context
+ * Create ico_uws context.
+ * This API does not support secure access ("wss://") and
+ * the multi protocols.
+ * (If user sets "wss://", this function processes as "ws://".)
+ *
+ * @param[in] uri the uri to which to connect
+ * server sets the string ":(port)"
+ * client sets the string "ws://(host):(port)"
+ * @param[in] protocol the protocol name
+ * @return context
+ * @retval ico_uws context success
+ * @retval NULL error
+ */
+/*--------------------------------------------------------------------------*/
+ICO_API struct ico_uws_context *
+ico_uws_create_context(const char *uri, const char *protocol)
+{
+ struct ico_uws_context *context;
+ ico_uws_detail detail;
+
+ _DBG("ico_uws_create_context called");
+ if (uri == NULL || protocol == NULL) {
+ detail._ico_uws_error.code = ICO_UWS_ERR_INVALID_PARAM;
+ _ERR("invalid param (%d)", detail._ico_uws_error.code);
+ exec_callback(NULL, ICO_UWS_EVT_ERROR, NULL, &detail, NULL);
+ return NULL;
+ }
+
+ if (strncmp(uri, ":", 1) == 0) {
+ /* server */
+ context = create_server(uri, protocol);
+ _DBG("ico_uws_create_context created server context 0x%08x", (int)context);
+ }
+ else if (strstr(uri, URI_WS) != NULL || strstr(uri, URI_WS_SECURE) != NULL) {
+ /* client */
+ context = create_client(uri, protocol);
+ _DBG("ico_uws_create_context created client context 0x%08x", (int)context);
+ }
+ else {
+ detail._ico_uws_error.code = ICO_UWS_ERR_INVALID_PARAM;
+ _ERR("invalid uri (%d)", detail._ico_uws_error.code);
+ exec_callback(NULL, ICO_UWS_EVT_ERROR, NULL, &detail, NULL);
+ return NULL;
+ }
+
+ return context;
+}
+
+/*--------------------------------------------------------------------------*/
+/**
+ * @brief ico_uws_close
+ * Close the connection and destroy the ico_uws context.
+ *
+ * @param[in] context ico_uws context
+ * @return none
+ */
+/*--------------------------------------------------------------------------*/
+ICO_API void
+ico_uws_close(struct ico_uws_context *context)
+{
+ ico_uws_detail detail;
+
+ _DBG("ico_uws_close called");
+ if (context == NULL) {
+ detail._ico_uws_error.code = ICO_UWS_ERR_INVALID_PARAM;
+ _ERR("invalid param (%d)", detail._ico_uws_error.code);
+ exec_callback(context, ICO_UWS_EVT_ERROR, NULL, &detail, NULL);
+ return;
+ }
+
+ /* free list */
+ del_connect_list(context);
+
+ /* destroy websocket context */
+ if (context->ws_context != NULL) {
+ (void)libwebsocket_context_destroy(context->ws_context);
+ }
+
+ /* free "protocol name" area */
+ if (context->protocols[PROTOCOL_ICO_UWS].name != NULL) {
+ free((char *)context->protocols[PROTOCOL_ICO_UWS].name);
+ }
+
+ /* free ico_uws_context */
+ (void)del_context(context);
+ if (ctx_list_first == NULL) {
+ /* no context exists in the local, but free list exists */
+ (void)del_context_list();
+ }
+
+ return;
+}
+
+/*--------------------------------------------------------------------------*/
+/**
+ * @brief ico_uws_send
+ * Send data to the connecting server or client.
+ * User needs to call the function "ico_uws_service"
+ * before calling this function.
+ *
+ * @param[in] context ico_uws context
+ * @param[in] id the id to connected to (callback notifies)
+ * @param[in] data the data to send
+ * @param[in] len count of the data bytes
+ * @return none
+ * @see ico_uws_service
+ */
+/*--------------------------------------------------------------------------*/
+ICO_API void
+ico_uws_send(struct ico_uws_context *context, void *id,
+ unsigned char *data, size_t len)
+{
+ int ret = 0;
+ unsigned char buf[DATA_LEN] = {};
+ struct libwebsocket *wsi;
+ ico_uws_detail detail;
+
+ _DBG("ico_uws_send called");
+ if (context == NULL || id == NULL || data == NULL || len <= 0) {
+ detail._ico_uws_error.code = ICO_UWS_ERR_INVALID_PARAM;
+ _ERR("invalid param (%d)", detail._ico_uws_error.code);
+ exec_callback(context, ICO_UWS_EVT_ERROR, id, &detail, NULL);
+ return;
+ }
+
+ wsi = (struct libwebsocket *)id;
+ /* set send data to buffer */
+ memcpy(&buf[LWS_SEND_BUFFER_PRE_PADDING], data, len);
+ /* send data using websocket instance */
+ ret = libwebsocket_write(wsi,
+ &buf[LWS_SEND_BUFFER_PRE_PADDING],
+ len, LWS_WRITE_BINARY);
+ if (ret < 0) {
+ /* libwebsocket write failed */
+ detail._ico_uws_error.code = ICO_UWS_ERR_SEND;
+ _ERR("libwebsocket write failed ret=%d (%d)",
+ ret, detail._ico_uws_error.code);
+ exec_callback(context, ICO_UWS_EVT_ERROR, id, &detail, NULL);
+ }
+
+ return;
+}
+
+/*--------------------------------------------------------------------------*/
+/**
+ * @brief ico_uws_service
+ * Service any pending websocket activity.
+ * This function deals with any pending websocket traffic,
+ * so you need to call this function periodically.
+ *
+ * @param[in] context ico_uws context
+ * @return none
+ */
+/*--------------------------------------------------------------------------*/
+ICO_API void
+ico_uws_service(struct ico_uws_context *context)
+{
+ int timedout_ms = 0;
+ ico_uws_detail detail;
+
+ if (context == NULL) {
+ detail._ico_uws_error.code = ICO_UWS_ERR_INVALID_PARAM;
+ _ERR("invalid param (%d)", detail._ico_uws_error.code);
+ exec_callback(context, ICO_UWS_EVT_ERROR, NULL, &detail, NULL);
+ return;
+ }
+
+ /* service any pending websocket activity */
+ (void)libwebsocket_service(context->ws_context, timedout_ms);
+
+ return;
+}
+
+/*--------------------------------------------------------------------------*/
+/**
+ * @brief ico_uws_get_uri
+ * Get the uri that is connecting to now.
+ *
+ * @param[in] context ico_uws context
+ * @return uri
+ * @retval data of string success
+ * @retval NULL error
+ */
+/*--------------------------------------------------------------------------*/
+ICO_API char *
+ico_uws_get_uri(struct ico_uws_context *context)
+{
+ ico_uws_detail detail;
+
+ _DBG("ico_uws_get_uri called");
+ if (context == NULL) {
+ detail._ico_uws_error.code = ICO_UWS_ERR_INVALID_PARAM;
+ _ERR("invalid param (%d)", detail._ico_uws_error.code);
+ exec_callback(context, ICO_UWS_EVT_ERROR, NULL, &detail, NULL);
+ return NULL;
+ }
+
+ _DBG("return uri: %s", context->uri);
+ return context->uri;
+}
+
+/*--------------------------------------------------------------------------*/
+/**
+ * @brief ico_uws_get_ready_state
+ * Get the state of connection.
+ *
+ * @param[in] context ico_uws context
+ * @return state
+ * @retval >= 0 success
+ * @retval ICO_UWS_STATE_UNKNOWN error
+ */
+/*--------------------------------------------------------------------------*/
+ICO_API ico_uws_state_e
+ico_uws_get_ready_state(struct ico_uws_context *context)
+{
+ ico_uws_detail detail;
+
+ _DBG("ico_uws_get_ready_state called");
+ if (context == NULL) {
+ detail._ico_uws_error.code = ICO_UWS_ERR_INVALID_PARAM;
+ _ERR("invalid param (%d)", detail._ico_uws_error.code);
+ exec_callback(context, ICO_UWS_EVT_ERROR, NULL, &detail, NULL);
+ return ICO_UWS_STATE_UNKNOWN;
+ }
+
+ _DBG("return state: %d", context->state);
+ return context->state;
+}
+
+/*--------------------------------------------------------------------------*/
+/**
+ * @brief ico_uws_set_event_cb
+ * Set the event callback function.
+ *
+ * @param[in] context ico_uws context
+ * @param[in] callback callback function
+ * @param[in] user_data user data
+ * @return result
+ * @retval ICO_UWS_ERR_NONE success
+ * @retval others error
+ */
+/*--------------------------------------------------------------------------*/
+ICO_API int
+ico_uws_set_event_cb(struct ico_uws_context *context,
+ ico_uws_evt_cb callback, void *user_data)
+{
+ ico_uws_detail detail;
+ int i;
+
+ _DBG("ico_uws_set_event_cb called");
+ if (context == NULL || callback == NULL) {
+ /* invalid parameter */
+ _ERR("invalid param");
+ return ICO_UWS_ERR_INVALID_PARAM;
+ }
+
+ /* set callback & user data */
+ context->callback = callback;
+ context->user_data = user_data;
+
+ /* call callback */
+ for (i = 0; i < ICO_UWS_MAX_FDS; i++) {
+ if (context->callback_fd_list[i].fd != 0) {
+ detail._ico_uws_fd.fd = context->callback_fd_list[i].fd;
+ context->callback_fd_list[i].fd = 0;
+ exec_callback(context, ICO_UWS_EVT_ADD_FD,
+ context->callback_fd_list[i].wsi, &detail, NULL);
+ }
+ }
+
+ return ICO_UWS_ERR_NONE;
+}
+
+/*--------------------------------------------------------------------------*/
+/**
+ * @brief ico_uws_unset_event_cb
+ * Unset the event callback function.
+ *
+ * @param[in] context ico_uws context
+ * @return none
+ */
+/*--------------------------------------------------------------------------*/
+ICO_API void
+ico_uws_unset_event_cb(struct ico_uws_context *context)
+{
+ _DBG("ico_uws_unset_event_cb called");
+
+ if (context == NULL) {
+ /* invalid parameter */
+ _ERR("invalid param");
+ return;
+ }
+
+ /* unset callback & user data */
+ context->callback = NULL;
+ context->user_data = NULL;
+
+ return;
+}
diff --git a/test/Makefile.am b/test/Makefile.am
new file mode 100644
index 0000000..45f88b6
--- /dev/null
+++ b/test/Makefile.am
@@ -0,0 +1,37 @@
+TESTS_ENVIRONMENT = $(SHELL) $(top_srcdir)/test/run_test.sh
+
+export abs_builddir
+
+AM_CFLAGS = $(GCC_CFLAGS)
+AM_CPPFLAGS = $(GCC_CFLAGS)
+
+noinst_PROGRAMS = \
+ tst_ico_uws_client \
+ tst_ico_uws_server \
+ tst_ico_uws_multi_client \
+ tst_ico_uws_multi_server
+
+check_LTLIBRARIES = $(TESTS)
+check_PROGRAMS = tst_ico_uws_client tst_ico_uws_server tst_ico_uws_multi_client tst_ico_uws_multi_server
+
+test_common_lib = -lwebsockets
+test_target_lib = ../src/.libs/libico-util-com.so
+
+tst_ico_uws_client_SOURCES = tst_ico_uws_client.c
+tst_ico_uws_client_CFLAGS = -I../include $(OPT_CFLAGS)
+tst_ico_uws_client_LDADD = $(test_target_lib) $(OPT_LIBS) $(test_common_lib)
+
+tst_ico_uws_server_SOURCES = tst_ico_uws_server.c
+tst_ico_uws_server_CFLAGS = -I../include $(OPT_CFLAGS)
+tst_ico_uws_server_LDADD = $(test_target_lib) $(OPT_LIBS) $(test_common_lib)
+
+tst_ico_uws_multi_client_SOURCES = tst_ico_uws_multi_client.c
+tst_ico_uws_multi_client_CFLAGS = -I../include $(OPT_CFLAGS)
+tst_ico_uws_multi_client_LDADD = $(test_target_lib) $(OPT_LIBS) $(test_common_lib)
+
+tst_ico_uws_multi_server_SOURCES = tst_ico_uws_multi_server.c
+tst_ico_uws_multi_server_CFLAGS = -I../include $(OPT_CFLAGS)
+tst_ico_uws_multi_server_LDADD = $(test_target_lib) $(OPT_LIBS) $(test_common_lib)
+
+EXTRA_DIST = run_test.sh
+
diff --git a/test/run_test.sh b/test/run_test.sh
new file mode 100755
index 0000000..dd9c881
--- /dev/null
+++ b/test/run_test.sh
@@ -0,0 +1,331 @@
+#!/bin/sh
+
+########################
+#
+# Setting value
+#
+########################
+# directory to put test's result in
+rslt_dir="./result"
+log_dir="${rslt_dir}/full_log"
+# number of tests
+num_tst_loop=1
+
+# test log tag
+tst_tag="TestCase"
+
+# log file name (common)
+date_str=`date '+%Y%m%d'`
+time_str=`date '+%H%M'`
+file_str="${date_str}_${time_str}.txt"
+srv_file_str="server_${file_str}"
+clt_file_str="client_${file_str}"
+
+# set library path
+export LD_LIBRARY_PATH=../src/.libs:$LD_LIBRARY_PATH
+
+########################
+#
+# Make a directory to put test's result in
+#
+########################
+if [ ! -e ${rslt_dir} ]; then
+ mkdir ${rslt_dir}
+fi
+if [ ! -e ${log_dir} ]; then
+ mkdir ${log_dir}
+fi
+
+########################
+#
+# Set the number of the test's loop
+# (if argument exists)
+#
+########################
+if [ $# -ne 0 ]; then
+ if expr "$1" : '[0-9]*' > /dev/null ; then
+ num_tst_loop=$1
+ fi
+fi
+
+########################
+#
+# Function
+#
+########################
+kill_old_proc()
+{
+ pids=(`ps -ef | grep tst_ico_uws | grep -v grep | awk '{ print $2 }'`)
+ for pid in ${pids[*]}
+ do
+ kill -9 ${pid}
+ done
+}
+
+check_srv_no_exist()
+{
+ while :
+ do
+ proc_srv=`pgrep -lf "$1"`
+ if [ -n "${proc_srv}" ]; then
+ break
+ fi
+ # sleep while process of server does not exist
+ usleep 100000
+ done
+}
+
+check_srv_exist()
+{
+ while :
+ do
+ proc_srv=`pgrep -lf "$1"`
+ if [ -z "${proc_srv}" ]; then
+ break
+ fi
+ # sleep while process of server exists
+ sleep 1
+ done
+}
+
+print_result()
+{
+ local l_type="$1"
+ local l_log="$2"
+ local l_log_total="$3"
+ local l_cnt_ok=0
+ local l_cnt_ng=0
+ local l_str=""
+
+ # title
+ echo "" | tee -a ${l_log_total}
+ echo "----- ${l_type} result -----" | tee -a ${l_log_total}
+ # count OK/NG, and output console and file
+ l_cnt_ok=`grep ${tst_tag} ${l_log} | grep "OK" | wc -l`
+ l_cnt_ng=`grep ${tst_tag} ${l_log} | grep "NG" | wc -l`
+ l_str="<<Results Total>> OK: ${l_cnt_ok}, NG: ${l_cnt_ng}"
+ l_str="${l_str} (num of tests: ${num_tst_loop})"
+ echo "${l_str}" | tee -a ${l_log_total}
+ # grep test result, and output to file
+ grep ${tst_tag} ${l_log} | tee -a ${l_log_total}
+}
+
+exec_test()
+{
+ local l_tst_no="0$3"
+ local l_app_srv="./$1"
+ local l_app_clt="./$2"
+
+ local l_log_srv="${log_dir}/tst${l_tst_no}_${srv_file_str}"
+ local l_log_clt="${log_dir}/tst${l_tst_no}_${clt_file_str}"
+ local l_log_total="${rslt_dir}/tst${l_tst_no}_${file_str}"
+
+ # kill old process if exists
+ kill_old_proc
+
+ sleep 1
+
+ for i in `seq 1 ${num_tst_loop}`
+ do
+ # execute server
+ ${l_app_srv} >> ${l_log_srv} &
+ # sleep while process of server does not exist
+ check_srv_no_exist ${l_app_srv}
+ # execute client
+ ${l_app_clt} >> ${l_log_clt}
+
+ # sleep while process of server exists
+ check_srv_exist ${l_app_srv}
+ done
+
+ print_result "Server" ${l_log_srv} ${l_log_total}
+ print_result "Client" ${l_log_clt} ${l_log_total}
+ sleep 1
+}
+
+exec_test_multi_clt()
+{
+ local l_tst_no="0$4"
+ local l_app_srv="./$1"
+ local l_app_clt="./$2"
+ local l_app_clt_sec="./$3"
+
+ local l_log_srv="${log_dir}/tst${l_tst_no}_${srv_file_str}"
+ local l_log_clt="${log_dir}/tst${l_tst_no}_client0_${file_str}"
+ local l_log_clt_sec="${log_dir}/tst${l_tst_no}_client1_${file_str}"
+ local l_log_total="${rslt_dir}/tst${l_tst_no}_${file_str}"
+
+ # kill old process if exists
+ kill_old_proc
+
+ sleep 1
+
+ for i in `seq 1 ${num_tst_loop}`
+ do
+ # execute server
+ ${l_app_srv} >> ${l_log_srv} &
+ # sleep while process of server does not exist
+ check_srv_no_exist ${l_app_srv}
+ # execute client
+ ${l_app_clt} >> ${l_log_clt} &
+ usleep 100
+ ${l_app_clt_sec} >> ${l_log_clt_sec}
+
+ # sleep while process of server exists
+ check_srv_exist ${l_app_srv}
+ done
+
+ print_result "Server" ${l_log_srv} ${l_log_total}
+ print_result "Client 0" ${l_log_clt} ${l_log_total}
+ print_result "Client 1" ${l_log_clt_sec} ${l_log_total}
+ sleep 1
+}
+
+exec_test_multi_srv()
+{
+ local l_tst_no="0$4"
+ local l_app_srv="./$1"
+ local l_app_srv_sec="./$2"
+ local l_app_clt="./$3"
+
+ local l_log_srv="${log_dir}/tst${l_tst_no}_server0_${file_str}"
+ local l_log_srv_sec="${log_dir}/tst${l_tst_no}_server0_${file_str}"
+ local l_log_clt="${log_dir}/tst${l_tst_no}_${clt_file_str}"
+ local l_log_total="${rslt_dir}/tst${l_tst_no}_${file_str}"
+
+ # kill old process if exists
+ kill_old_proc
+
+ sleep 1
+
+ for i in `seq 1 ${num_tst_loop}`
+ do
+ # execute server
+ ${l_app_srv} >> ${l_log_srv} &
+ usleep 500
+ ${l_app_srv_sec} >> ${l_log_srv_sec} &
+ # sleep while process of server does not exist
+ check_srv_no_exist ${l_app_srv}
+ check_srv_no_exist ${l_app_srv_sec}
+ # execute client
+ ${l_app_clt} >> ${l_log_clt}
+
+ # sleep while process of server exists
+ check_srv_exist ${l_app_srv}
+ check_srv_exist ${l_app_srv_sec}
+ done
+
+ print_result "Server 0" ${l_log_srv} ${l_log_total}
+ print_result "Server 1" ${l_log_srv_sec} ${l_log_total}
+ print_result "Client" ${l_log_clt} ${l_log_total}
+ sleep 1
+}
+
+########################
+#
+# Test Start
+#
+########################
+echo ""
+echo "=== API Test Start ==="
+
+########################
+#
+# API Test (1)
+# 1 server / 1 client
+#
+########################
+# application
+app_srv="tst_ico_uws_server -p 8080"
+app_clt="tst_ico_uws_client -p 8080"
+
+# test & output result
+echo ""
+tst_no=1
+echo "=== API Test ($tst_no) <<1 server, 1 client>> Start ==="
+exec_test "${app_srv}" "${app_clt}" ${tst_no}
+echo "=== API Test ($tst_no) <<1 server, 1 client>> End ==="
+
+
+########################
+#
+# API Test (2)
+# 1 server / 2 client
+#
+########################
+# application
+app_srv="tst_ico_uws_server -p 8080"
+app_clt="tst_ico_uws_client -p 8080"
+
+# test & output result
+echo ""
+tst_no=2
+echo "=== API Test ($tst_no) <<1 server, 2 client>> Start ==="
+exec_test_multi_clt "${app_srv}" "${app_clt}" "${app_clt}" ${tst_no}
+echo "=== API Test ($tst_no) <<1 server, 2 client>> End ==="
+
+
+########################
+#
+# API Test (3)
+# 2 server / 1 client (2 thread)
+#
+########################
+# application
+app_srv="tst_ico_uws_server -p 8080"
+app_srv_sec="tst_ico_uws_server -p 9090"
+app_clt="tst_ico_uws_multi_client"
+
+# test & output result
+echo ""
+tst_no=3
+echo "=== API Test ($tst_no) <<2 server, 1 client>> Start ==="
+exec_test_multi_srv "${app_srv}" "${app_srv_sec}" "${app_clt}" ${tst_no}
+echo "=== API Test ($tst_no) <<2 server, 1 client>> End ==="
+
+
+########################
+#
+# API Test (4)
+# 1 server (2 thread) / 1 client (2 thread)
+#
+########################
+# application
+app_srv="tst_ico_uws_multi_server"
+app_clt="tst_ico_uws_multi_client"
+
+# test & output result
+echo ""
+tst_no=4
+echo "=== API Test ($tst_no) <<multi server, multi client>> Start ==="
+exec_test "${app_srv}" "${app_clt}" ${tst_no}
+echo "=== API Test ($tst_no) <<multi server, multi client>> End ==="
+
+
+########################
+#
+# API Test (5)
+# 1 server (2 thread) / 2 client (2 process)
+#
+########################
+# application
+app_srv="tst_ico_uws_multi_server"
+app_clt="tst_ico_uws_client -p 8080"
+app_clt_sec="tst_ico_uws_client -p 9090"
+
+# test & output result
+echo ""
+tst_no=5
+echo "=== API Test ($tst_no) <<multi server, 2 client>> Start ==="
+exec_test_multi_clt "${app_srv}" "${app_clt}" "${app_clt_sec}" ${tst_no}
+echo "=== API Test ($tst_no) <<multi server, 2 client>> End ==="
+
+
+########################
+#
+# Test End
+#
+########################
+echo "=== API Test End ==="
+echo ""
+
diff --git a/test/tst_ico_uws.h b/test/tst_ico_uws.h
new file mode 100644
index 0000000..9c33f05
--- /dev/null
+++ b/test/tst_ico_uws.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2013, TOYOTA MOTOR CORPORATION.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0. The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+
+#ifndef __TST_ICO_UWS_H__
+#define __TST_ICO_UWS_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define dbg_print(fmt, ...) \
+ printf("[TestCase] " fmt, __VA_ARGS__);
+
+#define TEST_OK "OK"
+#define TEST_NG "NG"
+
+#define SET_FLAG 1
+#define UNSET_FLAG 0
+
+#define SRV_URI "ws://127.0.0.1"
+#define SRV_PORT "8080"
+#define PROTOCOL_NAME "test_protocol"
+
+#define CLT_DATA "test data from client"
+
+#define MAX_DATA_NUM 2
+
+char *srv_ports[MAX_DATA_NUM] = {SRV_PORT, "9090"};
+char *clt_datas[MAX_DATA_NUM] = {CLT_DATA, "test to send data"};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __TST_ICO_UWS_H__ */
diff --git a/test/tst_ico_uws_client.c b/test/tst_ico_uws_client.c
new file mode 100644
index 0000000..7647e9c
--- /dev/null
+++ b/test/tst_ico_uws_client.c
@@ -0,0 +1,368 @@
+/*
+ * Copyright (c) 2013, TOYOTA MOTOR CORPORATION.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0. The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+/**
+ * @brief test client (socket library for communicate)
+ *
+ * @date June-7-2013
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include "ico_uws.h"
+
+#include "tst_ico_uws.h"
+
+/* ----------------------------------------------- */
+/* Variable */
+/* ----------------------------------------------- */
+#define SLEEP_TIME 2
+
+/* context */
+static struct ico_uws_context *clt_context;
+static void *clt_id;
+
+/* receive event check */
+static int receive_flag = UNSET_FLAG;
+
+/* callback function is setting or not setting */
+static int set_cb_flag = UNSET_FLAG;
+static int num_call_cb = 0;
+
+/* ----------------------------------------------- */
+/* Define of static function */
+/* ----------------------------------------------- */
+static void tst_uws_callback(const struct ico_uws_context *context,
+ const ico_uws_evt_e event,
+ const void *id,
+ const ico_uws_detail *detail,
+ void *user_data);
+static void tst_create_context(char *uri);
+static void tst_get_ready_state(int state, char *str_state);
+static void tst_get_uri(char *set_uri);
+static void tst_send(unsigned char *data);
+static void tst_service(void);
+static void tst_close(void);
+static void tst_set_evt_callback(unsigned char *send_data);
+static void tst_unset_evt_callback(void);
+static int ico_uws_client_test(char *uri, unsigned char *data);
+
+/* ----------------------------------------------- */
+/* Public API Test */
+/* ----------------------------------------------- */
+/* event callback */
+static void
+tst_uws_callback(const struct ico_uws_context *context,
+ const ico_uws_evt_e event,
+ const void *id,
+ const ico_uws_detail *detail,
+ void *user_data)
+{
+ char str[256];
+ char *ret_str;
+
+ num_call_cb++;
+ if (set_cb_flag == SET_FLAG) {
+ ret_str = TEST_OK;
+ }
+ else {
+ ret_str = TEST_NG;
+ }
+
+ /* set id */
+ clt_id = (void *)id;
+
+ switch (event) {
+ case ICO_UWS_EVT_OPEN:
+ sprintf(str, "open");
+ if (clt_context != NULL) {
+ tst_get_ready_state(ICO_UWS_STATE_OPEN, "open");
+ }
+ break;
+ case ICO_UWS_EVT_ERROR:
+ sprintf(str, "error");
+ if (detail->_ico_uws_error.code == ICO_UWS_ERR_SEND) {
+ dbg_print("ico_uws_service (client) : %s\n", TEST_NG);
+ dbg_print("ico_uws_send (client) : %s\n", TEST_NG);
+ receive_flag = SET_FLAG;
+ }
+ break;
+ case ICO_UWS_EVT_CLOSE:
+ sprintf(str, "close");
+ if (clt_context != NULL) {
+ tst_get_ready_state(ICO_UWS_STATE_CLOSED, "close");
+ }
+ break;
+ case ICO_UWS_EVT_RECEIVE:
+ sprintf(str, "receive");
+ char *data = (char *)detail->_ico_uws_message.recv_data;
+ if (strcmp((char *)user_data, data) != 0) {
+ dbg_print("ico_uws_send (client) : %s\n", TEST_NG);
+ } else {
+ dbg_print("ico_uws_send (client) : %s\n", TEST_OK);
+ }
+ sprintf(str, "%s '%s'", str, data);
+ receive_flag = SET_FLAG;
+ break;
+ case ICO_UWS_EVT_ADD_FD:
+ sprintf(str, "add fd(%d)", detail->_ico_uws_fd.fd);
+ break;
+ case ICO_UWS_EVT_DEL_FD:
+ sprintf(str, "delete fd(%d)", detail->_ico_uws_fd.fd);
+ break;
+ default:
+ /* other event is not test */
+ break;
+ }
+ dbg_print("ico_uws_evt_cb [%d (%s)] (client) : %s\n",
+ event, str, ret_str);
+
+ return;
+}
+
+/* create context */
+static void
+tst_create_context(char *uri)
+{
+ char *ret_str = TEST_OK;
+
+ clt_context = ico_uws_create_context(uri, PROTOCOL_NAME);
+ if (clt_context == NULL) {
+ ret_str = TEST_NG;
+ }
+ dbg_print("ico_uws_create_context (client) : %s\n", ret_str);
+
+ return;
+}
+
+/* get ready state */
+static void
+tst_get_ready_state(int state, char *str_state)
+{
+ char *ret_str = TEST_OK;
+
+ ico_uws_state_e cur_state = ico_uws_get_ready_state(clt_context);
+ if (cur_state != state) {
+ ret_str = TEST_NG;
+ }
+ dbg_print("ico_uws_get_ready_state [%s] (client) : %s\n",
+ str_state, ret_str);
+
+ return;
+}
+
+/* get uri */
+static void
+tst_get_uri(char *set_uri)
+{
+ char *ret_str = TEST_OK;
+
+ char *uri = ico_uws_get_uri(clt_context);
+ if (strcmp(uri, set_uri) != 0) {
+ ret_str = TEST_NG;
+ }
+ dbg_print("ico_uws_get_uri [%s] (client) : %s\n",
+ uri, ret_str);
+
+ return;
+}
+
+/* send data */
+static void
+tst_send(unsigned char *data)
+{
+ int i;
+ size_t len = strlen((char *)data) + 1;
+
+ for (i = 0; i < 10; i++) {
+ ico_uws_service(clt_context);
+ usleep(100);
+ }
+ ico_uws_send(clt_context, clt_id, data, len);
+
+ return;
+}
+
+/* service loop (wait to receive data) */
+static void
+tst_service()
+{
+ char *ret_str = TEST_OK;
+
+ /* wait to close the connection */
+ while (receive_flag == UNSET_FLAG) {
+ ico_uws_service(clt_context);
+ usleep(50);
+ }
+ receive_flag = UNSET_FLAG;
+ dbg_print("ico_uws_service (client) : %s\n", ret_str);
+
+ return;
+}
+
+/* close */
+static void
+tst_close()
+{
+ char *ret_str = TEST_OK;
+
+ ico_uws_close(clt_context);
+ dbg_print("ico_uws_close (client) : %s\n", ret_str);
+
+ return;
+}
+
+/* set callback */
+static void
+tst_set_evt_callback(unsigned char *send_data)
+{
+ int ret;
+ char *ret_str = TEST_OK;
+
+ /* set callback */
+ set_cb_flag = SET_FLAG;
+ ret = ico_uws_set_event_cb(clt_context, tst_uws_callback,
+ (void *)send_data);
+ if (ret != ICO_UWS_ERR_NONE) {
+ ret_str = TEST_NG;
+ dbg_print("ico_uws_set_event_cb (client) : %s (%d)\n",
+ ret_str, ret);
+ return;
+ }
+
+ dbg_print("ico_uws_set_event_cb (client) : %s\n", ret_str);
+
+ return;
+}
+
+/* unset callback */
+static void
+tst_unset_evt_callback()
+{
+ char *ret_str = TEST_OK;
+
+ /* unset callback */
+ ico_uws_unset_event_cb(clt_context);
+ set_cb_flag = UNSET_FLAG;
+ num_call_cb = 0;
+
+ /* occurs the error event */
+ (void)ico_uws_get_uri(NULL);
+ sleep(SLEEP_TIME);
+ if (num_call_cb > 0) {
+ ret_str = TEST_NG;
+ }
+
+ dbg_print("ico_uws_unset_event_cb (client) : %s\n", ret_str);
+
+ return;
+}
+
+/* test main (to connect to single server) */
+static int
+ico_uws_client_test(char *uri, unsigned char *data)
+{
+ /* create context */
+ tst_create_context(uri);
+
+ /* set callback */
+ tst_set_evt_callback(data);
+
+ /* interval */
+ sleep(SLEEP_TIME);
+
+ if (clt_context) {
+ /* get uri */
+ tst_get_uri(uri);
+
+ /* send data */
+ tst_send(data);
+
+ /* wait to receive data */
+ tst_service();
+
+ /* interval */
+ sleep(SLEEP_TIME);
+
+ /* unset callback */
+ tst_unset_evt_callback();
+
+ /* close */
+ tst_close();
+ }
+
+ return 1;
+}
+
+/* ----------------------------------------------- */
+/* Main */
+/* ----------------------------------------------- */
+static GMainLoop *g_mainloop = NULL;
+
+static gboolean
+exit_program(gpointer data)
+{
+ g_main_loop_quit(g_mainloop);
+
+ return FALSE;
+}
+
+/* main */
+int
+main(int argc, char **argv)
+{
+ char uri[128];
+ unsigned char data[256];
+ int id;
+ int set_uri_flag = UNSET_FLAG;
+ int set_data_flag = UNSET_FLAG;
+
+ for (id = 0; id < argc; id++) {
+ if (strcmp(argv[id], "-p") == 0) {
+ /* set uri to connect */
+ id++;
+ sprintf(uri, "%s:%s", SRV_URI, argv[id]);
+ set_uri_flag = SET_FLAG;
+ }
+ else if (strcmp(argv[id], "-d") == 0) {
+ /* set data to send */
+ id++;
+ sprintf((char *)data, "%s", argv[id]);
+ data[strlen(argv[id]) + 1] = '\0';
+ set_data_flag = SET_FLAG;
+ }
+ }
+
+ /* set default uri to connect */
+ if (set_uri_flag == UNSET_FLAG) {
+ sprintf(uri, "%s:%s", SRV_URI, SRV_PORT);
+ }
+
+ /* set default data to send */
+ if (set_data_flag == UNSET_FLAG) {
+ sprintf((char *)data, "%s", CLT_DATA);
+ }
+
+ g_setenv("PKG_NAME", "org.tizen.ico.tst_ico_uws_client", 1);
+ g_mainloop = g_main_loop_new(NULL, 0);
+
+ printf("\n");
+ printf("##### ico_uws API (client) Test Start #####\n");
+ ico_uws_client_test(uri, data);
+ printf("##### ico_uws API (client) Test End #####\n");
+ printf("\n");
+
+ g_timeout_add_seconds(2, exit_program, NULL);
+ g_main_loop_run(g_mainloop);
+
+ return 0;
+}
diff --git a/test/tst_ico_uws_multi_client.c b/test/tst_ico_uws_multi_client.c
new file mode 100644
index 0000000..06fab7d
--- /dev/null
+++ b/test/tst_ico_uws_multi_client.c
@@ -0,0 +1,548 @@
+/*
+ * Copyright (c) 2013, TOYOTA MOTOR CORPORATION.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0. The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+/**
+ * @brief test client to connect to multi servers
+ * (socket library for communicate)
+ *
+ * @date June-27-2013
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include "ico_uws.h"
+
+#include "tst_ico_uws.h"
+
+/* ----------------------------------------------- */
+/* Variable */
+/* ----------------------------------------------- */
+#define SLEEP_TIME 3
+
+struct tst_client_t{
+ struct tst_client_t *next;
+ struct ico_uws_context *context;
+ char uri[128];
+ unsigned char data[256];
+ size_t len;
+ void *clt_id; /* use to send data */
+ int receive_flag;
+ int open_flag;
+ int set_cb_flag;
+ int num_call_cb;
+ int id;
+};
+
+struct tst_client_t *first_clt = NULL;
+struct tst_client_t *second_clt = NULL;
+
+/* pthread mutex initialize */
+static pthread_mutex_t multi_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* ----------------------------------------------- */
+/* Define of static function */
+/* ----------------------------------------------- */
+static void tst_uws_callback(const struct ico_uws_context *context,
+ const ico_uws_evt_e event,
+ const void *id,
+ const ico_uws_detail *detail,
+ void *user_data);
+static void tst_create_context(struct tst_client_t *clt_t);
+static void tst_get_ready_state(struct tst_client_t *clt_t,
+ int state, char *str_state);
+static void tst_get_uri(struct tst_client_t *clt_t);
+static void tst_send(struct tst_client_t *clt_t);
+static void tst_service_open(struct tst_client_t *clt_t);
+static void tst_service_receive(struct tst_client_t *clt_t);
+static void tst_close(struct tst_client_t *clt_t);
+static void tst_set_evt_callback(struct tst_client_t *clt_t);
+static void tst_unset_evt_callback(struct tst_client_t *clt_t);
+static struct tst_client_t *ico_uws_client_test_init(int id);
+static void *tst_client_thread(void *args);
+static void *tst_client_thread_sec(void *args);
+static int ico_uws_client_test_multi(void);
+
+/* ----------------------------------------------- */
+/* Public API Test */
+/* ----------------------------------------------- */
+/* event callback */
+static void
+tst_uws_callback(const struct ico_uws_context *context,
+ const ico_uws_evt_e event,
+ const void *id,
+ const ico_uws_detail *detail,
+ void *user_data)
+{
+ char str[256];
+ char *ret_str;
+ struct tst_client_t *clt_t;
+
+ if (context == NULL) return;
+
+ if (first_clt != NULL && context == first_clt->context) {
+ clt_t = first_clt;
+ }
+ else if (second_clt != NULL && context == second_clt->context) {
+ clt_t = second_clt;
+ }
+ else {
+ return;
+ }
+
+ clt_t->num_call_cb++;
+ if (clt_t->set_cb_flag == SET_FLAG) {
+ ret_str = TEST_OK;
+ }
+ else {
+ ret_str = TEST_NG;
+ }
+
+ switch (event) {
+ case ICO_UWS_EVT_OPEN:
+ sprintf(str, "open");
+ clt_t->clt_id = (void *)id;
+ clt_t->open_flag = SET_FLAG;
+ break;
+ case ICO_UWS_EVT_ERROR:
+ sprintf(str, "error");
+ if (detail->_ico_uws_error.code == ICO_UWS_ERR_SEND) {
+ dbg_print("ico_uws_service (client %d) : %s\n",
+ clt_t->id, TEST_NG);
+ dbg_print("ico_uws_send (client %d) : %s\n",
+ clt_t->id, TEST_NG);
+ clt_t->receive_flag = SET_FLAG;
+ }
+ break;
+ case ICO_UWS_EVT_CLOSE:
+ sprintf(str, "close");
+ tst_get_ready_state(clt_t, ICO_UWS_STATE_CLOSED, "close");
+ break;
+ case ICO_UWS_EVT_RECEIVE:
+ sprintf(str, "receive");
+ char *data = (char *)detail->_ico_uws_message.recv_data;
+ char *send_data = (char *)clt_t->data;
+ if (strcmp(send_data, data) != 0) {
+ dbg_print("ico_uws_send (client %d) : %s\n",
+ clt_t->id, TEST_NG);
+ } else {
+ dbg_print("ico_uws_send (client %d) : %s\n",
+ clt_t->id, TEST_OK);
+ }
+ clt_t->receive_flag = SET_FLAG;
+ sprintf(str, "%s '%s'", str, data);
+ break;
+ case ICO_UWS_EVT_ADD_FD:
+ sprintf(str, "add fd(%d)", detail->_ico_uws_fd.fd);
+ break;
+ case ICO_UWS_EVT_DEL_FD:
+ sprintf(str, "delete fd(%d)", detail->_ico_uws_fd.fd);
+ break;
+ default:
+ /* other event is not test */
+ break;
+ }
+
+ printf("@@@ ico_uws_evt_cb [%d (%s)] (client %d) : %s\n",
+ event, str, clt_t->id, ret_str);
+
+ return;
+}
+
+/* create context */
+static void
+tst_create_context(struct tst_client_t *clt_t)
+{
+ char *ret_str = TEST_OK;
+
+ /* mutex lock */
+ pthread_mutex_lock(&multi_mutex);
+ clt_t->context = ico_uws_create_context(clt_t->uri, PROTOCOL_NAME);
+ /* mutex unlock */
+ pthread_mutex_unlock(&multi_mutex);
+ if (clt_t->context == NULL) {
+ ret_str = TEST_NG;
+ }
+ dbg_print("ico_uws_create_context (client %d) : %s\n",
+ clt_t->id, ret_str);
+
+ return;
+}
+
+/* get ready state */
+static void
+tst_get_ready_state(struct tst_client_t *clt_t,
+ int state, char *str_state)
+{
+ char *ret_str = TEST_OK;
+
+ /* mutex lock */
+ pthread_mutex_lock(&multi_mutex);
+ ico_uws_state_e cur_state = ico_uws_get_ready_state(clt_t->context);
+ /* mutex unlock */
+ pthread_mutex_unlock(&multi_mutex);
+ if (cur_state != state) {
+ ret_str = TEST_NG;
+ }
+ dbg_print("ico_uws_get_ready_state [%s] (client %d) : %s\n",
+ str_state, clt_t->id, ret_str);
+
+ return;
+}
+
+/* get uri */
+static void
+tst_get_uri(struct tst_client_t *clt_t)
+{
+ char *ret_str = TEST_OK;
+
+ /* mutex lock */
+ pthread_mutex_lock(&multi_mutex);
+ char *uri = ico_uws_get_uri(clt_t->context);
+ /* mutex unlock */
+ pthread_mutex_unlock(&multi_mutex);
+ if (strcmp(uri, clt_t->uri) != 0) {
+ ret_str = TEST_NG;
+ }
+ dbg_print("ico_uws_get_uri [%s] (client %d) : %s\n",
+ uri, clt_t->id, ret_str);
+
+ return;
+}
+
+/* send data */
+static void
+tst_send(struct tst_client_t *clt_t)
+{
+ int i;
+
+ for (i = 0; i < 10; i++) {
+ /* mutex lock */
+ pthread_mutex_lock(&multi_mutex);
+ ico_uws_service(clt_t->context);
+ /* mutex unlock */
+ pthread_mutex_unlock(&multi_mutex);
+ usleep(100);
+ }
+
+ /* mutex lock */
+ pthread_mutex_lock(&multi_mutex);
+ ico_uws_send(clt_t->context, clt_t->clt_id, clt_t->data, clt_t->len);
+ /* mutex unlock */
+ pthread_mutex_unlock(&multi_mutex);
+
+ return;
+}
+
+/* service loop (wait to open) */
+static void
+tst_service_open(struct tst_client_t *clt_t)
+{
+ char *ret_str = TEST_OK;
+
+ while (clt_t->open_flag == UNSET_FLAG) {
+ /* mutex lock */
+ pthread_mutex_lock(&multi_mutex);
+ ico_uws_service(clt_t->context);
+ /* mutex unlock */
+ pthread_mutex_unlock(&multi_mutex);
+ usleep(50);
+ }
+ clt_t->open_flag = UNSET_FLAG;
+ dbg_print("ico_uws_service (client %d open) : %s\n", clt_t->id, ret_str);
+
+ return;
+}
+
+/* service loop (wait to receive data) */
+static void
+tst_service_receive(struct tst_client_t *clt_t)
+{
+ char *ret_str = TEST_OK;
+
+ while (clt_t->receive_flag == UNSET_FLAG) {
+ /* mutex lock */
+ pthread_mutex_lock(&multi_mutex);
+ ico_uws_service(clt_t->context);
+ /* mutex unlock */
+ pthread_mutex_unlock(&multi_mutex);
+ usleep(50);
+ }
+ clt_t->receive_flag = UNSET_FLAG;
+ dbg_print("ico_uws_service (client %d receive) : %s\n", clt_t->id, ret_str);
+
+ return;
+}
+
+/* close */
+static void
+tst_close(struct tst_client_t *clt_t)
+{
+ char *ret_str = TEST_OK;
+
+ /* mutex lock */
+ pthread_mutex_lock(&multi_mutex);
+ ico_uws_close(clt_t->context);
+ /* mutex unlock */
+ pthread_mutex_unlock(&multi_mutex);
+
+ dbg_print("ico_uws_close (client %d) : %s\n", clt_t->id, ret_str);
+
+ return;
+}
+
+/* set callback */
+static void
+tst_set_evt_callback(struct tst_client_t *clt_t)
+{
+ int ret;
+ char *ret_str = TEST_OK;
+
+ clt_t->set_cb_flag = SET_FLAG;
+ /* mutex lock */
+ pthread_mutex_lock(&multi_mutex);
+ /* set callback */
+ ret = ico_uws_set_event_cb(clt_t->context, tst_uws_callback, NULL);
+ /* mutex unlock */
+ pthread_mutex_unlock(&multi_mutex);
+ if (ret != ICO_UWS_ERR_NONE) {
+ ret_str = TEST_NG;
+ dbg_print("ico_uws_set_event_cb (client %d) : %s (%d)\n",
+ clt_t->id, ret_str, ret);
+ return;
+ }
+
+ dbg_print("ico_uws_set_event_cb (client %d) : %s\n",
+ clt_t->id, ret_str);
+
+ return;
+}
+
+/* unset callback */
+static void
+tst_unset_evt_callback(struct tst_client_t *clt_t)
+{
+ char *ret_str = TEST_OK;
+
+ /* mutex lock */
+ pthread_mutex_lock(&multi_mutex);
+ /* unset callback */
+ ico_uws_unset_event_cb(clt_t->context);
+ /* mutex unlock */
+ pthread_mutex_unlock(&multi_mutex);
+
+ clt_t->set_cb_flag = UNSET_FLAG;
+ clt_t->num_call_cb = 0;
+
+ /* mutex lock */
+ pthread_mutex_lock(&multi_mutex);
+ /* occurs the error event */
+ (void)ico_uws_get_uri(NULL);
+ /* mutex unlock */
+ pthread_mutex_unlock(&multi_mutex);
+ sleep(SLEEP_TIME);
+ if (clt_t->num_call_cb > 0) {
+ ret_str = TEST_NG;
+ }
+
+ dbg_print("ico_uws_unset_event_cb (client %d) : %s\n",
+ clt_t->id, ret_str);
+
+ return;
+}
+
+/* prepare for test */
+static struct tst_client_t *
+ico_uws_client_test_init(int id)
+{
+ struct tst_client_t *clt_t;
+
+ clt_t = calloc(1, sizeof(struct tst_client_t));
+ if (clt_t == NULL) {
+ printf("calloc failed\n");
+ return NULL;
+ }
+
+ /* set uri to connect to */
+ sprintf(clt_t->uri, "%s:%s", SRV_URI, srv_ports[id]);
+ /* set data to send */
+ sprintf((char *)clt_t->data, "%s", clt_datas[id]);
+ clt_t->len = strlen(clt_datas[id]) + 1;
+ clt_t->data[clt_t->len] = '\0';
+
+ /* initialize */
+ clt_t->context = NULL;
+ clt_t->clt_id = NULL;
+ clt_t->receive_flag = UNSET_FLAG;
+ clt_t->open_flag = UNSET_FLAG;
+ clt_t->set_cb_flag = UNSET_FLAG;
+ clt_t->num_call_cb = 0;
+ clt_t->id = id;
+
+ return clt_t;
+}
+
+/* ----------------------------------------------- */
+/* Test Main */
+/* ----------------------------------------------- */
+static void *
+tst_client_thread(void *args)
+{
+ /* prepare for test */
+ first_clt = ico_uws_client_test_init(0);
+ if (first_clt == NULL) {
+ return NULL;
+ }
+
+ /* create context */
+ tst_create_context(first_clt);
+
+ if (first_clt->context != NULL) {
+ /* set callback */
+ tst_set_evt_callback(first_clt);
+
+ /* wait to open */
+ tst_service_open(first_clt);
+
+ /* check the state */
+ tst_get_ready_state(first_clt, ICO_UWS_STATE_OPEN, "open");
+
+ /* check the uri */
+ tst_get_uri(first_clt);
+
+ /* send data */
+ tst_send(first_clt);
+
+ /* wait to receive data */
+ tst_service_receive(first_clt);
+
+ /* interval */
+ sleep(SLEEP_TIME);
+
+ /* unset callback */
+ tst_unset_evt_callback(first_clt);
+
+ /* interval */
+ sleep(SLEEP_TIME);
+
+ /* session close */
+ tst_close(first_clt);
+ }
+ /* free memory */
+ free(first_clt);
+
+ return NULL;
+}
+
+static void *
+tst_client_thread_sec(void *args)
+{
+ /* prepare for test */
+ second_clt = ico_uws_client_test_init(1);
+ if (second_clt == NULL) {
+ return NULL;
+ }
+
+ /* create context */
+ tst_create_context(second_clt);
+
+ if (second_clt->context != NULL) {
+ /* set callback */
+ tst_set_evt_callback(second_clt);
+
+ /* wait to open */
+ tst_service_open(second_clt);
+
+ /* check the state */
+ tst_get_ready_state(second_clt, ICO_UWS_STATE_OPEN, "open");
+
+ /* check the uri */
+ tst_get_uri(second_clt);
+
+ /* send data */
+ tst_send(second_clt);
+
+ /* wait to receive data */
+ tst_service_receive(second_clt);
+
+ /* interval */
+ sleep(SLEEP_TIME);
+
+ /* unset callback */
+ tst_unset_evt_callback(second_clt);
+
+ /* interval */
+ sleep(SLEEP_TIME);
+
+ /* session close */
+ tst_close(second_clt);
+ }
+
+ /* free memory */
+ free(second_clt);
+
+ return NULL;
+}
+
+/* test main (to connect to multi servers) */
+static int
+ico_uws_client_test_multi()
+{
+ pthread_t thread, thread_sec;
+
+ /* client to connect server (port: 8080) */
+ pthread_create( &thread, NULL, tst_client_thread, (void *)NULL );
+ /* client to connect server (port: 9090) */
+ pthread_create( &thread_sec, NULL, tst_client_thread_sec, (void *)NULL );
+
+ pthread_join( thread, NULL );
+ pthread_join( thread_sec, NULL );
+
+ /* interval */
+ sleep(SLEEP_TIME);
+
+ return 1;
+}
+
+/* ----------------------------------------------- */
+/* Main */
+/* ----------------------------------------------- */
+static GMainLoop *g_mainloop = NULL;
+
+static gboolean
+exit_program(gpointer data)
+{
+ g_main_loop_quit(g_mainloop);
+
+ return FALSE;
+}
+
+/* main */
+int
+main(int argc, char **argv)
+{
+ g_setenv("PKG_NAME", "org.tizen.ico.tst_ico_uws_mlt_client", 1);
+ g_mainloop = g_main_loop_new(NULL, 0);
+
+ printf("\n");
+ printf("##### ico_uws API (client to connect to multi servers)");
+ printf(" Test Start #####\n");
+ ico_uws_client_test_multi();
+ printf("##### ico_uws API (client to connect to multi servers)");
+ printf(" Test End #####\n");
+ printf("\n");
+
+ g_timeout_add_seconds(2, exit_program, NULL);
+ g_main_loop_run(g_mainloop);
+
+ return 0;
+}
diff --git a/test/tst_ico_uws_multi_server.c b/test/tst_ico_uws_multi_server.c
new file mode 100644
index 0000000..ba928d1
--- /dev/null
+++ b/test/tst_ico_uws_multi_server.c
@@ -0,0 +1,541 @@
+/*
+ * Copyright (c) 2013, TOYOTA MOTOR CORPORATION.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0. The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+/**
+ * @brief test server to listen to multi servers
+ * (socket library for communicate)
+ *
+ * @date June-27-2013
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include "ico_uws.h"
+
+#include "tst_ico_uws.h"
+
+/* ----------------------------------------------- */
+/* Variable */
+/* ----------------------------------------------- */
+#define SLEEP_TIME 3
+
+struct tst_server_t{
+ struct tst_server_t *next;
+ struct ico_uws_context *context;
+ char uri[128];
+ unsigned char data[256];
+ size_t len;
+ void *srv_id; /* use to send data */
+ int receive_flag;
+ int close_flag;
+ int set_cb_flag;
+ int num_call_cb;
+ int id;
+};
+
+struct tst_server_t *first_srv = NULL;
+struct tst_server_t *second_srv = NULL;
+
+/* pthread mutex initialize */
+static pthread_mutex_t multi_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* ----------------------------------------------- */
+/* Define of static function */
+/* ----------------------------------------------- */
+static void tst_uws_callback(const struct ico_uws_context *context,
+ const ico_uws_evt_e event,
+ const void *id,
+ const ico_uws_detail *detail,
+ void *user_data);
+static void tst_create_context(struct tst_server_t *srv_t);
+static void tst_get_ready_state(struct tst_server_t *srv_t,
+ int state, char *str_state);
+static void tst_get_uri(struct tst_server_t *srv_t);
+static void tst_send(struct tst_server_t *srv_t);
+static void tst_service_receive(struct tst_server_t *srv_t);
+static void tst_service_close(struct tst_server_t *srv_t);
+static void tst_close(struct tst_server_t *srv_t);
+static void tst_set_evt_callback(struct tst_server_t *srv_t);
+static void tst_unset_evt_callback(struct tst_server_t *srv_t);
+static struct tst_server_t *ico_uws_server_test_init(int id);
+static void *tst_server_thread(void *args);
+static void *tst_server_thread_sec(void *args);
+static int ico_uws_server_test_multi(void);
+
+/* ----------------------------------------------- */
+/* Public API Test */
+/* ----------------------------------------------- */
+/* event callback */
+static void
+tst_uws_callback(const struct ico_uws_context *context,
+ const ico_uws_evt_e event,
+ const void *id,
+ const ico_uws_detail *detail,
+ void *user_data)
+{
+ char str[256];
+ char *ret_str;
+ struct tst_server_t *srv_t;
+
+ if (context == NULL) return;
+
+ if (first_srv != NULL && context == first_srv->context) {
+ srv_t = first_srv;
+ }
+ else if (second_srv != NULL && context == second_srv->context) {
+ srv_t = second_srv;
+ }
+ else {
+ return;
+ }
+
+ srv_t->num_call_cb++;
+ if (srv_t->set_cb_flag == SET_FLAG) {
+ ret_str = TEST_OK;
+ }
+ else {
+ ret_str = TEST_NG;
+ }
+
+ switch (event) {
+ case ICO_UWS_EVT_OPEN:
+ sprintf(str, "open");
+ break;
+ case ICO_UWS_EVT_ERROR:
+ sprintf(str, "error");
+ break;
+ case ICO_UWS_EVT_CLOSE:
+ sprintf(str, "close");
+ srv_t->close_flag = SET_FLAG;
+ break;
+ case ICO_UWS_EVT_RECEIVE:
+ sprintf(str, "receive");
+ /* set id */
+ srv_t->srv_id = (void *)id;
+ char *data = (char *)detail->_ico_uws_message.recv_data;
+ size_t len = detail->_ico_uws_message.recv_len;
+ /* set data to send */
+ sprintf((char *)srv_t->data, "%s", data);
+ srv_t->len = len;
+ srv_t->receive_flag = SET_FLAG;
+ sprintf(str, "%s '%s'", str, data);
+ break;
+ case ICO_UWS_EVT_ADD_FD:
+ sprintf(str, "add fd(%d)", detail->_ico_uws_fd.fd);
+ break;
+ case ICO_UWS_EVT_DEL_FD:
+ sprintf(str, "delete fd(%d)", detail->_ico_uws_fd.fd);
+ break;
+ default:
+ /* other event is not test */
+ break;
+ }
+
+ printf("@@@ ico_uws_evt_cb [%d (%s)] (server %d) : %s\n",
+ event, str, srv_t->id, ret_str);
+
+ return;
+}
+
+/* create context */
+static void
+tst_create_context(struct tst_server_t *srv_t)
+{
+ char *ret_str = TEST_OK;
+
+ /* mutex lock */
+ pthread_mutex_lock(&multi_mutex);
+ srv_t->context = ico_uws_create_context(srv_t->uri, PROTOCOL_NAME);
+ /* mutex unlock */
+ pthread_mutex_unlock(&multi_mutex);
+ if (srv_t->context == NULL) {
+ ret_str = TEST_NG;
+ }
+ dbg_print("ico_uws_create_context (server %d) : %s\n",
+ srv_t->id, ret_str);
+
+ return;
+}
+
+/* get ready state */
+static void
+tst_get_ready_state(struct tst_server_t *srv_t,
+ int state, char *str_state)
+{
+ char *ret_str = TEST_OK;
+
+ /* mutex lock */
+ pthread_mutex_lock(&multi_mutex);
+ ico_uws_state_e cur_state = ico_uws_get_ready_state(srv_t->context);
+ /* mutex unlock */
+ pthread_mutex_unlock(&multi_mutex);
+ if (cur_state != state) {
+ ret_str = TEST_NG;
+ }
+ dbg_print("ico_uws_get_ready_state [%s] (server %d) : %s\n",
+ str_state, srv_t->id, ret_str);
+
+ return;
+}
+
+/* get uri */
+static void
+tst_get_uri(struct tst_server_t *srv_t)
+{
+ char *ret_str = TEST_OK;
+
+ /* mutex lock */
+ pthread_mutex_lock(&multi_mutex);
+ char *uri = ico_uws_get_uri(srv_t->context);
+ /* mutex unlock */
+ pthread_mutex_unlock(&multi_mutex);
+ if (strcmp(uri, srv_t->uri) != 0) {
+ ret_str = TEST_NG;
+ }
+ dbg_print("ico_uws_get_uri [%s] (server %d) : %s\n",
+ uri, srv_t->id, ret_str);
+
+ return;
+}
+
+/* send data */
+static void
+tst_send(struct tst_server_t *srv_t)
+{
+ int i;
+
+ for (i = 0; i < 10; i++) {
+ /* mutex lock */
+ pthread_mutex_lock(&multi_mutex);
+ ico_uws_service(srv_t->context);
+ /* mutex unlock */
+ pthread_mutex_unlock(&multi_mutex);
+ usleep(100);
+ }
+
+ /* mutex lock */
+ pthread_mutex_lock(&multi_mutex);
+ ico_uws_send(srv_t->context, srv_t->srv_id, srv_t->data, srv_t->len);
+ /* mutex unlock */
+ pthread_mutex_unlock(&multi_mutex);
+
+ return;
+}
+
+/* service loop (wait to receive data) */
+static void
+tst_service_receive(struct tst_server_t *srv_t)
+{
+ char *ret_str = TEST_OK;
+
+ while (srv_t->receive_flag == UNSET_FLAG) {
+ /* mutex lock */
+ pthread_mutex_lock(&multi_mutex);
+ ico_uws_service(srv_t->context);
+ /* mutex unlock */
+ pthread_mutex_unlock(&multi_mutex);
+ usleep(50);
+ }
+ srv_t->receive_flag = UNSET_FLAG;
+ dbg_print("ico_uws_service (server %d received) : %s\n", srv_t->id, ret_str);
+
+ return;
+}
+
+/* service loop (wait to close connection) */
+static void
+tst_service_close(struct tst_server_t *srv_t)
+{
+ char *ret_str = TEST_OK;
+
+ while (srv_t->close_flag == UNSET_FLAG) {
+ /* mutex lock */
+ pthread_mutex_lock(&multi_mutex);
+ ico_uws_service(srv_t->context);
+ /* mutex unlock */
+ pthread_mutex_unlock(&multi_mutex);
+ usleep(50);
+ }
+ srv_t->close_flag = UNSET_FLAG;
+ dbg_print("ico_uws_service (server %d close) : %s\n", srv_t->id, ret_str);
+
+ return;
+}
+
+/* close */
+static void
+tst_close(struct tst_server_t *srv_t)
+{
+ char *ret_str = TEST_OK;
+
+ /* mutex lock */
+ pthread_mutex_lock(&multi_mutex);
+ ico_uws_close(srv_t->context);
+ /* mutex unlock */
+ pthread_mutex_unlock(&multi_mutex);
+
+ dbg_print("ico_uws_close (server %d) : %s\n", srv_t->id, ret_str);
+
+ return;
+}
+
+/* set callback */
+static void
+tst_set_evt_callback(struct tst_server_t *srv_t)
+{
+ int ret;
+ char *ret_str = TEST_OK;
+
+ srv_t->set_cb_flag = SET_FLAG;
+ /* mutex lock */
+ pthread_mutex_lock(&multi_mutex);
+ /* set callback */
+ ret = ico_uws_set_event_cb(srv_t->context, tst_uws_callback, NULL);
+ /* mutex unlock */
+ pthread_mutex_unlock(&multi_mutex);
+ if (ret != ICO_UWS_ERR_NONE) {
+ ret_str = TEST_NG;
+ dbg_print("ico_uws_set_event_cb (server %d) : %s (%d)\n",
+ srv_t->id, ret_str, ret);
+ return;
+ }
+
+ dbg_print("ico_uws_set_event_cb (server %d) : %s\n",
+ srv_t->id, ret_str);
+
+ return;
+}
+
+/* unset callback */
+static void
+tst_unset_evt_callback(struct tst_server_t *srv_t)
+{
+ char *ret_str = TEST_OK;
+
+ /* mutex lock */
+ pthread_mutex_lock(&multi_mutex);
+ /* unset callback */
+ ico_uws_unset_event_cb(srv_t->context);
+ /* mutex unlock */
+ pthread_mutex_unlock(&multi_mutex);
+
+ srv_t->set_cb_flag = UNSET_FLAG;
+ srv_t->num_call_cb = 0;
+
+ /* mutex lock */
+ pthread_mutex_lock(&multi_mutex);
+ /* occurs the error event */
+ (void)ico_uws_get_uri(NULL);
+ /* mutex unlock */
+ pthread_mutex_unlock(&multi_mutex);
+ sleep(SLEEP_TIME);
+ if (srv_t->num_call_cb > 0) {
+ ret_str = TEST_NG;
+ }
+
+ dbg_print("ico_uws_unset_event_cb (server %d) : %s\n",
+ srv_t->id, ret_str);
+
+ return;
+}
+
+/* prepare for test */
+static struct tst_server_t *
+ico_uws_server_test_init(int id)
+{
+ struct tst_server_t *srv_t;
+
+ srv_t = calloc(1, sizeof(struct tst_server_t));
+ if (srv_t == NULL) {
+ printf("calloc failed\n");
+ return NULL;
+ }
+
+ /* set uri to connect to */
+ sprintf(srv_t->uri, ":%s", srv_ports[id]);
+
+ /* initialize */
+ srv_t->context = NULL;
+ srv_t->srv_id = NULL;
+ srv_t->receive_flag = UNSET_FLAG;
+ srv_t->close_flag = UNSET_FLAG;
+ srv_t->set_cb_flag = UNSET_FLAG;
+ srv_t->num_call_cb = 0;
+ srv_t->id = id;
+
+ return srv_t;
+}
+
+/* ----------------------------------------------- */
+/* Test Main */
+/* ----------------------------------------------- */
+static void *
+tst_server_thread(void *args)
+{
+ /* prepare for test */
+ first_srv = ico_uws_server_test_init(0);
+ if (first_srv == NULL) {
+ return NULL;
+ }
+
+ /* create context */
+ tst_create_context(first_srv);
+
+ if (first_srv->context != NULL) {
+ /* set callback */
+ tst_set_evt_callback(first_srv);
+
+ /* check the state */
+ tst_get_ready_state(first_srv, ICO_UWS_STATE_CONNECTING,
+ "connecting");
+
+ /* check the uri */
+ tst_get_uri(first_srv);
+
+ /* wait to receive data */
+ tst_service_receive(first_srv);
+
+ /* send data */
+ tst_send(first_srv);
+
+ /* wait to close connection */
+ tst_service_close(first_srv);
+
+ /* check the state */
+ tst_get_ready_state(first_srv, ICO_UWS_STATE_CLOSED, "close");
+
+ /* interval */
+ sleep(SLEEP_TIME);
+
+ /* unset callback */
+ tst_unset_evt_callback(first_srv);
+
+ /* interval */
+ sleep(SLEEP_TIME);
+
+ /* session close */
+ tst_close(first_srv);
+ }
+ /* free memory */
+ free(first_srv);
+
+ return NULL;
+}
+
+static void *
+tst_server_thread_sec(void *args)
+{
+ /* prepare for test */
+ second_srv = ico_uws_server_test_init(1);
+ if (second_srv == NULL) {
+ return NULL;
+ }
+
+ /* create context */
+ tst_create_context(second_srv);
+
+ if (second_srv->context != NULL) {
+ /* set callback */
+ tst_set_evt_callback(second_srv);
+
+ /* check the state */
+ tst_get_ready_state(second_srv, ICO_UWS_STATE_CONNECTING,
+ "connecting");
+
+ /* check the uri */
+ tst_get_uri(second_srv);
+
+ /* wait to receive data */
+ tst_service_receive(second_srv);
+
+ /* send data */
+ tst_send(second_srv);
+
+ /* wait to close connection */
+ tst_service_close(second_srv);
+
+ /* check the state */
+ tst_get_ready_state(second_srv, ICO_UWS_STATE_CLOSED, "close");
+
+ /* interval */
+ sleep(SLEEP_TIME);
+
+ /* unset callback */
+ tst_unset_evt_callback(second_srv);
+
+ /* interval */
+ sleep(SLEEP_TIME);
+
+ /* session close */
+ tst_close(second_srv);
+ }
+
+ /* free memory */
+ free(second_srv);
+
+ return NULL;
+}
+
+/* test main (to connect to multi servers) */
+static int
+ico_uws_server_test_multi()
+{
+ pthread_t thread, thread_sec;
+
+ /* server to connect server (port: 8080) */
+ pthread_create( &thread, NULL, tst_server_thread, (void *)NULL );
+ /* server to connect server (port: 9090) */
+ pthread_create( &thread_sec, NULL, tst_server_thread_sec, (void *)NULL );
+
+ pthread_join( thread, NULL );
+ pthread_join( thread_sec, NULL );
+
+ /* interval */
+ sleep(SLEEP_TIME);
+
+ return 1;
+}
+
+/* ----------------------------------------------- */
+/* Main */
+/* ----------------------------------------------- */
+static GMainLoop *g_mainloop = NULL;
+
+static gboolean
+exit_program(gpointer data)
+{
+ g_main_loop_quit(g_mainloop);
+
+ return FALSE;
+}
+
+/* main */
+int
+main(int argc, char **argv)
+{
+ g_setenv("PKG_NAME", "org.tizen.ico.tst_ico_uws_mlt_server", 1);
+ g_mainloop = g_main_loop_new(NULL, 0);
+
+ printf("\n");
+ printf("##### ico_uws API (server to listen to multi clients)");
+ printf(" Test Start #####\n");
+ ico_uws_server_test_multi();
+ printf("##### ico_uws API (server to listen to multi clients)");
+ printf(" Test End #####\n");
+ printf("\n");
+
+ g_timeout_add_seconds(2, exit_program, NULL);
+ g_main_loop_run(g_mainloop);
+
+ return 0;
+}
diff --git a/test/tst_ico_uws_server.c b/test/tst_ico_uws_server.c
new file mode 100644
index 0000000..28d5c40
--- /dev/null
+++ b/test/tst_ico_uws_server.c
@@ -0,0 +1,328 @@
+/*
+ * Copyright (c) 2013, TOYOTA MOTOR CORPORATION.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0. The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+/**
+ * @brief test server (socket library for communicate)
+ *
+ * @date June-7-2013
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include "ico_uws.h"
+
+#include "tst_ico_uws.h"
+
+/* ----------------------------------------------- */
+/* Variable */
+/* ----------------------------------------------- */
+#define SLEEP_TIME 2
+
+/* context */
+static struct ico_uws_context *context;
+
+/* close event check */
+static int close_flag = UNSET_FLAG;
+static int num_connect = 0;
+
+/* callback function is setting or not setting */
+static int set_cb_flag = UNSET_FLAG;
+static int num_call_cb = 0;
+
+/* ----------------------------------------------- */
+/* Define of static function */
+/* ----------------------------------------------- */
+static void tst_uws_callback(const struct ico_uws_context *context,
+ const ico_uws_evt_e event,
+ const void *id,
+ const ico_uws_detail *detail,
+ void *user_data);
+static void tst_create_context(char *uri);
+static void tst_get_ready_state(int state, char *str_state);
+static void tst_get_uri(char *set_uri);
+static void tst_service(void);
+static void tst_close(void);
+static void tst_set_evt_callback(void);
+static void tst_unset_evt_callback(void);
+static int ico_uws_server_test(char *uri);
+
+/* ----------------------------------------------- */
+/* Public API Test */
+/* ----------------------------------------------- */
+/* event callback */
+static void
+tst_uws_callback(const struct ico_uws_context *context,
+ const ico_uws_evt_e event,
+ const void *id,
+ const ico_uws_detail *detail,
+ void *user_data)
+{
+ char str[256];
+ char *ret_str;
+
+ num_call_cb++;
+ if (set_cb_flag == SET_FLAG) {
+ ret_str = TEST_OK;
+ }
+ else {
+ ret_str = TEST_NG;
+ }
+
+ switch (event) {
+ case ICO_UWS_EVT_OPEN:
+ sprintf(str, "open");
+ num_connect++;
+ if (context != NULL) {
+ tst_get_ready_state(ICO_UWS_STATE_OPEN, "open");
+ }
+ break;
+ case ICO_UWS_EVT_ERROR:
+ sprintf(str, "error");
+ break;
+ case ICO_UWS_EVT_CLOSE:
+ sprintf(str, "close");
+ num_connect--;
+ if (num_connect == 0) {
+ close_flag = SET_FLAG;
+ }
+ if (context != NULL) {
+ tst_get_ready_state(ICO_UWS_STATE_CLOSED, "close");
+ }
+ break;
+ case ICO_UWS_EVT_RECEIVE:
+ sprintf(str, "receive");
+ ico_uws_send((struct ico_uws_context *)context,
+ (void *)id,
+ (unsigned char *)detail->_ico_uws_message.recv_data,
+ detail->_ico_uws_message.recv_len);
+ sprintf(str, "%s '%s'",
+ str, (unsigned char *)detail->_ico_uws_message.recv_data);
+ break;
+ case ICO_UWS_EVT_ADD_FD:
+ sprintf(str, "add fd(%d)", detail->_ico_uws_fd.fd);
+ break;
+ case ICO_UWS_EVT_DEL_FD:
+ sprintf(str, "delete fd(%d)", detail->_ico_uws_fd.fd);
+ break;
+ default:
+ /* other event is not test */
+ break;
+ }
+ dbg_print("ico_uws_evt_cb [%d (%s)] (server) : %s\n",
+ event, str, ret_str);
+
+ return;
+}
+
+/* create context */
+static void
+tst_create_context(char *uri)
+{
+ char *ret_str = TEST_OK;
+
+ context = ico_uws_create_context(uri, PROTOCOL_NAME);
+ if (context == NULL) {
+ ret_str = TEST_NG;
+ }
+ num_connect = 0;
+ dbg_print("ico_uws_create_context (server) : %s\n", ret_str);
+
+ return;
+}
+
+/* get ready state */
+static void
+tst_get_ready_state(int state, char *str_state)
+{
+ char *ret_str = TEST_OK;
+
+ ico_uws_state_e cur_state = ico_uws_get_ready_state(context);
+ if (cur_state != state) {
+ ret_str = TEST_NG;
+ }
+ dbg_print("ico_uws_get_ready_state [%s] (server) : %s\n",
+ str_state, ret_str);
+
+ return;
+}
+
+/* get uri */
+static void
+tst_get_uri(char *set_uri)
+{
+ char *ret_str = TEST_OK;
+
+ char *uri = ico_uws_get_uri(context);
+ if (strcmp(uri, set_uri) != 0) {
+ ret_str = TEST_NG;
+ }
+ dbg_print("ico_uws_get_uri [%s] (server) : %s\n",
+ uri, ret_str);
+
+ return;
+}
+
+/* service loop */
+static void
+tst_service()
+{
+ char *ret_str = TEST_OK;
+
+ close_flag = UNSET_FLAG;
+ /* wait to close the connection */
+ while (close_flag == UNSET_FLAG) {
+ ico_uws_service(context);
+ usleep(50);
+ }
+ dbg_print("ico_uws_service (server) : %s\n", ret_str);
+
+ return;
+}
+
+/* close */
+static void
+tst_close()
+{
+ char *ret_str = TEST_OK;
+
+ ico_uws_close(context);
+ dbg_print("ico_uws_close (server) : %s\n", ret_str);
+
+ return;
+}
+
+/* set callback */
+static void
+tst_set_evt_callback()
+{
+ int ret;
+ char *ret_str = TEST_OK;
+
+ /* set callback */
+ set_cb_flag = SET_FLAG;
+ ret = ico_uws_set_event_cb(context, tst_uws_callback, NULL);
+ if (ret != ICO_UWS_ERR_NONE) {
+ ret_str = TEST_NG;
+ dbg_print("ico_uws_set_event_cb (server) : %s (%d)\n",
+ ret_str, ret);
+ return;
+ }
+
+ dbg_print("ico_uws_set_event_cb (server) : %s\n", ret_str);
+
+ return;
+}
+
+/* unset callback */
+static void
+tst_unset_evt_callback()
+{
+ char *ret_str = TEST_OK;
+
+ /* unset callback */
+ ico_uws_unset_event_cb(context);
+ set_cb_flag = UNSET_FLAG;
+ num_call_cb = 0;
+
+ /* occurs the error event */
+ (void)ico_uws_get_uri(NULL);
+ sleep(SLEEP_TIME);
+ if (num_call_cb > 0) {
+ ret_str = TEST_NG;
+ }
+
+ dbg_print("ico_uws_unset_event_cb (server) : %s\n", ret_str);
+
+ return;
+}
+
+/* test main (server) */
+static int
+ico_uws_server_test(char *uri)
+{
+ /* create context */
+ tst_create_context(uri);
+
+ if (context) {
+ /* set callback */
+ tst_set_evt_callback();
+
+ /* client does not connect */
+ tst_get_ready_state(ICO_UWS_STATE_CONNECTING, "connecting");
+
+ /* get uri */
+ tst_get_uri(uri);
+
+ /* service (loop) */
+ tst_service();
+
+ /* interval */
+ sleep(SLEEP_TIME);
+
+ /* unset callback */
+ tst_unset_evt_callback();
+
+ /* close */
+ tst_close();
+ }
+
+ return 1;
+}
+
+/* ----------------------------------------------- */
+/* Main */
+/* ----------------------------------------------- */
+static GMainLoop *g_mainloop = NULL;
+
+static gboolean
+exit_program(gpointer data)
+{
+ g_main_loop_quit(g_mainloop);
+
+ return FALSE;
+}
+
+/* main */
+int
+main(int argc, char **argv)
+{
+ char uri[256];
+ int id;
+ int set_uri_flag = UNSET_FLAG;
+
+ for (id = 0; id < argc; id++) {
+ if (strcmp(argv[id], "-p") == 0) {
+ id++;
+ sprintf(uri, ":%s", argv[id]);
+ set_uri_flag = SET_FLAG;
+ }
+ }
+
+ /* set default uri */
+ if (set_uri_flag == UNSET_FLAG) {
+ sprintf(uri, ":%s", SRV_PORT);
+ }
+
+ g_setenv("PKG_NAME", "org.tizen.ico.tst_ico_uws_server", 1);
+ g_mainloop = g_main_loop_new(NULL, 0);
+
+ printf("\n");
+ printf("##### ico_uws API (server) Test Start #####\n");
+ ico_uws_server_test(uri);
+ printf("##### ico_uws API (server) Test End #####\n");
+ printf("\n");
+
+ g_timeout_add_seconds(2, exit_program, NULL);
+ g_main_loop_run(g_mainloop);
+
+ return 0;
+}