--- /dev/null
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+*/
+
+#if defined VINE_EVENT_LOOP_EXTERNAL_GLIB
+#include <glib.h>
+#include <unistd.h>
+#include <stdint.h>
+
+#include "vine.h"
+#include "vine-event-loop.h"
+#include "vine-queue.h"
+#include "vine-log.h"
+#include "vine-utils.h"
+
+typedef struct {
+ int fd;
+ vine_poll_handler handler;
+ void *user_data;
+ guint g_source_id;
+} vine_glib_io_event_handler;
+
+#define MAX_IO_EVENT_HANDLERS FD_SETSIZE
+static vine_glib_io_event_handler *io_event_handlers[MAX_IO_EVENT_HANDLERS] = {0, };
+
+#ifdef FD_SETSIZE
+#define MAX_IO_EVENT_HANDLERS FD_SETSIZE
+#else
+#define MAX_IO_EVENT_HANDLERS MAX_VINE_FDS
+#endif
+
+int vine_event_loop_glib_init()
+{
+ return VINE_ERROR_NONE;
+}
+
+void vine_event_loop_glib_deinit()
+{
+}
+
+int vine_event_loop_glib_start()
+{
+ return VINE_ERROR_NONE;
+}
+
+void vine_event_loop_glib_stop()
+{
+}
+
+int vine_event_queue_glib_create(vine_event_queue_h *event_queue)
+{
+ return VINE_ERROR_NONE;
+}
+
+void vine_event_queue_glib_destroy(vine_event_queue_h event_queue)
+{
+}
+
+void vine_event_loop_glib_get_eventfd(vine_event_queue_h event_queue, int *eventfd)
+{
+}
+
+static void _add_io_event_handler(int fd, vine_glib_io_event_handler *h)
+{
+ if (io_event_handlers[fd])
+ free(io_event_handlers[fd]);
+ io_event_handlers[fd] = h;
+}
+
+static void _del_io_event_handler(int fd)
+{
+ if (io_event_handlers[fd]) {
+ free(io_event_handlers[fd]);
+ io_event_handlers[fd] = NULL;
+ }
+}
+
+static vine_glib_io_event_handler *_find_io_event_handler(int fd)
+{
+ return io_event_handlers[fd];
+}
+
+static int convert_glib_cond_to_poll_events(GIOCondition condition)
+{
+ int events = 0;
+ if (condition & G_IO_IN)
+ events |= VINE_POLLIN;
+ if (condition & G_IO_OUT)
+ events |= VINE_POLLOUT;
+ if (condition & G_IO_HUP)
+ events |= VINE_POLLHUP;
+ return events;
+}
+
+static GIOCondition convert_poll_events_to_glib_cond(int events)
+{
+ int cond = 0;
+ if (events & VINE_POLLIN)
+ cond |= G_IO_IN;
+ if (events & VINE_POLLOUT)
+ cond |= G_IO_OUT;
+ if (events & VINE_POLLHUP)
+ cond |= G_IO_HUP;
+ return (GIOCondition)cond;
+}
+
+static gboolean __vine_glib_io_handler(GIOChannel *source,
+ GIOCondition condition,
+ gpointer data)
+{
+ RET_VAL_IF(data == NULL, TRUE, "vine_glib_io_event_handler is NULL");
+ vine_glib_io_event_handler *h = (vine_glib_io_event_handler *)data;
+ if (h->handler)
+ h->handler(h->fd, convert_glib_cond_to_poll_events(condition), h->user_data);
+ return TRUE;
+}
+
+int vine_event_loop_glib_add_io_handler(
+ int fd, int events, vine_poll_handler handler, void *user_data)
+{
+ RET_VAL_IF(fd < 0, VINE_ERROR_INVALID_PARAMETER,
+ "fd should be equal to or greater than zero");
+ RET_VAL_IF(handler == NULL, VINE_ERROR_INVALID_PARAMETER,
+ "handler should not be null");
+
+ vine_glib_io_event_handler *h =
+ (vine_glib_io_event_handler *)calloc(1, sizeof(vine_glib_io_event_handler));
+ RET_VAL_IF(h == NULL, VINE_ERROR_OUT_OF_MEMORY, "Out of memory");
+ h->fd = fd;
+ h->handler = handler;
+ h->user_data = user_data;
+
+ GIOChannel *ch = g_io_channel_unix_new(fd);
+ g_io_channel_set_flags(ch, G_IO_FLAG_NONBLOCK, NULL);
+ g_io_channel_set_close_on_unref(ch, FALSE);
+ h->g_source_id = g_io_add_watch(ch,
+ convert_poll_events_to_glib_cond(events), __vine_glib_io_handler, h);
+
+ _add_io_event_handler(fd, h);
+ return VINE_ERROR_NONE;
+}
+
+int vine_event_loop_glib_del_io_handler(int fd)
+{
+ RET_VAL_IF(fd < 0, VINE_ERROR_INVALID_PARAMETER,
+ "fd should be equal to or greater than zero");
+
+ vine_glib_io_event_handler *handler = _find_io_event_handler(fd);
+ if (handler == NULL) {
+ VINE_LOGE("vine_glib_io_event_handler is NULL for fd %d", fd);
+ return VINE_ERROR_INVALID_PARAMETER;
+ }
+ g_source_remove(handler->g_source_id);
+ _del_io_event_handler(fd);
+ VINE_LOGD("Del an glib event. fd: %d", fd);
+
+ return VINE_ERROR_NONE;
+}
+
+int vine_event_loop_glib_mod_io_handler(
+ int fd, int events, vine_poll_handler handler, void *user_data)
+{
+ RET_VAL_IF(fd < 0, VINE_ERROR_INVALID_PARAMETER,
+ "fd should be equal to or greater than zero");
+ RET_VAL_IF(handler == NULL, VINE_ERROR_INVALID_PARAMETER,
+ "handler should not be null");
+
+ vine_event_loop_glib_del_io_handler(fd);
+ vine_event_loop_glib_add_io_handler(fd, events, handler, user_data);
+ VINE_LOGD("Modify an glib event. fd: %d event: %d", fd, events);
+
+ return VINE_ERROR_NONE;
+}
+
+int vine_event_loop_glib_add_event(vine_event_queue_h event_queue, void *event_data,
+ vine_event_handler handler, vine_event_free_handler free_func,
+ void *user_data)
+{
+ // Ignore event_queue
+
+ RET_VAL_IF(handler == NULL, VINE_ERROR_INVALID_PARAMETER, "handler is NULL");
+ VINE_LOGD("event_data[%p]", event_data);
+
+ handler(event_data, user_data);
+ if (free_func)
+ free_func(event_data);
+
+ return VINE_ERROR_NONE;
+}
+
+int vine_event_loop_glib_process(vine_event_queue_h event_queue)
+{
+ return VINE_ERROR_NONE;
+}
+
+vine_event_loop_fn vine_event_loop_glib = {
+ .init = vine_event_loop_glib_init,
+ .deinit = vine_event_loop_glib_deinit,
+ .start = vine_event_loop_glib_start,
+ .stop = vine_event_loop_glib_stop,
+ .event_queue_create = vine_event_queue_glib_create,
+ .event_queue_destroy = vine_event_queue_glib_destroy,
+ .get_eventfd = vine_event_loop_glib_get_eventfd,
+ .process = vine_event_loop_glib_process,
+ .add_io_handler = vine_event_loop_glib_add_io_handler,
+ .mod_io_handler = vine_event_loop_glib_mod_io_handler,
+ .del_io_handler = vine_event_loop_glib_del_io_handler,
+ .add_event = vine_event_loop_glib_add_event,
+};
+
+#endif // VINE_EVENT_LOOP_EXTERNAL_GLIB
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <glib.h>
+#include <list>
+#include <iterator>
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+#include <time.h>
+#include <vine.h>
+#include <vine-log.h>
+
+#include "vine-test-utils.h"
+
+#define MAX_EVENTS 16
+#define TEST_DEBUG
+
+#define CHECK_SESSION \
+ do { \
+ if (!g_session) { \
+ _test_print_error("No Session"); \
+ return; \
+ } \
+ } while (0)
+
+#define MAX_SERVICE_TYPE_LEN 16
+#define MAX_SERVICE_NAME_LEN 63
+#define MAX_IP_LEN 39 // for IPv6
+
+#define ROOT_CA_PATH "certs/rootCA/ca.pem"
+#define SERVER_CERT_PATH "certs/server/test-server.pem"
+#define SERVER_PRIVATE_KEY_PATH "certs/server/test-server.key"
+
+GMainLoop *main_loop = NULL;
+static vine_session_h g_session = NULL;
+static vine_service_h g_service = NULL;
+static vine_dp_h g_server_dp = NULL;
+static vine_dp_h g_client_dp = NULL;
+static vine_dp_h g_pubsub_dp = NULL;
+static std::list<vine_dp_h> g_datapath_list;
+static std::list<vine_service_h> g_service_list;
+
+static bool test_get_user_string(const char *msg, char *buf, int buf_size)
+{
+ if (msg == NULL || buf == NULL || buf_size < 2)
+ return false;
+
+ int ret;
+ printf("%s", msg);
+ fflush(stdout);
+ memset(buf, 0, buf_size);
+ ret = read(0, buf, buf_size - 1);
+
+ if (ret < 0 || buf[0] == '\0' || buf[0] == '\n' || buf[0] == '\r') {
+ buf[0] = '\0';
+ return false;
+ }
+
+ buf[ret - 1] = '\0';
+ return true;
+}
+
+static void __quit()
+{
+ PRINT_IF_ERROR(vine_deinitialize(), "vine_initialize()");
+ g_main_loop_quit(main_loop);
+ exit(1);
+}
+
+static void __event_handler(vine_session_h session)
+{
+ printf("Vine Event\n");
+ PRINT_IF_ERROR(vine_session_process_event(session), "vine_process_event");
+}
+
+static void __start_event_loop()
+{
+}
+
+static void __init()
+{
+ PRINT_IF_ERROR(vine_initialize(), "vine_initialize()");
+}
+
+static void __registered_cb(vine_session_h session,
+ const char *service_name, vine_error_e error, void *user_data)
+{
+ if (error == VINE_ERROR_NONE) {
+ PRINT_RESULT(error, "Successfully registered");
+ printf("Service Name: %s\n", service_name);
+ } else if (error == VINE_ERROR_NAME_CONFLICT) {
+ PRINT_RESULT(error, "Successfully registered, but service name conflicted");
+ printf("Service Name: %s\n", service_name);
+ } else {
+ PRINT_IF_ERROR(error, "Failed to register a service");
+ }
+}
+
+static bool __print_attr(const char *key, const char *value, void *user_data)
+{
+ printf("\t > Attributes: %s=%s\n", key, value);
+ return true;
+}
+
+static void __ip_resolved_cb(vine_session_h session, vine_service_h service,
+ const char *ip, vine_address_family_e address_family, /* availability */
+ void *user_data)
+{
+ printf("\t++ IP resolved\n");
+ int ret;
+ char *service_type;
+ char *service_name;
+ int port;
+
+ ret = vine_service_get_type(service, &service_type);
+ PRINT_IF_ERROR(ret, "vine_service_get_type");
+ ret = vine_service_get_name(service, &service_name);
+ PRINT_IF_ERROR(ret, "vine_service_get_name");
+ ret = vine_service_get_port(service, &port);
+ PRINT_IF_ERROR(ret, "vine_service_get_port");
+
+ printf("\t > Service Type: %s\n", service_type);
+ printf("\t > Service Name: %s\n", service_name);
+ printf("\t > IP Address: %s\n", ip);
+ printf("\t > Port: %d\n", port);
+ ret = vine_service_foreach_attribute(service, __print_attr, NULL);
+ PRINT_IF_ERROR(ret, "vine_service_foreach_attribute");
+ printf("\n");
+ fflush(stdout);
+
+ free(service_type);
+ free(service_name);
+}
+
+static void __discovered_cb(vine_session_h session, vine_service_h service,
+ vine_service_state_e state, void *user_data)
+{
+ printf("\t++ Service Discovered\n");
+
+ int ret;
+ char *service_type;
+ char *service_name;
+ int port;
+
+ ret = vine_service_get_type(service, &service_type);
+ PRINT_IF_ERROR(ret, "vine_service_get_type");
+ ret = vine_service_get_name(service, &service_name);
+ PRINT_IF_ERROR(ret, "vine_service_get_name");
+ ret = vine_service_get_port(service, &port);
+ PRINT_IF_ERROR(ret, "vine_service_get_port");
+
+ printf("\t > State: %s\n",
+ state == VINE_SERVICE_UNAVAILABLE ? "Unavailable" : "Available");
+ printf("\t > Service Type: %s\n", service_type);
+ printf("\t > Service Name: %s\n", service_name);
+ printf("\t > Port: %d\n", port);
+ ret = vine_service_foreach_attribute(service, __print_attr, NULL);
+ PRINT_IF_ERROR(ret, "vine_service_foreach_attribute");
+ printf("\n");
+ fflush(stdout);
+
+ vine_service_h s;
+ vine_service_clone(service, &s);
+ g_service_list.push_back(s);
+ free(service_type);
+ free(service_name);
+}
+
+static void __print_received_data(unsigned char *buf, size_t len)
+{
+ for (int i = 0; i < (int)len; i++)
+ printf("%c", buf[i]);
+ printf("\n");
+}
+
+static void __received_cb(vine_dp_h dp, size_t received_len, void *user_data)
+{
+ unsigned char buf[20] = {0, };
+ size_t bytes = 0;
+
+ printf(COLOR_GRN "[RECV_CB] %p received %zd bytes." COLOR_RESET "\n", dp, received_len);
+ do {
+ vine_dp_recv(dp, buf, 20, &bytes);
+ __print_received_data(buf, bytes);
+ received_len -= bytes;
+ } while (received_len > 0);
+}
+
+static void __terminated_cb(vine_dp_h dp, void *user_data)
+{
+ printf(COLOR_GRN "[TERMINATED_CB] %p is terminated." COLOR_RESET "\n", dp);
+ g_datapath_list.remove(dp);
+ vine_dp_destroy(dp);
+}
+
+static void __add_new_dp(vine_dp_h dp)
+{
+ g_datapath_list.push_back(dp);
+ vine_dp_set_received_cb(dp, __received_cb, NULL);
+ vine_dp_set_terminated_cb(dp, __terminated_cb, NULL);
+}
+
+static void __opened_cb(vine_dp_h dp, vine_error_e result, void *user_data)
+{
+ int port;
+
+ vine_dp_get_port(dp, &port);
+ printf(COLOR_GRN "[OPENED_CB] %p is %s. port[%d]" COLOR_RESET "\n",
+ dp, (result == VINE_ERROR_NONE) ? "opened" : "not opened", port);
+ if (dp == g_client_dp || dp == g_pubsub_dp)
+ __add_new_dp(dp);
+}
+
+static void __set_callbacks()
+{
+ CHECK_SESSION;
+ PRINT_IF_ERROR(vine_session_set_registered_cb(g_session, __registered_cb, NULL),
+ "vine_session_set_registered_cb");
+ PRINT_IF_ERROR(vine_session_set_discovered_cb(g_session, __discovered_cb, NULL),
+ "vine_session_set_discovered_cb");
+}
+
+static void __create_session()
+{
+ int ret;
+ ret = vine_session_create(&g_session);
+ if (ret != VINE_ERROR_NONE) {
+ PRINT_IF_ERROR(ret, "vine_session_create");
+ return;
+ }
+
+ __set_callbacks();
+ printf("Session Created\n");
+}
+
+static void __destroy_session()
+{
+ CHECK_SESSION;
+ PRINT_IF_ERROR(vine_session_destroy(g_session),
+ "vine_session_destroy");
+}
+
+static void __set_service_type()
+{
+ CHECK_SESSION;
+ char type[64];
+ printf(" >> Service Type: ");
+ if (scanf(" %63s", type) < 1) {
+ _test_print_error("Scan failed");
+ return;
+ }
+ PRINT_RESULT(vine_service_set_type(g_service, type),
+ "vine_service_set_type");
+}
+
+static void __set_service_name()
+{
+ CHECK_SESSION;
+ char name[64];
+ printf(" >> Service Name (Max length 64): ");
+ if (scanf(" %63s", name) < 1) {
+ _test_print_error("Scan failed");
+ return;
+ }
+ PRINT_RESULT(vine_service_set_name(g_service, name),
+ "vine_service_set_name");
+}
+
+static void __set_port()
+{
+ CHECK_SESSION;
+ int port;
+ printf(" >> Port Number (0 ~ 65535): ");
+ if (scanf(" %d", &port) < 1) {
+ _test_print_error("Scan failed");
+ return;
+ }
+ PRINT_RESULT(vine_service_set_port(g_service, port), "vine_session_set_port");
+}
+
+static void __add_attribute()
+{
+ CHECK_SESSION;
+
+ while (true) {
+ char key[10];
+ char value[256] = {0, };
+ if (!test_get_user_string(" >> Key (Max length 9. Enter if no attribute): ", key, 10))
+ break;
+ test_get_user_string(" >> Value (Enter if empty): ", value, 256);
+ PRINT_RESULT(vine_service_add_attribute(g_service, key, value),
+ "vine_service_add_attribute");
+ }
+}
+
+static void __create_service()
+{
+ int ret;
+ ret = vine_service_create(&g_service);
+ if (ret != VINE_ERROR_NONE) {
+ PRINT_IF_ERROR(ret, "vine_service_create");
+ return;
+ }
+
+ __set_service_type();
+ __set_service_name();
+ __set_port();
+ __add_attribute();
+
+ printf("Service Created\n");
+}
+
+static void __destroy_service()
+{
+ CHECK_SESSION;
+ PRINT_IF_ERROR(vine_service_destroy(g_service), "vine_service_destroy");
+}
+
+static void __register()
+{
+ CHECK_SESSION;
+ PRINT_IF_ERROR(vine_session_register(g_session, g_service, NULL), "vine_session_register");
+ printf("Registered\n");
+}
+
+static void __unregister()
+{
+ CHECK_SESSION;
+ PRINT_IF_ERROR(vine_session_unregister(g_session), "vine_session_unregister");
+ printf("Unregistered\n");
+}
+
+static void __start_discovery()
+{
+ CHECK_SESSION;
+ char type[20];
+ printf(" >> Service Type: ");
+ if (scanf(" %19s", type) < 1) {
+ _test_print_error("Scan failed");
+ return;
+ }
+
+ PRINT_IF_ERROR(vine_session_start_discovery(g_session, type, NULL),
+ "vine_session_start_discovery");
+ printf("Discovery started\n");
+}
+
+static void __stop_discovery()
+{
+ CHECK_SESSION;
+ PRINT_IF_ERROR(vine_session_stop_discovery(g_session), "vine_session_stop_discovery");
+ printf("Discovery stopped\n");
+}
+
+static void __print_service_list()
+{
+ int idx = -1;
+ int ret = VINE_ERROR_NONE;
+ for (const auto &service : g_service_list) {
+ char *service_type;
+ char *service_name;
+ int port;
+
+ ret = vine_service_get_type(service, &service_type);
+ PRINT_IF_ERROR(ret, "vine_service_get_type");
+ ret = vine_service_get_name(service, &service_name);
+ PRINT_IF_ERROR(ret, "vine_service_get_name");
+ ret = vine_service_get_port(service, &port);
+ PRINT_IF_ERROR(ret, "vine_service_get_port");
+ printf("\t %d: type[%s] name[%s] port[%d]\n", ++idx, service_type, service_name, port);
+ free(service_type);
+ free(service_name);
+ }
+}
+
+static vine_service_h __get_service()
+{
+ __print_service_list();
+
+ int idx;
+ printf(" >> Select service: \n");
+ if (scanf("%d", &idx) < 0)
+ return NULL;
+
+ auto it = g_service_list.begin();
+ std::advance(it, idx);
+
+ return (vine_service_h) *it;
+}
+
+static void __resolve_ip()
+{
+ CHECK_SESSION;
+ int ret = vine_session_set_ip_resolved_cb(g_session, __get_service(),
+ VINE_ADDRESS_FAMILY_DEFAULT,__ip_resolved_cb, NULL);
+ PRINT_IF_ERROR(ret, "vine_session_set_ip_resolved_cb");
+}
+
+static void __stop_resolve_ip()
+{
+ CHECK_SESSION;
+ int ret = vine_session_unset_ip_resolved_cb(g_session, __get_service());
+ PRINT_IF_ERROR(ret, "vine_session_unset_ip_resolved_cb");
+}
+
+#ifdef TEST_DEBUG
+#define VINE_LOGGER_TIME_MESSAGE_LEN 17
+static void __get_current_time(char *buf)
+{
+ int hour, min, sec, day, month;
+ time_t now;
+ struct tm *local;
+
+ time(&now);
+ local = localtime(&now);
+
+ hour = local->tm_hour;
+ min = local->tm_min;
+ sec = local->tm_sec;
+ day = local->tm_mday;
+ month = local->tm_mon + 1;
+
+ snprintf(buf, VINE_LOGGER_TIME_MESSAGE_LEN,
+ "[%02u-%02u %02u:%02u:%02u]", month, day, hour, min, sec);
+}
+
+void __logger(int log_level, const char *log)
+{
+ char timestamp[VINE_LOGGER_TIME_MESSAGE_LEN];
+ __get_current_time(timestamp);
+ printf("%s[T%5u] ", timestamp, (unsigned int)syscall(__NR_gettid));
+
+ switch (log_level) {
+ case VINE_LOG_DEBUG:
+ printf("D/");
+ break;
+ case VINE_LOG_INFO:
+ printf("I/");
+ break;
+ case VINE_LOG_ERROR:
+ printf(COLOR_RED "E/");
+ break;
+ }
+ printf("%s" COLOR_RESET "\n", log);
+}
+#endif
+
+static void __debug_on_off()
+{
+ static int __debug_on = 0;
+ __debug_on = 1 - __debug_on;
+ printf("Debug %s\n", __debug_on ? "ON" : "OFF");
+#ifdef TEST_DEBUG
+ if (__debug_on) {
+ vine_set_logger(__logger);
+ vine_set_log_level(VINE_LOG_DEBUG | VINE_LOG_INFO | VINE_LOG_ERROR);
+ } else {
+ vine_set_logger(NULL);
+ }
+#endif
+}
+
+static vine_security_h __create_security_handle(int type, bool is_server)
+{
+ vine_security_h s = NULL;
+
+ if (type == VINE_SECURITY_TYPE_NONE)
+ return NULL;
+ if (vine_security_create(&s) != VINE_ERROR_NONE)
+ return NULL;
+
+ if (vine_security_set_type(s, (vine_security_type_e)type) != VINE_ERROR_NONE) {
+ vine_security_destroy(s);
+ return NULL;
+ }
+
+ if (type >= VINE_SECURITY_TYPE_TLS) {
+ vine_security_set_ca_path(s, ROOT_CA_PATH);
+ vine_security_set_cert_path(s, SERVER_CERT_PATH);
+ vine_security_set_verification_flags(s, VINE_SECURITY_VERIFICATION_FLAG_ALLOW_SELF_SIGNED | VINE_SECURITY_VERIFICATION_FLAG_SKIP_HOST_NAME_CHECK);
+ vine_security_set_tls_version(s, VINE_SECURITY_TLS_VERSION_1_3);
+ if (is_server)
+ vine_security_set_private_key(s, SERVER_PRIVATE_KEY_PATH);
+ }
+
+ if (type == VINE_SECURITY_TYPE_PSK_OVER_TLS) {
+ char psk[256] = {0, };
+ while (!test_get_user_string(" >> PSK (Max length 256): ", psk, 256)) {
+ }
+ vine_security_set_psk(s, psk);
+ }
+
+ return s;
+}
+
+static void __accepted_cb(vine_dp_h dp, vine_dp_h accepted_dp, void *user_data)
+{
+ printf(COLOR_GRN "[ACCEPTED_CB] %p is accepted." COLOR_RESET "\n", accepted_dp);
+ vine_address_family_e addr_family;
+ char *ip;
+ int ret = vine_dp_get_remote_ip(accepted_dp, &addr_family, &ip);
+ PRINT_IF_ERROR(ret, "vine_dp_get_remote_ip");
+ printf(COLOR_GRN " Client IP[%s] Family[%d]" COLOR_RESET "\n", ip, (int)addr_family);
+ free(ip);
+ __add_new_dp(accepted_dp);
+}
+
+static void __open_server()
+{
+ CHECK_SESSION;
+ int addr_family = 0;
+ int port = 0;
+ int security_type = 0;
+
+ printf(" >> Address type(0-default, 1-IPv4, 2-IPv6): ");
+ if (scanf(" %d", &addr_family) < 1) {
+ _test_print_error("Scan failed");
+ return;
+ }
+
+ printf(" >> listen port: ");
+ if (scanf(" %d", &port) < 1) {
+ _test_print_error("Scan failed");
+ return;
+ }
+
+ printf("Set security type(0.NONE, 1.TLS, 2.PSK): ");
+ if (scanf("%d", &security_type) < 0) {
+ _test_print_error("Scan failed");
+ return;
+ }
+
+ vine_dp_create(g_session, VINE_DP_TYPE_SERVER, &g_server_dp);
+ vine_dp_set_accepted_cb(g_server_dp, __accepted_cb, NULL);
+ vine_dp_set_terminated_cb(g_server_dp, __terminated_cb, NULL);
+ vine_dp_set_address_family(g_server_dp, (vine_address_family_e)addr_family);
+ vine_dp_set_port(g_server_dp, port);
+ vine_security_h security = __create_security_handle(security_type, true);
+ vine_dp_set_security(g_server_dp, security);
+ vine_security_destroy(security);
+
+ PRINT_RESULT(vine_dp_open(g_server_dp, __opened_cb, NULL), "vine_dp_open");
+}
+
+static void __connect_server()
+{
+ CHECK_SESSION;
+ int addr_type;
+ char ip[40] = {0, };
+ int port = 0;
+ int security_type = 0;
+
+ printf(" >> Address Family(0-IPv4, 1-IPv6): ");
+ if (scanf(" %d", &addr_type) < 1) {
+ _test_print_error("Scan failed");
+ return;
+ }
+ printf(" >> Peer IP: ");
+ if (scanf(" %39s", ip) < 1) {
+ _test_print_error("Scan failed");
+ return;
+ }
+
+ printf(" >> Peer port: ");
+ if (scanf(" %d", &port) < 1) {
+ _test_print_error("Scan failed");
+ return;
+ }
+
+ printf("Set security type(0.NONE, 1.TLS, 2.PSK): ");
+ if (scanf("%d", &security_type) < 0) {
+ _test_print_error("Scan failed");
+ return;
+ }
+
+ vine_dp_create(g_session, VINE_DP_TYPE_CLIENT, &g_client_dp);
+ vine_dp_set_remote_ip(g_client_dp,
+ addr_type ? VINE_ADDRESS_FAMILY_IPV6 : VINE_ADDRESS_FAMILY_IPV4, ip);
+ PRINT_RESULT(vine_dp_set_remote_port(g_client_dp, port), "vine_dp_set_remote_port");
+ vine_security_h security = __create_security_handle(security_type, true);
+ vine_dp_set_security(g_client_dp, security);
+ vine_security_destroy(security);
+ PRINT_RESULT(vine_dp_open(g_client_dp, __opened_cb, NULL), "vine_dp_open");
+}
+
+static void __join_service()
+{
+ CHECK_SESSION;
+ int port = 0;
+ int addr_family = 0;
+ char topic[64];
+
+ printf(" >> Address type(0-default, 1-IPv4, 2-IPv6): ");
+ if (scanf(" %d", &addr_family) < 1) {
+ _test_print_error("Scan failed");
+ return;
+ }
+
+ printf(" >> Listen port: ");
+ if (scanf(" %d", &port) < 1) {
+ _test_print_error("Scan failed");
+ return;
+ }
+
+ printf(" >> Set topic: ");
+ if (scanf(" %63s", topic) < 1) {
+ _test_print_error("Scan failed");
+ return;
+ }
+
+ vine_dp_create(g_session, VINE_DP_TYPE_PUBSUB, &g_pubsub_dp);
+ vine_dp_set_address_family(g_pubsub_dp, (vine_address_family_e)addr_family);
+ vine_dp_set_port(g_pubsub_dp, port);
+ vine_dp_set_topic(g_pubsub_dp, topic);
+ // TODO: set security.
+
+ vine_dp_set_terminated_cb(g_pubsub_dp, __terminated_cb, NULL);
+ PRINT_RESULT(vine_dp_open(g_pubsub_dp, __opened_cb, NULL), "vine_dp_open");
+}
+
+void __print_datapath_list()
+{
+ int idx = -1;
+ for (const auto &dp : g_datapath_list)
+ printf("\t %d: datapath[%p]\n", ++idx, dp);
+}
+
+static void __send_data()
+{
+ CHECK_SESSION;
+
+ const char *test_str[3] = {
+ "12345678910",
+ "Hello! This is a test string.",
+ "Tizen is an open and flexible operating system" \
+ "built from the ground up to address the needs of all stakeholders of the mobile"\
+ "and connected device ecosystem, including device manufacturers, mobile operators,"\
+ "application developers and independent software vendors (ISVs)."\
+ "Tizen is developed by a community of developers, under open source governance,"\
+ "and is open to all members who wish to participate."
+ };
+
+ __print_datapath_list();
+
+ int idx;
+ printf(" >> Select peer: \n");
+ if (scanf("%d", &idx) < 0)
+ return;
+
+ auto it = g_datapath_list.begin();
+ std::advance(it, idx);
+ vine_dp_h dp = *it;
+
+ for (int i = 0; i < 3; i++) {
+ int ret = vine_dp_send(dp,
+ (unsigned char *)test_str[i], strlen(test_str[i]));
+ PRINT_IF_ERROR(ret, "vine_data_path_write");
+ }
+}
+
+static void __close_data_path()
+{
+ __print_datapath_list();
+
+ int idx;
+ printf(" >> Select peer: \n");
+ if (scanf("%d", &idx) < 0)
+ return;
+
+ auto it = g_datapath_list.begin();
+ std::advance(it, idx);
+ vine_dp_h dp = *it;
+
+ PRINT_RESULT(vine_dp_close(dp), "vine_dp_close");
+ g_datapath_list.remove(dp);
+ PRINT_RESULT(vine_dp_destroy(dp), "vine_dp_destroy");
+}
+
+enum {
+ CMD_QUIT = 0,
+ CMD_CREATE_SESSION,
+ CMD_DESTROY_SESSION,
+ CMD_CREATE_SERVICE,
+ CMD_DESTROY_SERVICE,
+ CMD_REGISTER,
+ CMD_UNREGISTER,
+ CMD_START_DISCOVERY,
+ CMD_STOP_DISCOVERY,
+ CMD_RESOLVE_IP,
+ CMD_STOP_RESOLVING_IP,
+ CMD_OPEN_SERVER,
+ CMD_CONNECT_SERVER,
+ CMD_JOIN_SERVICE,
+ CMD_SEND_DATA,
+ CMD_CLOSE_DATA_PATH,
+ CMD_DEBUG,
+ CMD_INVALID,
+};
+
+static struct {
+ const char *str;
+ void (*func)(void);
+} __menus[] = {
+ [CMD_QUIT] = {"quit", __quit},
+ [CMD_CREATE_SESSION] = {"Create session", __create_session},
+ [CMD_DESTROY_SESSION] = {"Destroy session", __destroy_session},
+ [CMD_CREATE_SERVICE] = {"Create service", __create_service},
+ [CMD_DESTROY_SERVICE] = {"Destroy service", __destroy_service},
+ [CMD_REGISTER] = {"Register a service", __register},
+ [CMD_UNREGISTER] = {"Unregister a service", __unregister},
+ [CMD_START_DISCOVERY] = {"Start discovery", __start_discovery},
+ [CMD_STOP_DISCOVERY] = {"Stop discovery", __stop_discovery},
+ [CMD_RESOLVE_IP] = {"Resolve IP", __resolve_ip},
+ [CMD_STOP_RESOLVING_IP] = {"Stop resolveing IP", __stop_resolve_ip},
+ [CMD_OPEN_SERVER] = {"Open server", __open_server},
+ [CMD_CONNECT_SERVER] = {"Connect to server", __connect_server},
+ [CMD_JOIN_SERVICE] = {"Join a service", __join_service},
+ [CMD_SEND_DATA] = {"Send data to peer", __send_data},
+ [CMD_CLOSE_DATA_PATH] = {"Close datapath", __close_data_path},
+ [CMD_DEBUG] = {"Debug on/off", __debug_on_off},
+ {NULL, NULL},
+};
+
+static void __show_menus()
+{
+ printf("\n-- Vine Test\n");
+ for (int i = 0; __menus[i].str; ++i)
+ printf("%02d %s\n", i, __menus[i].str);
+ printf("> ");
+ fflush(stdout);
+}
+
+static inline int __is_digit(const char* str)
+{
+ int len;
+ int i;
+
+ if (str == NULL)
+ return -1;
+
+ if (strlen(str) == 0)
+ return -1;
+
+ len = strlen(str);
+ for (i = 0; i < len; i++) {
+ if (str[i] < '0' || str[i] > '9')
+ return -2;
+ }
+
+ return 0;
+}
+
+static void __process_input(const char *input)
+{
+ int cmd = -1;
+
+ cmd = strtol(input, NULL, 0);
+ if (__is_digit(input) < 0 || strlen(input) == 0 || errno == ERANGE || errno
+ == EINVAL)
+ cmd = CMD_INVALID;
+
+ if (cmd >= CMD_INVALID || cmd < CMD_QUIT) {
+ printf("Invalid CMD\n");
+ return;
+ }
+ __menus[cmd].func();
+}
+
+static void __terminal_read_std_input()
+{
+ int fd = 0;
+
+ static char buf[1024];
+ int n;
+
+ errno = 0;
+ n = read(fd, buf, 1024);
+ if (n == 0) {
+ printf("Error: read() from stdin returns 0.\n");
+ } else if (n < 0) {
+ printf("input: read, err\n");
+ } else if (n - 1 > 0 && n < 1024) {
+ buf[n - 1] = '\0'; /* remove new line... */
+ printf("\n\n");
+ __process_input(buf);
+ } else {
+ if (buf[0] == '\n' || buf[0] == '\r')
+ __show_menus();
+ else
+ printf("invalid input\n");
+ }
+}
+
+static gboolean __io_handler(GIOChannel *source, GIOCondition condition, gpointer data)
+{
+ __terminal_read_std_input();
+ return TRUE;
+}
+
+int main()
+{
+ __init();
+ __show_menus();
+
+ main_loop = g_main_loop_new(NULL, FALSE);
+
+ GIOChannel *channel = g_io_channel_unix_new(0);
+ g_io_add_watch(channel, (GIOCondition)(G_IO_IN|G_IO_ERR|G_IO_HUP|G_IO_NVAL),
+ __io_handler, NULL);
+ g_main_loop_run(main_loop);
+ g_main_loop_unref(main_loop);
+
+ return 0;
+}