--- /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.
+ */
+
+/*
+ * Test: vine-pubsub-open-close-test
+ * Description:
+ * a PubSub DP opens and closes repeatedly in one session.
+ * The interval is 100ms. (DP_LIFETIME)
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <sys/epoll.h>
+#include <sys/timerfd.h>
+#include <unistd.h>
+#include <vine.h>
+#include <vine-log.h>
+
+#include "vine-test-utils.h"
+
+#define MAX_EVENTS 50
+#define DEFAULT_REPETITION_TIME 100
+#define DP_LIFETIME 100000000 // nanoseconds
+#define TOPIC "pubsub-test"
+
+static int epollfd = 0;
+static vine_session_h session = NULL;
+static int count = DEFAULT_REPETITION_TIME;
+
+enum {
+ EPOLL_EVENT_TYPE_SESSION = 0,
+ EPOLL_EVENT_TYPE_TIMEOUT
+};
+
+typedef struct {
+ int type;
+ int timerfd;
+ void *ptr;
+} epoll_data_s;
+
+static void open_dp(vine_session_h session);
+
+void _logger(int log_level, const char *log)
+{
+ 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);
+}
+
+static void add_event_fd(int fd, void *user_data)
+{
+ struct epoll_event ev;
+ ev.events = EPOLLIN;
+ ev.data.fd = fd;
+ ev.data.ptr = user_data;
+ if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
+ print_error("Fail to add an epoll event for fd %d: %d", fd, errno);
+ exit(1);
+ }
+}
+
+static void del_event_fd(int fd)
+{
+ epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, NULL);
+}
+
+static void _start_timer(vine_dp_h dp, int nsec)
+{
+ if (nsec <= 0)
+ return;
+
+ int timerfd = timerfd_create(CLOCK_MONOTONIC, 0);
+ if (timerfd == -1)
+ return;
+
+ struct itimerspec value;
+ value.it_interval.tv_sec = 0;
+ value.it_interval.tv_nsec = 0;
+ value.it_value.tv_sec = 0;
+ value.it_value.tv_nsec = nsec;
+ if (timerfd_settime(timerfd, 0, &value, NULL) != 0) {
+ close(timerfd);
+ return;
+ }
+
+ epoll_data_s *data = (epoll_data_s *)calloc(1, sizeof(epoll_data_s));
+ data->type = EPOLL_EVENT_TYPE_TIMEOUT;
+ data->timerfd = timerfd;
+ data->ptr = (void *)dp;
+
+ add_event_fd(timerfd, (void *)data);
+}
+
+static void _stop_timer(int fd)
+{
+ del_event_fd(fd);
+ close(fd);
+ --count;
+}
+
+static void _handle_timer_event(epoll_data_s *data)
+{
+ int fd = data->timerfd;
+ vine_dp_h dp = (vine_dp_h)data->ptr;
+
+ PRINT_LOG("Close dp[%p]", dp);
+ _stop_timer(fd);
+ vine_dp_close(dp);
+ vine_dp_destroy(dp);
+
+ open_dp(session);
+}
+
+static void _event_handler(void *user_data)
+{
+ epoll_data_s *data = (epoll_data_s *)user_data;
+
+ if (!data || !data->ptr)
+ return;
+
+ if (data->type == EPOLL_EVENT_TYPE_SESSION) {
+ PRINT_IF_ERROR(vine_session_process_event(data->ptr), "vine_process_event");
+ } else if (data->type == EPOLL_EVENT_TYPE_TIMEOUT) {
+ _handle_timer_event(data);
+ free(data);
+ }
+}
+
+static void run_event_loop(vine_session_h session)
+{
+ struct epoll_event events[MAX_EVENTS];
+
+ epollfd = epoll_create1(0);
+ if (epollfd == -1) {
+ print_error("Fail to create epoll fd %d", errno);
+ return;
+ }
+
+ int fd = 0;
+ PRINT_IF_ERROR(vine_session_get_event_fd(session, &fd), "vine_session_get_event_fd");
+ if (fd <= 0)
+ return;
+
+ epoll_data_s *data = (epoll_data_s *)calloc(1, sizeof(epoll_data_s));
+ data->type = EPOLL_EVENT_TYPE_SESSION;
+ data->ptr = session;
+ add_event_fd(fd, (void *)data);
+
+ while (count) {
+ int n = epoll_wait(epollfd, events, MAX_EVENTS, 0);
+ if (n == -1) {
+ print_error("epoll_wait %d", errno);
+ break;
+ }
+
+ for (int i = 0; i < n; ++i) {
+ if (events[i].data.ptr)
+ _event_handler(events[i].data.ptr);
+ }
+ }
+ free(data);
+ close(epollfd);
+}
+
+static void open_dp(vine_session_h session)
+{
+ vine_dp_h dp = NULL;
+
+ PRINT_IF_ERROR(vine_dp_create(session, VINE_DP_TYPE_PUBSUB, &dp), "vine_dp_create");
+ PRINT_IF_ERROR(vine_dp_set_topic(dp, TOPIC), "vine_dp_set_topic");
+ PRINT_IF_ERROR(vine_dp_set_terminated_cb(dp,
+ [](vine_dp_h dp, void *user_data) {
+ PRINT_LOG("dp[%p] is closed.");
+ }, NULL), "vine_dp_set_terminated_cb");
+ PRINT_IF_ERROR(vine_dp_set_peer_joined_cb(dp,
+ [](vine_dp_h dp, const char *ip, int port, void *user_data) {
+ PRINT_LOG("dp[%p]'s peer[%s:%d] is joined.", dp, ip, port);
+ }, NULL), "vine_dp_set_peer_joined_cb");
+ PRINT_IF_ERROR(vine_dp_set_peer_left_cb(dp,
+ [](vine_dp_h dp, const char *ip, int port, void *user_data) {
+ PRINT_LOG("dp[%p]'s peer[%s:%d] is left.", dp, ip, port);
+ }, NULL), "vine_dp_set_peer_left_cb");
+ PRINT_IF_ERROR(vine_dp_open(dp,
+ [](vine_dp_h dp, vine_error_e result, void *user_data) {
+ if (result != VINE_ERROR_NONE)
+ return;
+ PRINT_LOG("dp[%p] is opened.", dp);
+ _start_timer(dp, DP_LIFETIME);
+ }, NULL), "vine_dp_open");
+}
+
+static void _parse_options(int argc, char **argv)
+{
+ int opt = 0;
+
+ while ((opt = getopt(argc, argv, "dhn:")) != -1) {
+ switch(opt) {
+ case 'd':
+ vine_set_logger(_logger);
+ vine_set_log_level(VINE_LOG_DEBUG | VINE_LOG_INFO | VINE_LOG_ERROR);
+ break;
+ case 'n':
+ count = atoi(optarg);
+ break;
+ case 'h':
+ default:
+ printf(COLOR_CYN "[HELP] -n: number of times, -d: debug, -h: help\n" COLOR_RESET);
+ exit(1);
+ }
+ }
+}
+
+int main(int argc, char **argv)
+{
+ _parse_options(argc, argv);
+
+ PRINT_IF_ERROR(vine_initialize(), "vine_initialize()");
+ PRINT_IF_ERROR(vine_session_create(&session), "vine_session_create");
+
+ open_dp(session);
+ run_event_loop(session);
+
+ PRINT_IF_ERROR(vine_session_destroy(session), "vine_session_destroy");
+ PRINT_IF_ERROR(vine_deinitialize(), "vine_deinitialize()");
+
+ return 0;
+}