test/blackbox/test_case_meta_conn_03/Makefile
test/blackbox/test_case_meta_conn_04/Makefile
test/blackbox/test_case_meta_conn_05/Makefile
+ test/blackbox/test_cases_submesh01/Makefile
+ test/blackbox/test_cases_submesh02/Makefile
+ test/blackbox/test_cases_submesh03/Makefile
+ test/blackbox/test_cases_submesh04/Makefile
examples/Makefile
])
test_case_meta_conn_02 \
test_case_meta_conn_03 \
test_case_meta_conn_04 \
- test_case_meta_conn_05
+ test_case_meta_conn_05 \
+ test_cases_submesh01 \
+ test_cases_submesh02 \
+ test_cases_submesh03 \
+ test_cases_submesh04
+
gen_invite_SOURCES = util/gen_invite.c common/common_handlers.c common/test_step.c common/mesh_event_handler.c
gen_invite_LDADD = ../../src/libmeshlink.la
}
char *run_in_container(const char *cmd, const char *container_name, bool daemonize) {
- char container_find_name[100];
+ char container_find_name[1000];
struct lxc_container *container;
assert(cmd);
return invite_url;
}
+/* Run the gen_invite command inside the 'inviter' container to generate an invite
+ for 'invitee' belonging to pparticular submesh, and return the generated invite
+ which is output on the terminal */
+char *submesh_invite_in_container(const char *inviter, const char *invitee, const char *submesh) {
+ char invite_command[200];
+ char *invite_url;
+
+ assert(snprintf(invite_command, sizeof(invite_command),
+ "LD_LIBRARY_PATH=/home/ubuntu/test/.libs /home/ubuntu/test/gen_invite %s %s %s "
+ "2> gen_invite.log", inviter, invitee, submesh) >= 0);
+ assert(invite_url = run_in_container(invite_command, inviter, false));
+ PRINT_TEST_CASE_MSG("Invite Generated from '%s' to '%s': %s\n", inviter,
+ invitee, invite_url);
+
+ return invite_url;
+}
+
/* Run the node_sim_<nodename> program inside the 'node''s container */
void node_sim_in_container(const char *node, const char *device_class, const char *invite_url) {
char *node_sim_command;
/* Run the node_step.sh script inside the 'node''s container to send the 'sig' signal to the
node_sim program in the container */
void node_step_in_container(const char *node, const char *sig) {
- char node_step_command[200];
+ char node_step_command[1000];
assert(snprintf(node_step_command, sizeof(node_step_command),
"/home/ubuntu/test/node_step.sh lt-node_sim_%s %s 1>&2 2> node_step.log",
#define SERVER_LISTEN_PORT "9000" /* Port number that is binded with mesh event server socket */
#define UDP_BUFF_MAX 2000
+const char *event_status[] = {
+ [NODE_STARTED] = "Node Started",
+ [NODE_JOINED] = "Node Joined",
+ [ERR_NETWORK] = "Network Error",
+ [CHANNEL_OPENED] = "Channel Opened",
+ [CHANNEL_DATA_RECIEVED] = "Channel Data Received",
+ [SIG_ABORT] = "SIG_ABORT Received",
+ [MESH_EVENT_COMPLETED] = "MESH_EVENT_COMPLETED Received"
+};
+
// TODO: Implement mesh event handling with reentrancy .
static struct sockaddr_in server_addr;
static int client_fd = -1;
mesh_events_flush();
event_receive_thread_running = false;
pthread_cancel(event_receive_thread);
-}
-
+}
\ No newline at end of file
INCOMING_META_CONN,
OUTGOING_META_CONN,
AUTO_DISCONN,
-
+ MESH_EVENT_COMPLETED,
MAX_EVENT // Maximum event enum
} mesh_event_t;
+extern const char *event_status[];
+
/// mesh event UDP packet
typedef struct mesh_event_payload {
void *payload;
return mesh_handle;
}
-char *execute_invite(char *invitee) {
- char *invite_url = meshlink_invite_ex(mesh_handle, NULL, invitee, MESHLINK_INVITE_LOCAL | MESHLINK_INVITE_NUMERIC);
+char *execute_invite(char *invitee, meshlink_submesh_t *submesh) {
+ char *invite_url = meshlink_invite_ex(mesh_handle, submesh, invitee, MESHLINK_INVITE_LOCAL | MESHLINK_INVITE_NUMERIC);
PRINT_TEST_CASE_MSG("meshlink_invite status: %s\n", meshlink_strerror(meshlink_errno));
assert(invite_url);
#include "../../../src/meshlink.h"
meshlink_handle_t *execute_open(char *node_name, char *dev_class);
-char *execute_invite(char *invitee);
+char *execute_invite(char *invitee, meshlink_submesh_t *submesh);
void execute_join(char *invite_url);
void execute_start(void);
void execute_stop(void);
../test_case_channel_blacklist_01/node_sim_nut_01.c \
../test_case_channel_blacklist_01/node_sim_peer_01.c \
../test_case_channel_blacklist_01/node_sim_relay_01.c \
- test_cases_channel_blacklist.c
+ test_cases_channel_blacklist.c \
+ test_cases_submesh01.c \
+ test_cases_submesh02.c \
+ test_cases_submesh03.c \
+ test_cases_submesh04.c
run_blackbox_tests_LDADD = ../../../src/libmeshlink.la $(LXC_LIBS) $(CMOCKA_LIBS)
run_blackbox_tests_CFLAGS = -D_GNU_SOURCE $(LXC_CFLAGS) $(CMOCKA_CFLAGS)
return EXIT_SUCCESS;
}
+
+bool change_state(node_status_t *status, mesh_event_t currentEv) {
+
+ if(status->current_index == status->max_events) {
+ return false;
+ }
+
+ if(currentEv == status->expected_events[status->current_index]) {
+ status->current_index = status->current_index + 1;
+
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void signal_node_start(node_status_t *node_status, int start, int end, char *node_ids[]) {
+ int i, index;
+
+ for(i = start; i <= end; i++) {
+ index = node_status[i].current_index;
+
+ if(index < 1 || NODE_JOINED != node_status[i].expected_events[index - 1]) {
+ return;
+ }
+ }
+
+
+ for(i = start; i <= end; i++) {
+ fprintf(stderr, "\tSending signals to '%s'\n", node_ids[i]);
+ node_step_in_container(node_ids[i], "SIGIO");
+ }
+
+ return;
+}
+
+bool check_nodes_finished(node_status_t *node_status, int length) {
+ for(int i = 0; i < length; i++) {
+ if(node_status[i].current_index != node_status[i].max_events) {
+ return false;
+ }
+ }
+
+ return true;
+}
*/
#include <stdbool.h>
+#include "../common/mesh_event_handler.h"
+
+typedef struct {
+ const mesh_event_t *expected_events;
+ int current_index;
+ int max_events;
+} node_status_t;
typedef bool (*test_step_func_t)(void);
void execute_test(test_step_func_t step_func, void **state);
int teardown_test(void **state);
+/// Changes the state of the node state machine.
+/** This function changes the current state of the node
+ *
+ * @param status Pointer to status handle of that node.
+ * @param currentEv Current event triggered by the node.
+ *
+ * @return This function returns true if state change is successful else returns false
+ */
+extern bool change_state(node_status_t *status, mesh_event_t currentEv);
+
+/// Sends SIGIO signal to all the nodes in the container.
+/** This function Triggers SIGIO signal to all the target applications running inside the container
+ *
+ * @param status Pointer to array of status handles of target nodes.
+ * @param start Starting index from which to start in the array.
+ * @param end Ending index of the array
+ * @param node_ids Pointer to array of node id strings
+ *
+ * @return Void
+ */
+extern void signal_node_start(node_status_t *node_status, int start, int end, char *node_ids[]);
+
+/// Checks for the completion of nodes state machines.
+/** This function checks wheather the nodes state machines have reached their maximum state indexes
+ *
+ * @param status Pointer to array of status handles of target nodes.
+ * @param length Number of nodes to check.
+ *
+ * @return This function returns true if all the nodes reached their max states
+ */
+extern bool check_nodes_finished(node_status_t *node_status, int length);
+
#endif // TEST_STEP_H
#include "test_cases_channel_conn.h"
#include "test_cases_get_all_nodes_by_dev_class.h"
+#include "test_cases_submesh01.h"
+#include "test_cases_submesh02.h"
+#include "test_cases_submesh03.h"
+#include "test_cases_submesh04.h"
#include "../common/containers.h"
#include "../common/common_handlers.h"
int failed_tests = 0;
- /*failed_tests += test_meta_conn();
+ /*
+ failed_tests += test_meta_conn();
failed_tests += test_meshlink_set_status_cb();
failed_tests += test_meshlink_join();
failed_tests += test_meshlink_set_channel_poll_cb();
failed_tests += test_meshlink_channel_open();
failed_tests += test_meshlink_channel_close();
- failed_tests += test_meshlink_channel_conn();*/
+ failed_tests += test_meshlink_channel_conn();
failed_tests += test_optimal_pmtu();
+ */
+ failed_tests += test_cases_submesh01();
+ failed_tests += test_cases_submesh02();
+ failed_tests += test_cases_submesh03();
+ failed_tests += test_cases_submesh04();
failed_tests += test_optimal_pmtu();
--- /dev/null
+/*
+ test_cases_submesh.c -- Execution of specific meshlink black box test cases
+ Copyright (C) 2018 Guus Sliepen <guus@meshlink.io>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#include <stdlib.h>
+#include <stdarg.h>
+#include <setjmp.h>
+#include <cmocka.h>
+#include <assert.h>
+#include "execute_tests.h"
+#include "test_cases_submesh01.h"
+#include "pthread.h"
+#include "../common/containers.h"
+#include "../common/test_step.h"
+#include "../common/common_handlers.h"
+#include "../common/mesh_event_handler.h"
+
+#define CORENODE1_ID "0"
+#define APP1NODE1_ID "1"
+#define APP2NODE1_ID "2"
+#define CORENODE2_ID "3"
+#define APP1NODE2_ID "4"
+#define APP2NODE2_ID "5"
+
+#define INIT_ST 0
+
+static bool test_case_status = false;
+
+static void test_case_submesh_01(void **state);
+static bool test_steps_submesh_01(void);
+
+static char event_node_name[][10] = {"CORENODE1", "APP1NODE1", "APP2NODE1", "CORENODE2",
+ "APP1NODE2", "APP2NODE2"
+ };
+static const char *node_ids[] = { "corenode1", "app1node1", "app2node1", "corenode2",
+ "app1node2", "app2node2"
+ };
+
+static mesh_event_t core_node1[] = { NODE_STARTED, CHANNEL_OPENED, CHANNEL_DATA_RECIEVED};
+
+static mesh_event_t core_node2[] = { NODE_STARTED, NODE_JOINED, CHANNEL_OPENED, CHANNEL_DATA_RECIEVED};
+
+static mesh_event_t app1_node1[] = { NODE_STARTED, NODE_JOINED, CHANNEL_OPENED, CHANNEL_DATA_RECIEVED};
+
+static mesh_event_t app2_node1[] = { NODE_STARTED, NODE_JOINED, CHANNEL_OPENED, CHANNEL_DATA_RECIEVED};
+
+static mesh_event_t app1_node2[] = { NODE_STARTED, NODE_JOINED, CHANNEL_OPENED, CHANNEL_DATA_RECIEVED, CHANNEL_OPENED, CHANNEL_DATA_RECIEVED, MESH_EVENT_COMPLETED};
+
+static mesh_event_t app2_node2[] = { NODE_STARTED, NODE_JOINED, CHANNEL_OPENED, CHANNEL_DATA_RECIEVED, CHANNEL_OPENED, CHANNEL_DATA_RECIEVED, MESH_EVENT_COMPLETED};
+
+/* State structure for SubMesh Test Case #1 */
+static char *test_case_submesh_1_nodes[] = { "corenode1", "app1node1", "app2node1", "corenode2", "app1node2", "app2node2" };
+static black_box_state_t test_case_submesh_1_state = {
+ .test_case_name = "test_cases_submesh01",
+ .node_names = test_case_submesh_1_nodes,
+ .num_nodes = 6
+};
+
+static int black_box_group0_setup(void **state) {
+ const char *nodes[] = { "corenode1", "app1node1", "app2node1", "corenode2", "app1node2", "app2node2" };
+ int num_nodes = sizeof(nodes) / sizeof(nodes[0]);
+
+ PRINT_TEST_CASE_MSG("Creating Containers\n");
+ destroy_containers();
+ create_containers(nodes, num_nodes);
+
+ return 0;
+}
+
+static int black_box_group0_teardown(void **state) {
+ PRINT_TEST_CASE_MSG("Destroying Containers\n");
+ destroy_containers();
+
+ return 0;
+}
+
+static int black_box_all_nodes_setup(void **state) {
+ const char *nodes[] = { "corenode1" };
+ int num_nodes = sizeof(nodes) / sizeof(nodes[0]);
+
+ PRINT_TEST_CASE_MSG("Creating Containers\n");
+ destroy_containers();
+ create_containers(nodes, num_nodes);
+ PRINT_TEST_CASE_MSG("Created Containers\n");
+ return 0;
+}
+
+static bool event_cb(mesh_event_payload_t payload) {
+ static node_status_t node_status[6] = {
+ {core_node1, 0, 3, false},
+ {app1_node1, 0, 4, false},
+ {app2_node1, 0, 4, false},
+ {core_node2, 0, 4, false},
+ {app1_node2, 0, 7, false},
+ {app2_node2, 0, 7, false}
+ };
+
+ fprintf(stderr, "%s(%lu) : %s\n", event_node_name[payload.client_id], time(NULL), event_status[payload.mesh_event]);
+ assert(change_state(&node_status[payload.client_id], payload.mesh_event));
+
+ if(payload.mesh_event == NODE_JOINED) {
+ signal_node_start(node_status, 1, 5, node_ids);
+ }
+
+ if(check_nodes_finished(node_status, 6)) {
+ test_case_status = true;
+ return true;
+ }
+
+ return false;
+}
+
+/* Execute SubMesh Test Case # 1 */
+static void test_case_submesh_01(void **state) {
+ execute_test(test_steps_submesh_01, state);
+}
+
+/* Test Steps for SubMesh Test Case # 1
+
+ Test Steps:
+ 1. Run corenode1, app1node1, app2node1, corenode2, app1node2 and app2node2
+ 2. Generate invites to app1node1, app2node1, corenode2, app1node2 and app2node2
+ from corenode1 to join corenode1.
+ 3. After Join is successful start channels from all nodes and exchange data on channels
+ 4. Try to fetch the node handle of one sub-mesh node from node in another sub-mesh
+
+ Expected Result:
+ Channels should be formed between nodes of sub-mesh & coremesh, nodes with in sub-mesh
+ and should be able to exchange data. But node in one sub-mesh should not get the details
+ of node in another sub-mesh.
+*/
+static bool test_steps_submesh_01(void) {
+ char *invite_corenode2, *invite_app1node1, *invite_app2node1, *invite_app1node2, *invite_app2node2;
+ bool result = false;
+ int i;
+ char *import;
+ pthread_t thread1, thread2;
+
+ import = mesh_event_sock_create(eth_if_name);
+ invite_corenode2 = invite_in_container("corenode1", "corenode2");
+ invite_app1node1 = submesh_invite_in_container("corenode1", "app1node1", "app1");
+ invite_app2node1 = submesh_invite_in_container("corenode1", "app2node1", "app2");
+ invite_app1node2 = submesh_invite_in_container("corenode1", "app1node2", "app1");
+ invite_app2node2 = submesh_invite_in_container("corenode1", "app2node2", "app2");
+
+ node_sim_in_container_event("corenode1", "1", NULL, CORENODE1_ID, import);
+ node_sim_in_container_event("corenode2", "1", invite_corenode2, CORENODE2_ID, import);
+ node_sim_in_container_event("app1node1", "1", invite_app1node1, APP1NODE1_ID, import);
+ node_sim_in_container_event("app2node1", "1", invite_app2node1, APP2NODE1_ID, import);
+ node_sim_in_container_event("app1node2", "1", invite_app1node2, APP1NODE2_ID, import);
+ node_sim_in_container_event("app2node2", "1", invite_app2node2, APP2NODE2_ID, import);
+
+ PRINT_TEST_CASE_MSG("Waiting for nodes to get connected with corenode1\n");
+
+ assert(wait_for_event(event_cb, 240));
+ assert(test_case_status);
+
+ free(invite_corenode2);
+ free(invite_app1node1);
+ free(invite_app2node1);
+ free(invite_app1node2);
+ free(invite_app2node2);
+
+ mesh_event_destroy();
+
+ return true;
+}
+
+int test_cases_submesh01(void) {
+ const struct CMUnitTest blackbox_group0_tests[] = {
+ cmocka_unit_test_prestate_setup_teardown(test_case_submesh_01, setup_test, teardown_test,
+ (void *)&test_case_submesh_1_state)
+ };
+ total_tests += sizeof(blackbox_group0_tests) / sizeof(blackbox_group0_tests[0]);
+
+ return cmocka_run_group_tests(blackbox_group0_tests, black_box_group0_setup, black_box_group0_teardown);
+}
\ No newline at end of file
--- /dev/null
+#ifndef TEST_CASES_SUBMESH_H
+#define TEST_CASES_SUBMESH_H
+
+/*
+ test_cases_submesh01.h -- Declarations for Individual Test Case implementation functions
+ Copyright (C) 2018 Guus Sliepen <guus@meshlink.io>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+
+#include <stdbool.h>
+#include "../common/mesh_event_handler.h"
+
+extern int total_tests;
+extern int test_cases_submesh01(void);
+
+#endif // TEST_CASES_SUBMESH_H
\ No newline at end of file
--- /dev/null
+/*
+ test_cases_submesh02.c -- Execution of specific meshlink black box test cases
+ Copyright (C) 2018 Guus Sliepen <guus@meshlink.io>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#include <stdlib.h>
+#include <stdarg.h>
+#include <setjmp.h>
+#include <cmocka.h>
+#include <assert.h>
+#include "execute_tests.h"
+#include "test_cases_submesh02.h"
+#include "pthread.h"
+#include "../common/containers.h"
+#include "../common/test_step.h"
+#include "../common/common_handlers.h"
+#include "../common/mesh_event_handler.h"
+
+#define CORENODE1_ID "0"
+#define APP1NODE1_ID "1"
+#define APP2NODE1_ID "2"
+#define CORENODE2_ID "3"
+#define APP1NODE2_ID "4"
+#define APP2NODE2_ID "5"
+
+#define INIT_ST 0
+
+static bool test_case_status = false;
+
+static void test_case_submesh_02(void **state);
+static bool test_steps_submesh_02(void);
+
+static char event_node_name[][10] = {"CORENODE1", "APP1NODE1", "APP2NODE1", "CORENODE2",
+ "APP1NODE2", "APP2NODE2"
+ };
+static const char *node_ids[] = { "corenode1", "app1node1", "app2node1", "corenode2",
+ "app1node2", "app2node2"
+ };
+
+static mesh_event_t core_node1[] = { NODE_STARTED, CHANNEL_OPENED, CHANNEL_DATA_RECIEVED};
+
+static mesh_event_t core_node2[] = { NODE_STARTED, NODE_JOINED, CHANNEL_OPENED, CHANNEL_DATA_RECIEVED};
+
+static mesh_event_t app1_node1[] = { NODE_STARTED, NODE_JOINED, CHANNEL_OPENED, CHANNEL_DATA_RECIEVED};
+
+static mesh_event_t app2_node1[] = { NODE_STARTED, NODE_JOINED, CHANNEL_OPENED, CHANNEL_DATA_RECIEVED};
+
+static mesh_event_t app1_node2[] = { NODE_STARTED, NODE_JOINED, CHANNEL_OPENED, CHANNEL_DATA_RECIEVED, CHANNEL_OPENED, CHANNEL_DATA_RECIEVED, MESH_EVENT_COMPLETED};
+
+static mesh_event_t app2_node2[] = { NODE_STARTED, NODE_JOINED, CHANNEL_OPENED, CHANNEL_DATA_RECIEVED, CHANNEL_OPENED, CHANNEL_DATA_RECIEVED, MESH_EVENT_COMPLETED};
+
+/* State structure for SubMesh Test Case #1 */
+static char *test_case_submesh_2_nodes[] = { "corenode1", "app1node1", "app2node1", "corenode2", "app1node2", "app2node2" };
+static black_box_state_t test_case_submesh_2_state = {
+ .test_case_name = "test_cases_submesh02",
+ .node_names = test_case_submesh_2_nodes,
+ .num_nodes = 6
+};
+
+static int black_box_group0_setup(void **state) {
+ const char *nodes[] = { "corenode1", "app1node1", "app2node1", "corenode2", "app1node2", "app2node2" };
+ int num_nodes = sizeof(nodes) / sizeof(nodes[0]);
+
+ PRINT_TEST_CASE_MSG("Creating Containers\n");
+ destroy_containers();
+ create_containers(nodes, num_nodes);
+
+ return 0;
+}
+
+static int black_box_group0_teardown(void **state) {
+ PRINT_TEST_CASE_MSG("Destroying Containers\n");
+ destroy_containers();
+
+ return 0;
+}
+
+static int black_box_all_nodes_setup(void **state) {
+ const char *nodes[] = { "corenode1" };
+ int num_nodes = sizeof(nodes) / sizeof(nodes[0]);
+
+ PRINT_TEST_CASE_MSG("Creating Containers\n");
+ destroy_containers();
+ create_containers(nodes, num_nodes);
+ PRINT_TEST_CASE_MSG("Created Containers\n");
+ return 0;
+}
+
+static bool event_cb(mesh_event_payload_t payload) {
+ static node_status_t node_status[6] = {
+ {core_node1, 0, 3, false},
+ {app1_node1, 0, 4, false},
+ {app2_node1, 0, 4, false},
+ {core_node2, 0, 4, false},
+ {app1_node2, 0, 7, false},
+ {app2_node2, 0, 7, false}
+ };
+
+ fprintf(stderr, "%s(%lu) : %s\n", event_node_name[payload.client_id], time(NULL), event_status[payload.mesh_event]);
+ assert(change_state(&node_status[payload.client_id], payload.mesh_event));
+
+ if(payload.mesh_event == NODE_JOINED) {
+ signal_node_start(node_status, 1, 5, node_ids);
+ }
+
+ if(check_nodes_finished(node_status, 6)) {
+ test_case_status = true;
+ return true;
+ }
+
+ return false;
+}
+
+/* Execute SubMesh Test Case # 2 */
+static void test_case_submesh_02(void **state) {
+ execute_test(test_steps_submesh_02, state);
+}
+
+/* Test Steps for SubMesh Test Case # 2
+
+ Test Steps:
+ 1. Run corenode1, app1node1, app2node1, corenode2, app1node2 and app2node2
+ 2. Generate invites to app1node1, app2node1, corenode2, app1node2 and app2node2
+ from corenode1 to join corenode1.
+ 3. After Join is successful start channels from all nodes and exchange data on channels
+ 4. Try to fetch the list of all nodes and check if the nodes in other submesh doesnot
+ appear in the list.
+ 5. Try fetch all the nodes with a submesh handle and check only if both the nodes joining
+ the submesh are present.
+
+ Expected Result:
+ Channels should be formed between nodes of sub-mesh & coremesh, nodes with in sub-mesh
+ and should be able to exchange data. Lis of all nodes should only conatin four nodes
+ and the list of submesh should only conatin two nodes of that submesh.
+*/
+static bool test_steps_submesh_02(void) {
+ char *invite_corenode2, *invite_app1node1, *invite_app2node1, *invite_app1node2, *invite_app2node2;
+ bool result = false;
+ int i;
+ char *import;
+ pthread_t thread1, thread2;
+
+ import = mesh_event_sock_create(eth_if_name);
+ invite_corenode2 = invite_in_container("corenode1", "corenode2");
+ invite_app1node1 = submesh_invite_in_container("corenode1", "app1node1", "app1");
+ invite_app2node1 = submesh_invite_in_container("corenode1", "app2node1", "app2");
+ invite_app1node2 = submesh_invite_in_container("corenode1", "app1node2", "app1");
+ invite_app2node2 = submesh_invite_in_container("corenode1", "app2node2", "app2");
+
+ node_sim_in_container_event("corenode1", "1", NULL, CORENODE1_ID, import);
+ node_sim_in_container_event("corenode2", "1", invite_corenode2, CORENODE2_ID, import);
+ node_sim_in_container_event("app1node1", "1", invite_app1node1, APP1NODE1_ID, import);
+ node_sim_in_container_event("app2node1", "1", invite_app2node1, APP2NODE1_ID, import);
+ node_sim_in_container_event("app1node2", "1", invite_app1node2, APP1NODE2_ID, import);
+ node_sim_in_container_event("app2node2", "1", invite_app2node2, APP2NODE2_ID, import);
+
+ PRINT_TEST_CASE_MSG("Waiting for nodes to get connected with corenode1\n");
+
+ assert(wait_for_event(event_cb, 240));
+ assert(test_case_status);
+
+ free(invite_corenode2);
+ free(invite_app1node1);
+ free(invite_app2node1);
+ free(invite_app1node2);
+ free(invite_app2node2);
+
+ mesh_event_destroy();
+
+ return true;
+}
+
+int test_cases_submesh02(void) {
+ const struct CMUnitTest blackbox_group0_tests[] = {
+ cmocka_unit_test_prestate_setup_teardown(test_case_submesh_02, setup_test, teardown_test,
+ (void *)&test_case_submesh_2_state)
+ };
+ total_tests += sizeof(blackbox_group0_tests) / sizeof(blackbox_group0_tests[0]);
+
+ return cmocka_run_group_tests(blackbox_group0_tests, black_box_group0_setup, black_box_group0_teardown);
+}
\ No newline at end of file
--- /dev/null
+#ifndef TEST_CASES_SUBMESH02_H
+#define TEST_CASES_SUBMESH02_H
+
+/*
+ test_cases_submesh02.h -- Declarations for Individual Test Case implementation functions
+ Copyright (C) 2018 Guus Sliepen <guus@meshlink.io>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+
+#include <stdbool.h>
+#include "../common/mesh_event_handler.h"
+
+extern int total_tests;
+extern int test_cases_submesh02(void);
+
+#endif // TEST_CASES_SUBMESH02_H
\ No newline at end of file
--- /dev/null
+/*
+ test_cases_submesh03.c -- Execution of specific meshlink black box test cases
+ Copyright (C) 2018 Guus Sliepen <guus@meshlink.io>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#include <stdlib.h>
+#include <stdarg.h>
+#include <setjmp.h>
+#include <cmocka.h>
+#include <assert.h>
+#include "execute_tests.h"
+#include "test_cases_submesh03.h"
+#include "pthread.h"
+#include "../common/containers.h"
+#include "../common/test_step.h"
+#include "../common/common_handlers.h"
+#include "../common/mesh_event_handler.h"
+
+#define CORENODE1_ID "0"
+#define APP1NODE1_ID "1"
+#define APP1NODE2_ID "2"
+
+#define INIT_ST 0
+
+static bool test_case_status = false;
+
+static void test_case_submesh_03(void **state);
+static bool test_steps_submesh_03(void);
+
+static char event_node_name[][10] = {"CORENODE1", "APP1NODE1", "APP1NODE2"};
+static const char *node_ids[] = { "corenode1", "app1node1", "app1node2" };
+
+static mesh_event_t core_node1[] = { NODE_STARTED, CHANNEL_OPENED, CHANNEL_DATA_RECIEVED};
+
+static mesh_event_t app1_node1[] = { NODE_STARTED, NODE_JOINED, CHANNEL_OPENED, CHANNEL_DATA_RECIEVED};
+
+static mesh_event_t app1_node2[] = { NODE_STARTED, NODE_JOINED, CHANNEL_OPENED, CHANNEL_DATA_RECIEVED, CHANNEL_OPENED, CHANNEL_DATA_RECIEVED, MESH_EVENT_COMPLETED};
+
+static node_status_t node_status[3] = {
+ {core_node1, 0, 3, false},
+ {app1_node1, 0, 4, false},
+ {app1_node2, 0, 7, false}
+};
+
+/* State structure for SubMesh Test Case #3 */
+static char *test_case_submesh_3_nodes[] = { "corenode1", "app1node1", "app1node2" };
+static black_box_state_t test_case_submesh_3_state = {
+ .test_case_name = "test_cases_submesh03",
+ .node_names = test_case_submesh_3_nodes,
+ .num_nodes = 3
+};
+
+static int black_box_group0_setup(void **state) {
+ const char *nodes[] = { "corenode1", "app1node1", "app1node2" };
+ int num_nodes = sizeof(nodes) / sizeof(nodes[0]);
+
+ PRINT_TEST_CASE_MSG("Creating Containers\n");
+ destroy_containers();
+ create_containers(nodes, num_nodes);
+
+ return 0;
+}
+
+static int black_box_group0_teardown(void **state) {
+ PRINT_TEST_CASE_MSG("Destroying Containers\n");
+ destroy_containers();
+
+ return 0;
+}
+
+static int black_box_all_nodes_setup(void **state) {
+ const char *nodes[] = { "corenode1" };
+ int num_nodes = sizeof(nodes) / sizeof(nodes[0]);
+
+ PRINT_TEST_CASE_MSG("Creating Containers\n");
+ destroy_containers();
+ create_containers(nodes, num_nodes);
+ PRINT_TEST_CASE_MSG("Created Containers\n");
+ return 0;
+}
+
+static void restart_all_nodes(char *import) {
+ int i;
+
+ for(i = 0; i < 3; i++) {
+ node_step_in_container(node_ids[i], "SIGTERM");
+ node_status[i].current_index = 0;
+ }
+
+ sleep(5);
+
+ node_sim_in_container_event("corenode1", "1", NULL, CORENODE1_ID, import);
+ node_sim_in_container_event("app1node1", "1", NULL, APP1NODE1_ID, import);
+ node_sim_in_container_event("app1node2", "1", NULL, APP1NODE2_ID, import);
+}
+
+static bool event_cb(mesh_event_payload_t payload) {
+
+ fprintf(stderr, "%s(%lu) : %s\n", event_node_name[payload.client_id], time(NULL), event_status[payload.mesh_event]);
+ assert(change_state(&node_status[payload.client_id], payload.mesh_event));
+
+ if(payload.mesh_event == NODE_JOINED) {
+ signal_node_start(node_status, 1, 2, node_ids);
+ }
+
+ if(check_nodes_finished(node_status, 3)) {
+ test_case_status = true;
+ return true;
+ }
+
+ return false;
+}
+
+/* Execute SubMesh Test Case # 3 */
+static void test_case_submesh_03(void **state) {
+ execute_test(test_steps_submesh_03, state);
+}
+
+/* Test Steps for SubMesh Test Case # 3
+
+ Test Steps:
+ 1. Run corenode1, app1node1, and app1node2
+ 2. Generate invites to app1node1, and app1node2
+ from corenode1 to join corenode1.
+ 3. After Join is successful start channels from all nodes and exchange data on channels
+ 4. Try to restart all the nodes at the same time.
+
+ Expected Result:
+ Channels should be formed between nodes of sub-mesh & coremesh, nodes with in sub-mesh
+ and should be able to exchange data even after restart.
+*/
+static bool test_steps_submesh_03(void) {
+ char *invite_app1node1, *invite_app1node2;
+ bool result = false;
+ int i;
+ char *import;
+ pthread_t thread1, thread2;
+
+ import = mesh_event_sock_create(eth_if_name);
+ invite_app1node1 = invite_in_container("corenode1", "app1node1");
+ invite_app1node2 = invite_in_container("corenode1", "app1node2");
+
+ node_sim_in_container_event("corenode1", "1", NULL, CORENODE1_ID, import);
+ node_sim_in_container_event("app1node1", "1", invite_app1node1, APP1NODE1_ID, import);
+ node_sim_in_container_event("app1node2", "1", invite_app1node2, APP1NODE2_ID, import);
+
+ PRINT_TEST_CASE_MSG("Waiting for nodes to get connected with corenode1\n");
+
+ assert(wait_for_event(event_cb, 120));
+ assert(test_case_status);
+
+ test_case_status = false;
+
+ restart_all_nodes(import);
+ PRINT_TEST_CASE_MSG("Waiting for nodes to get restarted\n");
+
+ assert(wait_for_event(event_cb, 120));
+ assert(test_case_status);
+
+ free(invite_app1node1);
+ free(invite_app1node2);
+
+ mesh_event_destroy();
+
+ return true;
+}
+
+int test_cases_submesh03(void) {
+ const struct CMUnitTest blackbox_group0_tests[] = {
+ cmocka_unit_test_prestate_setup_teardown(test_case_submesh_03, setup_test, teardown_test,
+ (void *)&test_case_submesh_3_state)
+ };
+ total_tests += sizeof(blackbox_group0_tests) / sizeof(blackbox_group0_tests[0]);
+
+ return cmocka_run_group_tests(blackbox_group0_tests, black_box_group0_setup, black_box_group0_teardown);
+}
\ No newline at end of file
--- /dev/null
+#ifndef TEST_CASES_SUBMESH03_H
+#define TEST_CASES_SUBMESH03_H
+
+/*
+ test_cases_submesh03.h -- Declarations for Individual Test Case implementation functions
+ Copyright (C) 2018 Guus Sliepen <guus@meshlink.io>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+
+#include <stdbool.h>
+#include "../common/mesh_event_handler.h"
+
+extern int total_tests;
+extern int test_cases_submesh03(void);
+
+#endif // TEST_CASES_SUBMESH03_H
\ No newline at end of file
--- /dev/null
+/*
+ test_cases_submesh05.c -- Execution of specific meshlink black box test cases
+ Copyright (C) 2018 Guus Sliepen <guus@meshlink.io>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#include <stdlib.h>
+#include <stdarg.h>
+#include <setjmp.h>
+#include <cmocka.h>
+#include <assert.h>
+#include "execute_tests.h"
+#include "test_cases_submesh04.h"
+#include "pthread.h"
+#include "../common/containers.h"
+#include "../common/test_step.h"
+#include "../common/common_handlers.h"
+#include "../common/mesh_event_handler.h"
+
+#define CORENODE1_ID "0"
+#define APP1NODE1_ID "1"
+#define APP1NODE2_ID "2"
+
+#define INIT_ST 0
+
+static bool test_case_status = false;
+
+static void test_case_submesh_04(void **state);
+static bool test_steps_submesh_04(void);
+
+static char event_node_name[][10] = {"CORENODE1", "APP1NODE1", "APP1NODE2"};
+static const char *node_ids[] = { "corenode1", "app1node1", "app1node2" };
+
+static mesh_event_t core_node1[] = { NODE_STARTED, CHANNEL_OPENED, CHANNEL_DATA_RECIEVED };
+
+static mesh_event_t app1_node1[] = { NODE_STARTED, NODE_JOINED, CHANNEL_OPENED, CHANNEL_DATA_RECIEVED };
+
+static mesh_event_t app1_node2[] = { NODE_STARTED, NODE_JOINED, CHANNEL_OPENED, CHANNEL_DATA_RECIEVED, CHANNEL_OPENED, CHANNEL_DATA_RECIEVED, MESH_EVENT_COMPLETED};
+
+/* State structure for SubMesh Test Case #4 */
+static char *test_case_submesh_4_nodes[] = { "corenode1", "app1node1", "app1node2" };
+static black_box_state_t test_case_submesh_4_state = {
+ .test_case_name = "test_cases_submesh04",
+ .node_names = test_case_submesh_4_nodes,
+ .num_nodes = 3
+};
+
+static int black_box_group0_setup(void **state) {
+ const char *nodes[] = { "corenode1", "app1node1", "app1node2" };
+ int num_nodes = sizeof(nodes) / sizeof(nodes[0]);
+
+ PRINT_TEST_CASE_MSG("Creating Containers\n");
+ destroy_containers();
+ create_containers(nodes, num_nodes);
+
+ return 0;
+}
+
+static int black_box_group0_teardown(void **state) {
+ PRINT_TEST_CASE_MSG("Destroying Containers\n");
+ destroy_containers();
+
+ return 0;
+}
+
+static int black_box_all_nodes_setup(void **state) {
+ const char *nodes[] = { "corenode1" };
+ int num_nodes = sizeof(nodes) / sizeof(nodes[0]);
+
+ PRINT_TEST_CASE_MSG("Creating Containers\n");
+ destroy_containers();
+ create_containers(nodes, num_nodes);
+ PRINT_TEST_CASE_MSG("Created Containers\n");
+ return 0;
+}
+
+static bool event_cb(mesh_event_payload_t payload) {
+ static node_status_t node_status[3] = {
+ {core_node1, 0, 3, false},
+ {app1_node1, 0, 4, false},
+ {app1_node2, 0, 7, false}
+ };
+
+ fprintf(stderr, "%s(%lu) : %s\n", event_node_name[payload.client_id], time(NULL), event_status[payload.mesh_event]);
+ assert(change_state(&node_status[payload.client_id], payload.mesh_event));
+
+ if(payload.mesh_event == NODE_JOINED) {
+ signal_node_start(node_status, 1, 2, node_ids);
+ }
+
+ if(check_nodes_finished(node_status, 3)) {
+ test_case_status = true;
+ return true;
+ }
+
+ return false;
+}
+
+/* Execute SubMesh Test Case # 4 */
+static void test_case_submesh_04(void **state) {
+ execute_test(test_steps_submesh_04, state);
+}
+
+/* Test Steps for SubMesh Test Case # 4
+
+ Test Steps:
+ 1. Run corenode1, app1node1, and app1node2
+ 2. Generate invites to app1node1, app1node2
+ from corenode1 to join corenode1.
+ 3. After Join is successful start channels from all nodes and exchange data on channels
+ 4. Black list a node in the submesh and check if it is successful
+ 5. White list the node and it should be form all the connections again
+
+ Expected Result:
+ Channels should be formed between nodes of sub-mesh & coremesh, nodes with in sub-mesh
+ and should be able to exchange data. When black listed, other node should not get any
+ from the black listed node. When white listed again it has to form the connections as
+ they were previously before black listing.
+*/
+static bool test_steps_submesh_04(void) {
+ char *invite_app1node1, *invite_app1node2;
+ bool result = false;
+ int i;
+ char *import;
+ pthread_t thread1, thread2;
+
+ import = mesh_event_sock_create(eth_if_name);
+ invite_app1node1 = invite_in_container("corenode1", "app1node1");
+ invite_app1node2 = invite_in_container("corenode1", "app1node2");
+
+ node_sim_in_container_event("corenode1", "1", NULL, CORENODE1_ID, import);
+ node_sim_in_container_event("app1node1", "1", invite_app1node1, APP1NODE1_ID, import);
+ node_sim_in_container_event("app1node2", "1", invite_app1node2, APP1NODE2_ID, import);
+
+ PRINT_TEST_CASE_MSG("Waiting for nodes to get connected with corenode1\n");
+
+ assert(wait_for_event(event_cb, 120));
+ assert(test_case_status);
+
+ free(invite_app1node1);
+ free(invite_app1node2);
+
+ mesh_event_destroy();
+
+ return true;
+}
+
+int test_cases_submesh04(void) {
+ const struct CMUnitTest blackbox_group0_tests[] = {
+ cmocka_unit_test_prestate_setup_teardown(test_case_submesh_04, setup_test, teardown_test,
+ (void *)&test_case_submesh_4_state)
+ };
+ total_tests += sizeof(blackbox_group0_tests) / sizeof(blackbox_group0_tests[0]);
+
+ return cmocka_run_group_tests(blackbox_group0_tests, black_box_group0_setup, black_box_group0_teardown);
+}
\ No newline at end of file
--- /dev/null
+#ifndef TEST_CASES_SUBMESH04_H
+#define TEST_CASES_SUBMESH04_H
+
+/*
+ test_cases_submesh04.h -- Declarations for Individual Test Case implementation functions
+ Copyright (C) 2018 Guus Sliepen <guus@meshlink.io>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+
+#include <stdbool.h>
+#include "../common/mesh_event_handler.h"
+
+extern int total_tests;
+extern int test_cases_submesh04(void);
+
+#endif // TEST_CASES_SUBMESH04_H
\ No newline at end of file
node_sim_nut_SOURCES = node_sim_nut.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c
node_sim_nut_LDADD = ../../../src/libmeshlink.la
-node_sim_nut_CFLAGS = -D_GNU_SOURCE
+node_sim_nut_CFLAGS = -D_GNU_SOURCE
\ No newline at end of file
if(!argv[CMD_LINE_ARG_INVITEURL]) {
fprintf(stderr, "Generating Inviation to PEER\n");
- invite_peer = execute_invite("peer");
+ invite_peer = execute_invite("peer", NULL);
assert(invite_peer != NULL);
if(!mesh_event_sock_send(clientId, NODE_INVITATION, invite_peer, strlen(invite_peer) + 1)) {
}
fprintf(stderr, "Generating Inviation to PEER\n");
- invite_peer = execute_invite("peer");
+ invite_peer = execute_invite("peer", NULL);
assert(invite_peer != NULL);
if(!mesh_event_sock_send(clientId, NODE_INVITATION, invite_peer, strlen(invite_peer) + 1)) {
--- /dev/null
+check_PROGRAMS = node_sim_corenode1 node_sim_corenode2 node_sim_app1node1 node_sim_app1node2 node_sim_app2node1 node_sim_app2node2
+
+node_sim_corenode1_SOURCES = node_sim_corenode1.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c
+node_sim_corenode1_LDADD = ../../../src/libmeshlink.la
+node_sim_corenode1_CFLAGS = -D_GNU_SOURCE
+
+node_sim_corenode2_SOURCES = node_sim_corenode2.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c
+node_sim_corenode2_LDADD = ../../../src/libmeshlink.la
+node_sim_corenode2_CFLAGS = -D_GNU_SOURCE
+
+node_sim_app1node1_SOURCES = node_sim_app1node1.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c
+node_sim_app1node1_LDADD = ../../../src/libmeshlink.la
+node_sim_app1node1_CFLAGS = -D_GNU_SOURCE
+
+node_sim_app1node2_SOURCES = node_sim_app1node2.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c
+node_sim_app1node2_LDADD = ../../../src/libmeshlink.la
+node_sim_app1node2_CFLAGS = -D_GNU_SOURCE
+
+node_sim_app2node1_SOURCES = node_sim_app2node1.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c
+node_sim_app2node1_LDADD = ../../../src/libmeshlink.la
+node_sim_app2node1_CFLAGS = -D_GNU_SOURCE
+
+node_sim_app2node2_SOURCES = node_sim_app2node2.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c
+node_sim_app2node2_LDADD = ../../../src/libmeshlink.la
+node_sim_app2node2_CFLAGS = -D_GNU_SOURCE
--- /dev/null
+/*
+ node_sim_peer.c -- Implementation of Node Simulation for Meshlink Testing
+ for meta connection test case 01 - re-connection of
+ two nodes when relay node goes down
+ Copyright (C) 2018 Guus Sliepen <guus@meshlink.io>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <assert.h>
+#include <signal.h>
+#include <time.h>
+#include "../common/common_handlers.h"
+#include "../common/test_step.h"
+#include "../common/mesh_event_handler.h"
+#include "../../utils.h"
+
+#define CMD_LINE_ARG_NODENAME 1
+#define CMD_LINE_ARG_DEVCLASS 2
+#define CMD_LINE_ARG_CLIENTID 3
+#define CMD_LINE_ARG_IMPORTSTR 4
+#define CMD_LINE_ARG_INVITEURL 5
+#define CHANNEL_PORT 1234
+
+static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len);
+static bool channel_accept(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *dat, size_t len);
+
+static int client_id = -1;
+static meshlink_handle_t *mesh = NULL;
+
+static struct sync_flag peer_reachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag start_test = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag channel_opened = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag channel_data_recieved = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+
+static void send_event(mesh_event_t event) {
+ int attempts;
+
+ for(attempts = 0; attempts < 5; attempts += 1) {
+ if(mesh_event_sock_send(client_id, event, NULL, 0)) {
+ break;
+ }
+ }
+
+ assert(attempts < 5);
+
+ return;
+}
+
+static bool channel_accept(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *dat, size_t len) {
+ (void)dat;
+ (void)len;
+
+ assert(port == CHANNEL_PORT);
+
+ fprintf(stderr, "\tapp1node1 got channel request from %s\n", channel->node->name);
+
+ if(!strcmp(channel->node->name, "corenode1")) {
+ fprintf(stderr, "\tapp1node1 accepting channel request from %s at %lu\n", channel->node->name, time(NULL));
+ meshlink_set_channel_receive_cb(mesh, channel, channel_receive_cb);
+ mesh->priv = channel;
+
+ return true;
+ } else if(!strcmp(channel->node->name, "app1node2")) {
+ fprintf(stderr, "\tapp1node1 accepting channel request from %s at %lu\n", channel->node->name, time(NULL));
+ meshlink_set_channel_receive_cb(mesh, channel, channel_receive_cb);
+ mesh->priv = channel;
+
+ return true;
+ }
+
+ fprintf(stderr, "\tapp1node1 rejecting channel request from %s at %lu\n", channel->node->name, time(NULL));
+ return false;
+}
+
+/* channel receive callback */
+static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) {
+ char data[100] = {0};
+ char *message = "Channel Message";
+
+ if(len == 0) {
+ fprintf(stderr, "\tapp1node1 got error from %s at %lu\n", channel->node->name, time(NULL));
+ send_event(ERR_NETWORK);
+ return;
+ }
+
+ memcpy(data, dat, len);
+
+ fprintf(stderr, "\tapp1node1 got message from %s as %s\n", channel->node->name, data);
+
+ if(!strcmp(channel->node->name, "corenode1")) {
+ if(!memcmp(dat, "Channel Message", len)) {
+ set_sync_flag(&channel_data_recieved, true);
+ } else if(!memcmp(dat, "failure", 7)) {
+ assert(false);
+ }
+ } else if(!strcmp(channel->node->name, "app1node2")) {
+ if(!memcmp(dat, "Channel Message", len)) {
+ assert(meshlink_channel_send(mesh, channel, message, strlen(message)) >= 0);
+ } else if(!memcmp(dat, "failure", 7)) {
+ assert(false);
+ }
+ }
+
+ return;
+}
+
+static void poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, size_t len) {
+ char *message = "Channel Message";
+ char *node = (char *)channel->node->name;
+ (void)len;
+ meshlink_set_channel_poll_cb(mesh, channel, NULL);
+ fprintf(stderr, "\tapp1node1's Channel request has been accepted by %s at : %lu\n", node, time(NULL));
+
+ if(0 == strcmp("corenode1", node)) {
+ set_sync_flag(&channel_opened, true);
+ }
+
+ assert(meshlink_channel_send(mesh, channel, message, strlen(message)) >= 0);
+ return;
+}
+
+
+static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node,
+ bool reachable) {
+ if(!strcasecmp(node->name, "corenode1")) {
+ if(reachable) {
+ fprintf(stderr, "\tNode corenode1 became reachable\n");
+ set_sync_flag(&peer_reachable, true);
+ }
+ }
+
+ return;
+}
+
+void mesh_start_test_handler(int a) {
+ fprintf(stderr, "Starting test in app1node1\n");
+ set_sync_flag(&start_test, true);
+}
+
+int main(int argc, char *argv[]) {
+ struct timeval main_loop_wait = { 2, 0 };
+ meshlink_channel_t *channel = NULL;
+ meshlink_node_t *core_node = NULL;
+
+ fprintf(stderr, "\tMesh node 'app1node1' starting up........\n");
+
+ // Import mesh event handler
+
+ if((argv[CMD_LINE_ARG_CLIENTID]) && (argv[CMD_LINE_ARG_IMPORTSTR])) {
+ client_id = atoi(argv[CMD_LINE_ARG_CLIENTID]);
+ mesh_event_sock_connect(argv[CMD_LINE_ARG_IMPORTSTR]);
+ }
+
+ // Setup required signals
+
+ setup_signals();
+ signal(SIGIO, mesh_start_test_handler);
+
+ // Run peer node instance
+
+ mesh = meshlink_open("app1node1conf", argv[CMD_LINE_ARG_NODENAME],
+ "test_channel_conn", atoi(argv[CMD_LINE_ARG_DEVCLASS]));
+ assert(mesh);
+ meshlink_set_log_cb(mesh, MESHLINK_DEBUG, meshlink_callback_logger);
+ meshlink_set_channel_accept_cb(mesh, channel_accept);
+ meshlink_set_node_status_cb(mesh, node_status_cb);
+
+ if(argv[CMD_LINE_ARG_INVITEURL]) {
+ assert(meshlink_join(mesh, argv[CMD_LINE_ARG_INVITEURL]));
+ }
+
+ assert(meshlink_start(mesh));
+
+ send_event(NODE_STARTED);
+
+ // Wait for peer node to join
+
+ assert(wait_sync_flag(&peer_reachable, 15));
+ send_event(NODE_JOINED);
+
+ while(false == wait_sync_flag(&start_test, 10));
+
+ // Open a channel to peer node
+ core_node = meshlink_get_node(mesh, "corenode1");
+ assert(core_node);
+ fprintf(stderr, "\tapp1node1 Sending Channel request to corenode1 at : %lu\n", time(NULL));
+ channel = meshlink_channel_open(mesh, core_node, CHANNEL_PORT,
+ channel_receive_cb, NULL, 0);
+ meshlink_set_channel_poll_cb(mesh, channel, poll_cb);
+ assert(wait_sync_flag(&channel_opened, 100));
+ send_event(CHANNEL_OPENED);
+
+ assert(wait_sync_flag(&channel_data_recieved, 100));
+ send_event(CHANNEL_DATA_RECIEVED);
+
+ // All test steps executed - wait for signals to stop/start or close the mesh
+
+ while(test_running) {
+ select(1, NULL, NULL, NULL, &main_loop_wait);
+ }
+
+ meshlink_close(mesh);
+
+ return EXIT_SUCCESS;
+}
\ No newline at end of file
--- /dev/null
+/*
+ node_sim_peer.c -- Implementation of Node Simulation for Meshlink Testing
+ for meta connection test case 01 - re-connection of
+ two nodes when relay node goes down
+ Copyright (C) 2018 Guus Sliepen <guus@meshlink.io>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <assert.h>
+#include <signal.h>
+#include <time.h>
+#include "../common/common_handlers.h"
+#include "../common/test_step.h"
+#include "../common/mesh_event_handler.h"
+#include "../../utils.h"
+
+#define CMD_LINE_ARG_NODENAME 1
+#define CMD_LINE_ARG_DEVCLASS 2
+#define CMD_LINE_ARG_CLIENTID 3
+#define CMD_LINE_ARG_IMPORTSTR 4
+#define CMD_LINE_ARG_INVITEURL 5
+#define CHANNEL_PORT 1234
+
+static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len);
+static bool channel_accept(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *dat, size_t len);
+
+static int client_id = -1;
+static meshlink_handle_t *mesh = NULL;
+
+static struct sync_flag peer_reachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag start_test = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag app_reachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag channel_opened = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag channel_data_recieved = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+
+static void send_event(mesh_event_t event) {
+ int attempts;
+
+ for(attempts = 0; attempts < 5; attempts += 1) {
+ if(mesh_event_sock_send(client_id, event, NULL, 0)) {
+ break;
+ }
+ }
+
+ assert(attempts < 5);
+
+ return;
+}
+
+static bool channel_accept(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *dat, size_t len) {
+ (void)dat;
+ (void)len;
+
+ assert(port == CHANNEL_PORT);
+
+ fprintf(stderr, "\tapp1node2 got channel request from %s\n", channel->node->name);
+
+ if(!strcmp(channel->node->name, "corenode1")) {
+ meshlink_set_channel_receive_cb(mesh, channel, channel_receive_cb);
+ mesh->priv = channel;
+
+ return true;
+ }
+
+ return false;
+}
+
+/* channel receive callback */
+static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) {
+ char data[100] = {0};
+
+ if(len == 0) {
+ fprintf(stderr, "\tapp1node2 got error from %s at %lu\n", channel->node->name, time(NULL));
+ send_event(ERR_NETWORK);
+ return;
+ }
+
+ memcpy(data, dat, len);
+
+ fprintf(stderr, "\tapp1node2 got message from %s as %s\n", channel->node->name, data);
+
+ if(!strcmp(channel->node->name, "corenode1")) {
+ if(!memcmp(dat, "Channel Message", len)) {
+ set_sync_flag(&channel_data_recieved, true);
+ } else if(!memcmp(dat, "failure", 7)) {
+ assert(false);
+ }
+ } else if(!strcmp(channel->node->name, "app1node1")) {
+ if(!memcmp(dat, "Channel Message", len)) {
+ set_sync_flag(&channel_data_recieved, true);
+ } else if(!memcmp(dat, "failure", 7)) {
+ assert(false);
+ }
+ } else {
+ assert(false);
+ }
+
+ return;
+}
+
+static void poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, size_t len) {
+ char *message = "Channel Message";
+ char *node = (char *)channel->node->name;
+ (void)len;
+ meshlink_set_channel_poll_cb(mesh, channel, NULL);
+ fprintf(stderr, "\tapp1node2's Channel request has been accepted by %s at : %lu\n", node, time(NULL));
+ set_sync_flag(&channel_opened, true);
+ assert(meshlink_channel_send(mesh, channel, message, strlen(message)) >= 0);
+ return;
+}
+
+
+static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node,
+ bool reachable) {
+ if(!strcasecmp(node->name, "corenode1")) {
+ if(reachable) {
+ fprintf(stderr, "\tNode corenode1 became reachable\n");
+ set_sync_flag(&peer_reachable, true);
+ }
+ } else if(!strcasecmp(node->name, "app1node1")) {
+ if(reachable) {
+ fprintf(stderr, "\tNode app1node1 became reachable\n");
+ set_sync_flag(&app_reachable, true);
+ }
+ }
+
+ return;
+}
+
+void mesh_start_test_handler(int a) {
+ fprintf(stderr, "Starting test in app1node2\n");
+ set_sync_flag(&start_test, true);
+}
+
+int main(int argc, char *argv[]) {
+ struct timeval main_loop_wait = { 2, 0 };
+ meshlink_channel_t *channel = NULL;
+ meshlink_node_t *core_node = NULL;
+
+ fprintf(stderr, "\tMesh node 'app1node2' starting up........\n");
+
+ // Import mesh event handler
+
+ if((argv[CMD_LINE_ARG_CLIENTID]) && (argv[CMD_LINE_ARG_IMPORTSTR])) {
+ client_id = atoi(argv[CMD_LINE_ARG_CLIENTID]);
+ mesh_event_sock_connect(argv[CMD_LINE_ARG_IMPORTSTR]);
+ }
+
+ // Setup required signals
+
+ setup_signals();
+ signal(SIGIO, mesh_start_test_handler);
+
+ // Run peer node instance
+
+ mesh = meshlink_open("app1node2conf", argv[CMD_LINE_ARG_NODENAME],
+ "test_channel_conn", atoi(argv[CMD_LINE_ARG_DEVCLASS]));
+ assert(mesh);
+ meshlink_set_log_cb(mesh, MESHLINK_DEBUG, meshlink_callback_logger);
+ meshlink_set_channel_accept_cb(mesh, channel_accept);
+ meshlink_set_node_status_cb(mesh, node_status_cb);
+
+ if(argv[CMD_LINE_ARG_INVITEURL]) {
+ assert(meshlink_join(mesh, argv[CMD_LINE_ARG_INVITEURL]));
+ }
+
+ assert(meshlink_start(mesh));
+
+ send_event(NODE_STARTED);
+
+ // Wait for peer node to join
+
+ assert(wait_sync_flag(&peer_reachable, 15));
+ send_event(NODE_JOINED);
+
+ while(false == wait_sync_flag(&start_test, 10));
+
+ // Open a channel to peer node
+ core_node = meshlink_get_node(mesh, "corenode1");
+ assert(core_node);
+ fprintf(stderr, "\tapp1node2 Sending Channel request to corenode1 at : %lu\n", time(NULL));
+ channel = meshlink_channel_open(mesh, core_node, CHANNEL_PORT,
+ channel_receive_cb, NULL, 0);
+ meshlink_set_channel_poll_cb(mesh, channel, poll_cb);
+ assert(wait_sync_flag(&channel_opened, 15));
+ send_event(CHANNEL_OPENED);
+
+ assert(wait_sync_flag(&channel_data_recieved, 30));
+ send_event(CHANNEL_DATA_RECIEVED);
+
+ // Open a channel to peer node
+ channel_opened.flag = false;
+ channel_data_recieved.flag = false;
+
+ assert(wait_sync_flag(&app_reachable, 60));
+
+ core_node = meshlink_get_node(mesh, "app1node1");
+ assert(core_node);
+ fprintf(stderr, "\tapp1node2 Sending Channel request to app1node1 at : %lu\n", time(NULL));
+ channel = meshlink_channel_open(mesh, core_node, CHANNEL_PORT,
+ channel_receive_cb, NULL, 0);
+ meshlink_set_channel_poll_cb(mesh, channel, poll_cb);
+ assert(wait_sync_flag(&channel_opened, 100));
+ send_event(CHANNEL_OPENED);
+
+ assert(wait_sync_flag(&channel_data_recieved, 100));
+ send_event(CHANNEL_DATA_RECIEVED);
+
+ core_node = meshlink_get_node(mesh, "app2node1");
+
+ if(NULL != core_node) {
+ send_event(SIG_ABORT);
+ assert(false);
+ }
+
+ send_event(MESH_EVENT_COMPLETED);
+
+ // All test steps executed - wait for signals to stop/start or close the mesh
+
+ while(test_running) {
+ select(1, NULL, NULL, NULL, &main_loop_wait);
+ }
+
+ meshlink_close(mesh);
+
+ return EXIT_SUCCESS;
+}
\ No newline at end of file
--- /dev/null
+/*
+ node_sim_peer.c -- Implementation of Node Simulation for Meshlink Testing
+ for meta connection test case 01 - re-connection of
+ two nodes when relay node goes down
+ Copyright (C) 2018 Guus Sliepen <guus@meshlink.io>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <assert.h>
+#include <signal.h>
+#include <time.h>
+#include "../common/common_handlers.h"
+#include "../common/test_step.h"
+#include "../common/mesh_event_handler.h"
+#include "../../utils.h"
+
+#define CMD_LINE_ARG_NODENAME 1
+#define CMD_LINE_ARG_DEVCLASS 2
+#define CMD_LINE_ARG_CLIENTID 3
+#define CMD_LINE_ARG_IMPORTSTR 4
+#define CMD_LINE_ARG_INVITEURL 5
+#define CHANNEL_PORT 1234
+
+static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len);
+static bool channel_accept(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *dat, size_t len);
+
+static int client_id = -1;
+static meshlink_handle_t *mesh = NULL;
+
+static struct sync_flag peer_reachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag start_test = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag channel_opened = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag channel_data_recieved = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+
+static void send_event(mesh_event_t event) {
+ int attempts;
+
+ for(attempts = 0; attempts < 5; attempts += 1) {
+ if(mesh_event_sock_send(client_id, event, NULL, 0)) {
+ break;
+ }
+ }
+
+ assert(attempts < 5);
+
+ return;
+}
+
+static bool channel_accept(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *dat, size_t len) {
+ (void)dat;
+ (void)len;
+
+ assert(port == CHANNEL_PORT);
+
+ fprintf(stderr, "\tapp2node1 got channel request from %s\n", channel->node->name);
+
+ if(!strcmp(channel->node->name, "corenode1")) {
+ meshlink_set_channel_receive_cb(mesh, channel, channel_receive_cb);
+ mesh->priv = channel;
+
+ return true;
+ } else if(!strcmp(channel->node->name, "app2node2")) {
+ fprintf(stderr, "\tapp2node1 accepting channel request from %s at %lu\n", channel->node->name, time(NULL));
+ meshlink_set_channel_receive_cb(mesh, channel, channel_receive_cb);
+ mesh->priv = channel;
+
+ return true;
+ }
+
+ fprintf(stderr, "\tapp2node1 rejecting channel request from %s at %lu\n", channel->node->name, time(NULL));
+
+ return false;
+}
+
+/* channel receive callback */
+static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) {
+ char *message = "Channel Message";
+ char data[100] = {0};
+
+ if(len == 0) {
+ send_event(ERR_NETWORK);
+ return;
+ }
+
+ memcpy(data, dat, len);
+
+ fprintf(stderr, "\tapp2node1 got message from %s as %s\n", channel->node->name, data);
+
+ if(!strcmp(channel->node->name, "corenode1")) {
+ if(!memcmp(dat, "Channel Message", len)) {
+ set_sync_flag(&channel_data_recieved, true);
+ } else if(!memcmp(dat, "failure", 7)) {
+ assert(false);
+ }
+ } else if(!strcmp(channel->node->name, "app2node2")) {
+ if(!memcmp(dat, "Channel Message", len)) {
+ assert(meshlink_channel_send(mesh, channel, message, strlen(message)) >= 0);
+ } else if(!memcmp(dat, "failure", 7)) {
+ assert(false);
+ }
+ }
+
+ return;
+}
+
+static void poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, size_t len) {
+ char *message = "Channel Message";
+ char *node = (char *)channel->node->name;
+ (void)len;
+ meshlink_set_channel_poll_cb(mesh, channel, NULL);
+ fprintf(stderr, "\tapp2node1's Channel request has been accepted by corenode1 at : %lu\n", time(NULL));
+
+ if(0 == strcmp("corenode1", node)) {
+ set_sync_flag(&channel_opened, true);
+ }
+
+ assert(meshlink_channel_send(mesh, channel, message, strlen(message)) >= 0);
+ return;
+}
+
+
+static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node,
+ bool reachable) {
+ if(!strcasecmp(node->name, "corenode1")) {
+ if(reachable) {
+ fprintf(stderr, "\tNode corenode1 became reachable\n");
+ set_sync_flag(&peer_reachable, true);
+ }
+ }
+
+ return;
+}
+
+void mesh_start_test_handler(int a) {
+ fprintf(stderr, "Starting test in app2node1\n");
+ set_sync_flag(&start_test, true);
+}
+
+int main(int argc, char *argv[]) {
+ struct timeval main_loop_wait = { 2, 0 };
+ meshlink_channel_t *channel = NULL;
+ meshlink_node_t *core_node = NULL;
+
+ fprintf(stderr, "\tMesh node 'app2node1' starting up........\n");
+
+ // Import mesh event handler
+
+ if((argv[CMD_LINE_ARG_CLIENTID]) && (argv[CMD_LINE_ARG_IMPORTSTR])) {
+ client_id = atoi(argv[CMD_LINE_ARG_CLIENTID]);
+ mesh_event_sock_connect(argv[CMD_LINE_ARG_IMPORTSTR]);
+ }
+
+ // Setup required signals
+
+ setup_signals();
+ signal(SIGIO, mesh_start_test_handler);
+
+ // Run peer node instance
+
+ mesh = meshlink_open("app2node1conf", argv[CMD_LINE_ARG_NODENAME],
+ "test_channel_conn", atoi(argv[CMD_LINE_ARG_DEVCLASS]));
+ assert(mesh);
+ meshlink_set_log_cb(mesh, MESHLINK_DEBUG, meshlink_callback_logger);
+ meshlink_set_channel_accept_cb(mesh, channel_accept);
+ meshlink_set_node_status_cb(mesh, node_status_cb);
+
+ if(argv[CMD_LINE_ARG_INVITEURL]) {
+ assert(meshlink_join(mesh, argv[CMD_LINE_ARG_INVITEURL]));
+ }
+
+ assert(meshlink_start(mesh));
+
+ send_event(NODE_STARTED);
+
+ // Wait for peer node to join
+
+ assert(wait_sync_flag(&peer_reachable, 15));
+ send_event(NODE_JOINED);
+
+ while(false == wait_sync_flag(&start_test, 10));
+
+ // Open a channel to peer node
+ core_node = meshlink_get_node(mesh, "corenode1");
+ assert(core_node);
+ fprintf(stderr, "\tapp2node1 Sending Channel request to corenode1 at : %lu\n", time(NULL));
+ channel = meshlink_channel_open(mesh, core_node, CHANNEL_PORT,
+ channel_receive_cb, NULL, 0);
+ meshlink_set_channel_poll_cb(mesh, channel, poll_cb);
+ assert(wait_sync_flag(&channel_opened, 15));
+ send_event(CHANNEL_OPENED);
+
+ assert(wait_sync_flag(&channel_data_recieved, 30));
+ send_event(CHANNEL_DATA_RECIEVED);
+
+ // All test steps executed - wait for signals to stop/start or close the mesh
+
+ while(test_running) {
+ select(1, NULL, NULL, NULL, &main_loop_wait);
+ }
+
+ meshlink_close(mesh);
+
+ return EXIT_SUCCESS;
+}
\ No newline at end of file
--- /dev/null
+/*
+ node_sim_peer.c -- Implementation of Node Simulation for Meshlink Testing
+ for meta connection test case 01 - re-connection of
+ two nodes when relay node goes down
+ Copyright (C) 2018 Guus Sliepen <guus@meshlink.io>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <assert.h>
+#include <signal.h>
+#include <time.h>
+#include "../common/common_handlers.h"
+#include "../common/test_step.h"
+#include "../common/mesh_event_handler.h"
+#include "../../utils.h"
+
+#define CMD_LINE_ARG_NODENAME 1
+#define CMD_LINE_ARG_DEVCLASS 2
+#define CMD_LINE_ARG_CLIENTID 3
+#define CMD_LINE_ARG_IMPORTSTR 4
+#define CMD_LINE_ARG_INVITEURL 5
+#define CHANNEL_PORT 1234
+
+static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len);
+static bool channel_accept(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *dat, size_t len);
+
+static int client_id = -1;
+static meshlink_handle_t *mesh = NULL;
+
+static struct sync_flag peer_reachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag start_test = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag app_reachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag channel_opened = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag channel_data_recieved = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+
+static void send_event(mesh_event_t event) {
+ int attempts;
+
+ for(attempts = 0; attempts < 5; attempts += 1) {
+ if(mesh_event_sock_send(client_id, event, NULL, 0)) {
+ break;
+ }
+ }
+
+ assert(attempts < 5);
+
+ return;
+}
+
+static bool channel_accept(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *dat, size_t len) {
+ (void)dat;
+ (void)len;
+
+ assert(port == CHANNEL_PORT);
+
+ fprintf(stderr, "\tapp2node2 got channel request from %s\n", channel->node->name);
+
+ if(!strcmp(channel->node->name, "corenode1")) {
+ meshlink_set_channel_receive_cb(mesh, channel, channel_receive_cb);
+ mesh->priv = channel;
+
+ return true;
+ }
+
+ return false;
+}
+
+/* channel receive callback */
+static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) {
+ char data[100] = {0};
+
+ if(len == 0) {
+ fprintf(stderr, "\tapp2node2 got error from %s at %lu\n", channel->node->name, time(NULL));
+ send_event(ERR_NETWORK);
+ return;
+ }
+
+ memcpy(data, dat, len);
+
+ fprintf(stderr, "\tapp2node2 got message from %s as %s\n", channel->node->name, data);
+
+ if(!strcmp(channel->node->name, "corenode1")) {
+ if(!memcmp(dat, "Channel Message", len)) {
+ set_sync_flag(&channel_data_recieved, true);
+ } else if(!memcmp(dat, "failure", 7)) {
+ assert(false);
+ }
+ } else if(!strcmp(channel->node->name, "app2node1")) {
+ if(!memcmp(dat, "Channel Message", len)) {
+ set_sync_flag(&channel_data_recieved, true);
+ } else if(!memcmp(dat, "failure", 7)) {
+ assert(false);
+ }
+ } else {
+ assert(false);
+ }
+
+ return;
+}
+
+static void poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, size_t len) {
+ char *message = "Channel Message";
+ char *node = (char *)channel->node->name;
+ (void)len;
+ meshlink_set_channel_poll_cb(mesh, channel, NULL);
+ fprintf(stderr, "\tapp2node2's Channel request has been accepted by %s at : %lu\n", node, time(NULL));
+ set_sync_flag(&channel_opened, true);
+ assert(meshlink_channel_send(mesh, channel, message, strlen(message)) >= 0);
+ return;
+}
+
+
+static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node,
+ bool reachable) {
+ if(!strcasecmp(node->name, "corenode1")) {
+ if(reachable) {
+ fprintf(stderr, "\tNode corenode1 became reachable\n");
+ set_sync_flag(&peer_reachable, true);
+ }
+ } else if(!strcasecmp(node->name, "app2node1")) {
+ if(reachable) {
+ fprintf(stderr, "\tNode app2node1 became reachable\n");
+ set_sync_flag(&app_reachable, true);
+ }
+ }
+
+ return;
+}
+
+void mesh_start_test_handler(int a) {
+ fprintf(stderr, "Starting test in app2node2\n");
+ set_sync_flag(&start_test, true);
+}
+
+int main(int argc, char *argv[]) {
+ struct timeval main_loop_wait = { 2, 0 };
+ meshlink_channel_t *channel = NULL;
+ meshlink_node_t *core_node = NULL;
+
+ fprintf(stderr, "\tMesh node 'app2node2' starting up........\n");
+
+ // Import mesh event handler
+
+ if((argv[CMD_LINE_ARG_CLIENTID]) && (argv[CMD_LINE_ARG_IMPORTSTR])) {
+ client_id = atoi(argv[CMD_LINE_ARG_CLIENTID]);
+ mesh_event_sock_connect(argv[CMD_LINE_ARG_IMPORTSTR]);
+ }
+
+ // Setup required signals
+
+ setup_signals();
+ signal(SIGIO, mesh_start_test_handler);
+
+ // Run peer node instance
+
+ mesh = meshlink_open("app2node2conf", argv[CMD_LINE_ARG_NODENAME],
+ "test_channel_conn", atoi(argv[CMD_LINE_ARG_DEVCLASS]));
+ assert(mesh);
+ meshlink_set_log_cb(mesh, MESHLINK_DEBUG, meshlink_callback_logger);
+ meshlink_set_channel_accept_cb(mesh, channel_accept);
+ meshlink_set_node_status_cb(mesh, node_status_cb);
+
+ if(argv[CMD_LINE_ARG_INVITEURL]) {
+ assert(meshlink_join(mesh, argv[CMD_LINE_ARG_INVITEURL]));
+ }
+
+ assert(meshlink_start(mesh));
+
+ send_event(NODE_STARTED);
+
+ // Wait for peer node to join
+
+ assert(wait_sync_flag(&peer_reachable, 15));
+ send_event(NODE_JOINED);
+
+ while(false == wait_sync_flag(&start_test, 10));
+
+ // Open a channel to peer node
+ core_node = meshlink_get_node(mesh, "corenode1");
+ assert(core_node);
+ fprintf(stderr, "\tapp2node2 Sending Channel request to corenode1 at : %lu\n", time(NULL));
+ channel = meshlink_channel_open(mesh, core_node, CHANNEL_PORT,
+ channel_receive_cb, NULL, 0);
+ meshlink_set_channel_poll_cb(mesh, channel, poll_cb);
+ assert(wait_sync_flag(&channel_opened, 30));
+ send_event(CHANNEL_OPENED);
+
+ assert(wait_sync_flag(&channel_data_recieved, 30));
+ send_event(CHANNEL_DATA_RECIEVED);
+
+ // Open a channel to peer node
+ channel_opened.flag = false;
+ channel_data_recieved.flag = false;
+
+ assert(wait_sync_flag(&app_reachable, 60));
+
+ core_node = meshlink_get_node(mesh, "app2node1");
+ assert(core_node);
+ fprintf(stderr, "\tapp2node2 Sending Channel request to app2node1 at : %lu\n", time(NULL));
+ channel = meshlink_channel_open(mesh, core_node, CHANNEL_PORT,
+ channel_receive_cb, NULL, 0);
+ meshlink_set_channel_poll_cb(mesh, channel, poll_cb);
+ assert(wait_sync_flag(&channel_opened, 30));
+ send_event(CHANNEL_OPENED);
+
+ assert(wait_sync_flag(&channel_data_recieved, 30));
+ send_event(CHANNEL_DATA_RECIEVED);
+
+ core_node = meshlink_get_node(mesh, "app1node1");
+
+ if(NULL != core_node) {
+ send_event(SIG_ABORT);
+ assert(false);
+ }
+
+ send_event(MESH_EVENT_COMPLETED);
+
+ // All test steps executed - wait for signals to stop/start or close the mesh
+
+ while(test_running) {
+ select(1, NULL, NULL, NULL, &main_loop_wait);
+ }
+
+ meshlink_close(mesh);
+
+ return EXIT_SUCCESS;
+}
\ No newline at end of file
--- /dev/null
+/*
+ node_sim.c -- Implementation of Node Simulation for Meshlink Testing
+ for meta connection test case 01 - re-connection of
+ two nodes when relay node goes down
+ Copyright (C) 2018 Guus Sliepen <guus@meshlink.io>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <signal.h>
+#include "../common/common_handlers.h"
+#include "../common/test_step.h"
+#include "../common/mesh_event_handler.h"
+#include "../../utils.h"
+
+#define CMD_LINE_ARG_NODENAME 1
+#define CMD_LINE_ARG_DEVCLASS 2
+#define CMD_LINE_ARG_CLIENTID 3
+#define CMD_LINE_ARG_IMPORTSTR 4
+#define CMD_LINE_ARG_INVITEURL 5
+#define CHANNEL_PORT 1234
+
+static bool conn_status = false;
+static int client_id = -1;
+
+static struct sync_flag peer_reachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag channel_opened = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag channel_data_recieved = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+
+static meshlink_handle_t *mesh = NULL;
+
+static void mesh_send_message_handler(char *destination);
+
+static void send_event(mesh_event_t event) {
+ int attempts;
+
+ for(attempts = 0; attempts < 5; attempts += 1) {
+ if(mesh_event_sock_send(client_id, event, NULL, 0)) {
+ break;
+ }
+ }
+
+ assert(attempts < 5);
+
+ return;
+}
+
+/* channel receive callback */
+static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) {
+ char data[100] = {0};
+
+ if(len == 0) {
+ send_event(ERR_NETWORK);
+ return;
+ }
+
+ memcpy(data, dat, len);
+
+ fprintf(stderr, "corenode1 got message from %s as %s\n", channel->node->name, data);
+
+ if(!memcmp(dat, "Channel Message", len)) {
+ mesh_send_message_handler(channel->node->name);
+
+ if(0 == strcmp("corenode2", channel->node->name)) {
+ set_sync_flag(&channel_data_recieved, true);
+ }
+ } else if(!memcmp(dat, "failure", 7)) {
+ assert(false);
+ }
+
+ return;
+}
+
+static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node,
+ bool reachable) {
+ if(reachable) {
+ fprintf(stderr, "Node %s became reachable\n", node->name);
+ } else {
+ fprintf(stderr, "Node %s is unreachable\n", node->name);
+ }
+
+ return;
+}
+
+static void poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, size_t len) {
+ char *message = "Channel Message";
+ char *node = channel->node->name;
+ (void)len;
+ meshlink_set_channel_poll_cb(mesh, channel, NULL);
+ fprintf(stderr, "corenode1's Channel request has been accepted by %s at : %lu\n", node, time(NULL));
+
+ if(0 == strcmp("corenode2", node)) {
+ set_sync_flag(&channel_opened, true);
+ }
+
+ assert(meshlink_channel_send(mesh, channel, message, strlen(message)) >= 0);
+ return;
+}
+
+/* channel receive callback */
+static bool channel_accept(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *dat, size_t len) {
+ (void)dat;
+ (void)len;
+
+ assert(port == CHANNEL_PORT);
+
+ fprintf(stderr, "corenode1 got channel request from %s\n", channel->node->name);
+ meshlink_set_channel_receive_cb(mesh, channel, channel_receive_cb);
+
+ return true;
+}
+
+void mesh_send_message_handler(char *destination) {
+ meshlink_channel_t *channel = NULL;
+ meshlink_node_t *target_node = NULL;
+
+ // Open a channel to destination node
+ target_node = meshlink_get_node(mesh, destination);
+ assert(target_node);
+ fprintf(stderr, "corenode1 Sending Channel request to %s at : %lu\n", destination, time(NULL));
+ channel = meshlink_channel_open(mesh, target_node, CHANNEL_PORT,
+ channel_receive_cb, NULL, 0);
+ meshlink_set_channel_poll_cb(mesh, channel, poll_cb);
+}
+
+int main(int argc, char *argv[]) {
+ struct timeval main_loop_wait = { 5, 0 };
+ int i;
+
+ // Import mesh event handler
+
+ fprintf(stderr, "Mesh node 'corenode1' starting up........\n");
+
+ if((argv[CMD_LINE_ARG_CLIENTID]) && (argv[CMD_LINE_ARG_IMPORTSTR])) {
+ client_id = atoi(argv[CMD_LINE_ARG_CLIENTID]);
+ mesh_event_sock_connect(argv[CMD_LINE_ARG_IMPORTSTR]);
+ }
+
+ setup_signals();
+
+ // Execute test steps
+
+ mesh = meshlink_open("testconf", argv[CMD_LINE_ARG_NODENAME],
+ "test_channel_conn", atoi(argv[CMD_LINE_ARG_DEVCLASS]));
+ assert(mesh);
+ meshlink_set_log_cb(mesh, MESHLINK_DEBUG, meshlink_callback_logger);
+ meshlink_set_channel_accept_cb(mesh, channel_accept);
+ meshlink_set_node_status_cb(mesh, node_status_cb);
+
+ if(argv[CMD_LINE_ARG_INVITEURL]) {
+ assert(meshlink_join(mesh, argv[CMD_LINE_ARG_INVITEURL]));
+ }
+
+ assert(meshlink_start(mesh));
+
+ send_event(NODE_STARTED);
+
+ assert(wait_sync_flag(&channel_opened, 10));
+ send_event(CHANNEL_OPENED);
+
+ assert(wait_sync_flag(&channel_data_recieved, 10));
+ send_event(CHANNEL_DATA_RECIEVED);
+
+ // All test steps executed - wait for signals to stop/start or close the mesh
+
+ while(test_running) {
+ select(1, NULL, NULL, NULL, &main_loop_wait);
+ }
+
+ meshlink_close(mesh);
+
+ return 0;
+}
--- /dev/null
+/*
+ node_sim_peer.c -- Implementation of Node Simulation for Meshlink Testing
+ for meta connection test case 01 - re-connection of
+ two nodes when relay node goes down
+ Copyright (C) 2018 Guus Sliepen <guus@meshlink.io>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <assert.h>
+#include <signal.h>
+#include <time.h>
+#include "../common/common_handlers.h"
+#include "../common/test_step.h"
+#include "../common/mesh_event_handler.h"
+#include "../../utils.h"
+
+#define CMD_LINE_ARG_NODENAME 1
+#define CMD_LINE_ARG_DEVCLASS 2
+#define CMD_LINE_ARG_CLIENTID 3
+#define CMD_LINE_ARG_IMPORTSTR 4
+#define CMD_LINE_ARG_INVITEURL 5
+#define CHANNEL_PORT 1234
+
+static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len);
+static bool channel_accept(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *dat, size_t len);
+
+static int client_id = -1;
+static meshlink_handle_t *mesh = NULL;
+
+static struct sync_flag peer_reachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag start_test = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag channel_opened = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag channel_data_recieved = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+
+static void send_event(mesh_event_t event) {
+ int attempts;
+
+ for(attempts = 0; attempts < 5; attempts += 1) {
+ if(mesh_event_sock_send(client_id, event, NULL, 0)) {
+ break;
+ }
+ }
+
+ assert(attempts < 5);
+
+ return;
+}
+
+static bool channel_accept(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *dat, size_t len) {
+ (void)dat;
+ (void)len;
+
+ assert(port == CHANNEL_PORT);
+
+ fprintf(stderr, "corenode2 got channel request from %s", channel->node->name);
+
+ if(!strcmp(channel->node->name, "corenode1")) {
+ meshlink_set_channel_receive_cb(mesh, channel, channel_receive_cb);
+ mesh->priv = channel;
+
+ return true;
+ }
+
+ return false;
+}
+
+/* channel receive callback */
+static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) {
+ char data[100] = {0};
+
+ if(len == 0) {
+ send_event(ERR_NETWORK);
+ return;
+ }
+
+ memcpy(data, dat, len);
+
+ fprintf(stderr, "corenode2 got message from %s as %s", channel->node->name, data);
+
+ if(!strcmp(channel->node->name, "corenode1")) {
+ if(!memcmp(dat, "Channel Message", len)) {
+ set_sync_flag(&channel_data_recieved, true);
+ } else if(!memcmp(dat, "failure", 7)) {
+ assert(false);
+ }
+ }
+
+ return;
+}
+
+static void poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, size_t len) {
+ char *message = "Channel Message";
+ (void)len;
+ meshlink_set_channel_poll_cb(mesh, channel, NULL);
+ fprintf(stderr, "corenode2's Channel request has been accepted by corenode1 at : %lu", time(NULL));
+ set_sync_flag(&channel_opened, true);
+ assert(meshlink_channel_send(mesh, channel, message, strlen(message)) >= 0);
+ return;
+}
+
+
+static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node,
+ bool reachable) {
+ if(!strcasecmp(node->name, "corenode1")) {
+ if(reachable) {
+ fprintf(stderr, "Node corenode2 became reachable");
+ set_sync_flag(&peer_reachable, true);
+ }
+ }
+
+ return;
+}
+
+void mesh_start_test_handler(int a) {
+ fprintf(stderr, "Starting test in corenode2\n");
+ set_sync_flag(&start_test, true);
+}
+
+int main(int argc, char *argv[]) {
+ struct timeval main_loop_wait = { 2, 0 };
+ meshlink_channel_t *channel = NULL;
+ meshlink_node_t *core_node = NULL;
+
+ fprintf(stderr, "Mesh node 'corenode2' starting up........\n");
+
+ // Import mesh event handler
+
+ if((argv[CMD_LINE_ARG_CLIENTID]) && (argv[CMD_LINE_ARG_IMPORTSTR])) {
+ client_id = atoi(argv[CMD_LINE_ARG_CLIENTID]);
+ mesh_event_sock_connect(argv[CMD_LINE_ARG_IMPORTSTR]);
+ }
+
+ // Setup required signals
+
+ setup_signals();
+ signal(SIGIO, mesh_start_test_handler);
+
+ // Run peer node instance
+
+ mesh = meshlink_open("corenode1conf", argv[CMD_LINE_ARG_NODENAME],
+ "test_channel_conn", atoi(argv[CMD_LINE_ARG_DEVCLASS]));
+ assert(mesh);
+ meshlink_set_log_cb(mesh, MESHLINK_DEBUG, meshlink_callback_logger);
+ meshlink_set_channel_accept_cb(mesh, channel_accept);
+ meshlink_set_node_status_cb(mesh, node_status_cb);
+
+ if(argv[CMD_LINE_ARG_INVITEURL]) {
+ assert(meshlink_join(mesh, argv[CMD_LINE_ARG_INVITEURL]));
+ }
+
+ assert(meshlink_start(mesh));
+
+ send_event(NODE_STARTED);
+
+ // Wait for peer node to join
+
+ assert(wait_sync_flag(&peer_reachable, 15));
+ send_event(NODE_JOINED);
+
+ while(false == wait_sync_flag(&start_test, 10));
+
+ // Open a channel to peer node
+ core_node = meshlink_get_node(mesh, "corenode1");
+ assert(core_node);
+ fprintf(stderr, "corenode2 Sending Channel request to corenode1 at : %lu", time(NULL));
+ channel = meshlink_channel_open(mesh, core_node, CHANNEL_PORT,
+ channel_receive_cb, NULL, 0);
+ meshlink_set_channel_poll_cb(mesh, channel, poll_cb);
+ assert(wait_sync_flag(&channel_opened, 15));
+ send_event(CHANNEL_OPENED);
+
+ assert(wait_sync_flag(&channel_data_recieved, 10));
+ send_event(CHANNEL_DATA_RECIEVED);
+
+ // All test steps executed - wait for signals to stop/start or close the mesh
+
+ while(test_running) {
+ select(1, NULL, NULL, NULL, &main_loop_wait);
+ }
+
+ meshlink_close(mesh);
+
+ return EXIT_SUCCESS;
+}
\ No newline at end of file
--- /dev/null
+check_PROGRAMS = node_sim_corenode1 node_sim_corenode2 node_sim_app1node1 node_sim_app1node2 node_sim_app2node1 node_sim_app2node2
+
+node_sim_corenode1_SOURCES = node_sim_corenode1.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c
+node_sim_corenode1_LDADD = ../../../src/libmeshlink.la
+node_sim_corenode1_CFLAGS = -D_GNU_SOURCE
+
+node_sim_corenode2_SOURCES = node_sim_corenode2.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c
+node_sim_corenode2_LDADD = ../../../src/libmeshlink.la
+node_sim_corenode2_CFLAGS = -D_GNU_SOURCE
+
+node_sim_app1node1_SOURCES = node_sim_app1node1.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c
+node_sim_app1node1_LDADD = ../../../src/libmeshlink.la
+node_sim_app1node1_CFLAGS = -D_GNU_SOURCE
+
+node_sim_app1node2_SOURCES = node_sim_app1node2.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c
+node_sim_app1node2_LDADD = ../../../src/libmeshlink.la
+node_sim_app1node2_CFLAGS = -D_GNU_SOURCE
+
+node_sim_app2node1_SOURCES = node_sim_app2node1.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c
+node_sim_app2node1_LDADD = ../../../src/libmeshlink.la
+node_sim_app2node1_CFLAGS = -D_GNU_SOURCE
+
+node_sim_app2node2_SOURCES = node_sim_app2node2.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c
+node_sim_app2node2_LDADD = ../../../src/libmeshlink.la
+node_sim_app2node2_CFLAGS = -D_GNU_SOURCE
--- /dev/null
+/*
+ node_sim_peer.c -- Implementation of Node Simulation for Meshlink Testing
+ for meta connection test case 01 - re-connection of
+ two nodes when relay node goes down
+ Copyright (C) 2018 Guus Sliepen <guus@meshlink.io>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <assert.h>
+#include <signal.h>
+#include <time.h>
+#include "../common/common_handlers.h"
+#include "../common/test_step.h"
+#include "../common/mesh_event_handler.h"
+#include "../../utils.h"
+
+#define CMD_LINE_ARG_NODENAME 1
+#define CMD_LINE_ARG_DEVCLASS 2
+#define CMD_LINE_ARG_CLIENTID 3
+#define CMD_LINE_ARG_IMPORTSTR 4
+#define CMD_LINE_ARG_INVITEURL 5
+#define CHANNEL_PORT 1234
+
+static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len);
+static bool channel_accept(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *dat, size_t len);
+
+static int client_id = -1;
+static meshlink_handle_t *mesh = NULL;
+
+static struct sync_flag peer_reachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag start_test = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag channel_opened = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag channel_data_recieved = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+
+static void send_event(mesh_event_t event) {
+ int attempts;
+
+ for(attempts = 0; attempts < 5; attempts += 1) {
+ if(mesh_event_sock_send(client_id, event, NULL, 0)) {
+ break;
+ }
+ }
+
+ assert(attempts < 5);
+
+ return;
+}
+
+static bool channel_accept(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *dat, size_t len) {
+ (void)dat;
+ (void)len;
+
+ assert(port == CHANNEL_PORT);
+
+ fprintf(stderr, "\tapp1node1 got channel request from %s\n", channel->node->name);
+
+ if(!strcmp(channel->node->name, "corenode1")) {
+ fprintf(stderr, "\tapp1node1 accepting channel request from %s at %lu\n", channel->node->name, time(NULL));
+ meshlink_set_channel_receive_cb(mesh, channel, channel_receive_cb);
+ mesh->priv = channel;
+
+ return true;
+ } else if(!strcmp(channel->node->name, "app1node2")) {
+ fprintf(stderr, "\tapp1node1 accepting channel request from %s at %lu\n", channel->node->name, time(NULL));
+ meshlink_set_channel_receive_cb(mesh, channel, channel_receive_cb);
+ mesh->priv = channel;
+
+ return true;
+ }
+
+ fprintf(stderr, "\tapp1node1 rejecting channel request from %s at %lu\n", channel->node->name, time(NULL));
+ return false;
+}
+
+/* channel receive callback */
+static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) {
+ char data[100] = {0};
+ char *message = "Channel Message";
+
+ if(len == 0) {
+ fprintf(stderr, "\tapp1node1 got error from %s at %lu\n", channel->node->name, time(NULL));
+ send_event(ERR_NETWORK);
+ return;
+ }
+
+ memcpy(data, dat, len);
+
+ fprintf(stderr, "\tapp1node1 got message from %s as %s\n", channel->node->name, data);
+
+ if(!strcmp(channel->node->name, "corenode1")) {
+ if(!memcmp(dat, "Channel Message", len)) {
+ set_sync_flag(&channel_data_recieved, true);
+ } else if(!memcmp(dat, "failure", 7)) {
+ assert(false);
+ }
+ } else if(!strcmp(channel->node->name, "app1node2")) {
+ if(!memcmp(dat, "Channel Message", len)) {
+ assert(meshlink_channel_send(mesh, channel, message, strlen(message)) >= 0);
+ } else if(!memcmp(dat, "failure", 7)) {
+ assert(false);
+ }
+ }
+
+ return;
+}
+
+static void poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, size_t len) {
+ char *message = "Channel Message";
+ char *node = (char *)channel->node->name;
+ (void)len;
+ meshlink_set_channel_poll_cb(mesh, channel, NULL);
+ fprintf(stderr, "\tapp1node1's Channel request has been accepted by %s at : %lu\n", node, time(NULL));
+
+ if(0 == strcmp("corenode1", node)) {
+ set_sync_flag(&channel_opened, true);
+ }
+
+ assert(meshlink_channel_send(mesh, channel, message, strlen(message)) >= 0);
+ return;
+}
+
+
+static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node,
+ bool reachable) {
+ if(!strcasecmp(node->name, "corenode1")) {
+ if(reachable) {
+ fprintf(stderr, "\tNode corenode1 became reachable\n");
+ set_sync_flag(&peer_reachable, true);
+ }
+ }
+
+ return;
+}
+
+void mesh_start_test_handler(int a) {
+ fprintf(stderr, "Starting test in app1node1\n");
+ set_sync_flag(&start_test, true);
+}
+
+int main(int argc, char *argv[]) {
+ struct timeval main_loop_wait = { 2, 0 };
+ meshlink_channel_t *channel = NULL;
+ meshlink_node_t *core_node = NULL;
+
+ fprintf(stderr, "\tMesh node 'app1node1' starting up........\n");
+
+ // Import mesh event handler
+
+ if((argv[CMD_LINE_ARG_CLIENTID]) && (argv[CMD_LINE_ARG_IMPORTSTR])) {
+ client_id = atoi(argv[CMD_LINE_ARG_CLIENTID]);
+ mesh_event_sock_connect(argv[CMD_LINE_ARG_IMPORTSTR]);
+ }
+
+ // Setup required signals
+
+ setup_signals();
+ signal(SIGIO, mesh_start_test_handler);
+
+ // Run peer node instance
+
+ mesh = meshlink_open("app1node1conf", argv[CMD_LINE_ARG_NODENAME],
+ "test_channel_conn", atoi(argv[CMD_LINE_ARG_DEVCLASS]));
+ assert(mesh);
+ meshlink_set_log_cb(mesh, MESHLINK_DEBUG, meshlink_callback_logger);
+ meshlink_set_channel_accept_cb(mesh, channel_accept);
+ meshlink_set_node_status_cb(mesh, node_status_cb);
+
+ if(argv[CMD_LINE_ARG_INVITEURL]) {
+ assert(meshlink_join(mesh, argv[CMD_LINE_ARG_INVITEURL]));
+ }
+
+ assert(meshlink_start(mesh));
+
+ send_event(NODE_STARTED);
+
+ // Wait for peer node to join
+
+ assert(wait_sync_flag(&peer_reachable, 15));
+ send_event(NODE_JOINED);
+
+ while(false == wait_sync_flag(&start_test, 10));
+
+ // Open a channel to peer node
+ core_node = meshlink_get_node(mesh, "corenode1");
+ assert(core_node);
+ fprintf(stderr, "\tapp1node1 Sending Channel request to corenode1 at : %lu\n", time(NULL));
+ channel = meshlink_channel_open(mesh, core_node, CHANNEL_PORT,
+ channel_receive_cb, NULL, 0);
+ meshlink_set_channel_poll_cb(mesh, channel, poll_cb);
+ assert(wait_sync_flag(&channel_opened, 15));
+ send_event(CHANNEL_OPENED);
+
+ assert(wait_sync_flag(&channel_data_recieved, 30));
+ send_event(CHANNEL_DATA_RECIEVED);
+
+ // All test steps executed - wait for signals to stop/start or close the mesh
+
+ while(test_running) {
+ select(1, NULL, NULL, NULL, &main_loop_wait);
+ }
+
+ meshlink_close(mesh);
+
+ return EXIT_SUCCESS;
+}
\ No newline at end of file
--- /dev/null
+/*
+ node_sim_peer.c -- Implementation of Node Simulation for Meshlink Testing
+ for meta connection test case 01 - re-connection of
+ two nodes when relay node goes down
+ Copyright (C) 2018 Guus Sliepen <guus@meshlink.io>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <assert.h>
+#include <signal.h>
+#include <time.h>
+#include "../common/common_handlers.h"
+#include "../common/test_step.h"
+#include "../common/mesh_event_handler.h"
+#include "../../utils.h"
+
+#define CMD_LINE_ARG_NODENAME 1
+#define CMD_LINE_ARG_DEVCLASS 2
+#define CMD_LINE_ARG_CLIENTID 3
+#define CMD_LINE_ARG_IMPORTSTR 4
+#define CMD_LINE_ARG_INVITEURL 5
+#define CHANNEL_PORT 1234
+
+static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len);
+static bool channel_accept(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *dat, size_t len);
+
+static int client_id = -1;
+static meshlink_handle_t *mesh = NULL;
+
+static struct sync_flag peer_reachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag start_test = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag app_reachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag channel_opened = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag channel_data_recieved = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+
+static void send_event(mesh_event_t event) {
+ int attempts;
+
+ for(attempts = 0; attempts < 5; attempts += 1) {
+ if(mesh_event_sock_send(client_id, event, NULL, 0)) {
+ break;
+ }
+ }
+
+ assert(attempts < 5);
+
+ return;
+}
+
+static bool channel_accept(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *dat, size_t len) {
+ (void)dat;
+ (void)len;
+
+ assert(port == CHANNEL_PORT);
+
+ fprintf(stderr, "\tapp1node2 got channel request from %s\n", channel->node->name);
+
+ if(!strcmp(channel->node->name, "corenode1")) {
+ meshlink_set_channel_receive_cb(mesh, channel, channel_receive_cb);
+ mesh->priv = channel;
+
+ return true;
+ }
+
+ return false;
+}
+
+/* channel receive callback */
+static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) {
+ char data[100] = {0};
+
+ if(len == 0) {
+ fprintf(stderr, "\tapp1node2 got error from %s at %lu\n", channel->node->name, time(NULL));
+ send_event(ERR_NETWORK);
+ return;
+ }
+
+ memcpy(data, dat, len);
+
+ fprintf(stderr, "\tapp1node2 got message from %s as %s\n", channel->node->name, data);
+
+ if(!strcmp(channel->node->name, "corenode1")) {
+ if(!memcmp(dat, "Channel Message", len)) {
+ set_sync_flag(&channel_data_recieved, true);
+ } else if(!memcmp(dat, "failure", 7)) {
+ assert(false);
+ }
+ } else if(!strcmp(channel->node->name, "app1node1")) {
+ if(!memcmp(dat, "Channel Message", len)) {
+ set_sync_flag(&channel_data_recieved, true);
+ } else if(!memcmp(dat, "failure", 7)) {
+ assert(false);
+ }
+ } else {
+ assert(false);
+ }
+
+ return;
+}
+
+static void poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, size_t len) {
+ char *message = "Channel Message";
+ char *node = (char *)channel->node->name;
+ (void)len;
+ meshlink_set_channel_poll_cb(mesh, channel, NULL);
+ fprintf(stderr, "\tapp1node2's Channel request has been accepted by %s at : %lu\n", node, time(NULL));
+ set_sync_flag(&channel_opened, true);
+ assert(meshlink_channel_send(mesh, channel, message, strlen(message)) >= 0);
+ return;
+}
+
+
+static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node,
+ bool reachable) {
+ if(!strcasecmp(node->name, "corenode1")) {
+ if(reachable) {
+ fprintf(stderr, "\tNode corenode1 became reachable\n");
+ set_sync_flag(&peer_reachable, true);
+ }
+ } else if(!strcasecmp(node->name, "app1node1")) {
+ if(reachable) {
+ fprintf(stderr, "\tNode app1node1 became reachable\n");
+ set_sync_flag(&app_reachable, true);
+ }
+ }
+
+ return;
+}
+
+void mesh_start_test_handler(int a) {
+ fprintf(stderr, "Starting test in app1node2\n");
+ set_sync_flag(&start_test, true);
+}
+
+int main(int argc, char *argv[]) {
+ size_t num_nodes, i;
+ struct timeval main_loop_wait = { 2, 0 };
+ meshlink_channel_t *channel = NULL;
+ meshlink_node_t *core_node = NULL;
+ meshlink_node_t **node_handles = NULL;
+
+ fprintf(stderr, "\tMesh node 'app1node2' starting up........\n");
+
+ // Import mesh event handler
+
+ if((argv[CMD_LINE_ARG_CLIENTID]) && (argv[CMD_LINE_ARG_IMPORTSTR])) {
+ client_id = atoi(argv[CMD_LINE_ARG_CLIENTID]);
+ mesh_event_sock_connect(argv[CMD_LINE_ARG_IMPORTSTR]);
+ }
+
+ // Setup required signals
+
+ setup_signals();
+ signal(SIGIO, mesh_start_test_handler);
+
+ // Run peer node instance
+
+ mesh = meshlink_open("app1node2conf", argv[CMD_LINE_ARG_NODENAME],
+ "test_channel_conn", atoi(argv[CMD_LINE_ARG_DEVCLASS]));
+ assert(mesh);
+ meshlink_set_log_cb(mesh, MESHLINK_DEBUG, meshlink_callback_logger);
+ meshlink_set_channel_accept_cb(mesh, channel_accept);
+ meshlink_set_node_status_cb(mesh, node_status_cb);
+
+ if(argv[CMD_LINE_ARG_INVITEURL]) {
+ assert(meshlink_join(mesh, argv[CMD_LINE_ARG_INVITEURL]));
+ }
+
+ assert(meshlink_start(mesh));
+
+ send_event(NODE_STARTED);
+
+ // Wait for peer node to join
+
+ assert(wait_sync_flag(&peer_reachable, 15));
+ send_event(NODE_JOINED);
+
+ while(false == wait_sync_flag(&start_test, 10));
+
+ // Open a channel to peer node
+ core_node = meshlink_get_node(mesh, "corenode1");
+ assert(core_node);
+ fprintf(stderr, "\tapp1node2 Sending Channel request to corenode1 at : %lu\n", time(NULL));
+ channel = meshlink_channel_open(mesh, core_node, CHANNEL_PORT,
+ channel_receive_cb, NULL, 0);
+ meshlink_set_channel_poll_cb(mesh, channel, poll_cb);
+ assert(wait_sync_flag(&channel_opened, 15));
+ send_event(CHANNEL_OPENED);
+
+ assert(wait_sync_flag(&channel_data_recieved, 30));
+ send_event(CHANNEL_DATA_RECIEVED);
+
+ // Open a channel to peer node
+ channel_opened.flag = false;
+ channel_data_recieved.flag = false;
+
+ assert(wait_sync_flag(&app_reachable, 60));
+
+ core_node = meshlink_get_node(mesh, "app1node1");
+ assert(core_node);
+ fprintf(stderr, "\tapp1node2 Sending Channel request to app1node1 at : %lu\n", time(NULL));
+ channel = meshlink_channel_open(mesh, core_node, CHANNEL_PORT,
+ channel_receive_cb, NULL, 0);
+ meshlink_set_channel_poll_cb(mesh, channel, poll_cb);
+ assert(wait_sync_flag(&channel_opened, 30));
+ send_event(CHANNEL_OPENED);
+
+ assert(wait_sync_flag(&channel_data_recieved, 30));
+ send_event(CHANNEL_DATA_RECIEVED);
+
+ num_nodes = 0;
+ node_handles = meshlink_get_all_nodes(mesh, NULL, &num_nodes);
+ fprintf(stderr, "\tGot %d nodes in list with error : %s\n", num_nodes, meshlink_strerror(meshlink_errno));
+ assert(node_handles);
+ assert((num_nodes == 4));
+
+ for(i = 0; i < num_nodes; i++) {
+ fprintf(stderr, "\tChecking the node : %s\n", node_handles[i]->name);
+
+ if((0 == strcmp(node_handles[i]->name, "app2node1")) || (0 == strcmp(node_handles[i]->name, "app2node2"))) {
+ send_event(SIG_ABORT);
+ assert(false);
+ }
+ }
+
+ meshlink_node_t *node = meshlink_get_self(mesh);
+ assert(node);
+ meshlink_submesh_t *submesh = meshlink_get_node_submesh(mesh, node);
+ assert(submesh);
+
+ node_handles = meshlink_get_all_nodes_by_submesh(mesh, submesh, node_handles, &num_nodes);
+ assert(node_handles);
+ assert((num_nodes == 2));
+
+ for(i = 0; i < num_nodes; i++) {
+ fprintf(stderr, "\tChecking the node : %s\n", node_handles[i]->name);
+
+ if((0 == strcmp(node_handles[i]->name, "app2node1")) || (0 == strcmp(node_handles[i]->name, "app2node2"))) {
+ send_event(SIG_ABORT);
+ assert(false);
+ }
+ }
+
+ send_event(MESH_EVENT_COMPLETED);
+
+ // All test steps executed - wait for signals to stop/start or close the mesh
+
+ while(test_running) {
+ select(1, NULL, NULL, NULL, &main_loop_wait);
+ }
+
+ meshlink_close(mesh);
+
+ return EXIT_SUCCESS;
+}
\ No newline at end of file
--- /dev/null
+/*
+ node_sim_peer.c -- Implementation of Node Simulation for Meshlink Testing
+ for meta connection test case 01 - re-connection of
+ two nodes when relay node goes down
+ Copyright (C) 2018 Guus Sliepen <guus@meshlink.io>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <assert.h>
+#include <signal.h>
+#include <time.h>
+#include "../common/common_handlers.h"
+#include "../common/test_step.h"
+#include "../common/mesh_event_handler.h"
+#include "../../utils.h"
+
+#define CMD_LINE_ARG_NODENAME 1
+#define CMD_LINE_ARG_DEVCLASS 2
+#define CMD_LINE_ARG_CLIENTID 3
+#define CMD_LINE_ARG_IMPORTSTR 4
+#define CMD_LINE_ARG_INVITEURL 5
+#define CHANNEL_PORT 1234
+
+static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len);
+static bool channel_accept(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *dat, size_t len);
+
+static int client_id = -1;
+static meshlink_handle_t *mesh = NULL;
+
+static struct sync_flag peer_reachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag start_test = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag channel_opened = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag channel_data_recieved = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+
+static void send_event(mesh_event_t event) {
+ int attempts;
+
+ for(attempts = 0; attempts < 5; attempts += 1) {
+ if(mesh_event_sock_send(client_id, event, NULL, 0)) {
+ break;
+ }
+ }
+
+ assert(attempts < 5);
+
+ return;
+}
+
+static bool channel_accept(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *dat, size_t len) {
+ (void)dat;
+ (void)len;
+
+ assert(port == CHANNEL_PORT);
+
+ fprintf(stderr, "\tapp2node1 got channel request from %s\n", channel->node->name);
+
+ if(!strcmp(channel->node->name, "corenode1")) {
+ meshlink_set_channel_receive_cb(mesh, channel, channel_receive_cb);
+ mesh->priv = channel;
+
+ return true;
+ } else if(!strcmp(channel->node->name, "app2node2")) {
+ fprintf(stderr, "\tapp2node1 accepting channel request from %s at %lu\n", channel->node->name, time(NULL));
+ meshlink_set_channel_receive_cb(mesh, channel, channel_receive_cb);
+ mesh->priv = channel;
+
+ return true;
+ }
+
+ fprintf(stderr, "\tapp2node1 rejecting channel request from %s at %lu\n", channel->node->name, time(NULL));
+
+ return false;
+}
+
+/* channel receive callback */
+static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) {
+ char *message = "Channel Message";
+ char data[100] = {0};
+
+ if(len == 0) {
+ send_event(ERR_NETWORK);
+ return;
+ }
+
+ memcpy(data, dat, len);
+
+ fprintf(stderr, "\tapp2node1 got message from %s as %s\n", channel->node->name, data);
+
+ if(!strcmp(channel->node->name, "corenode1")) {
+ if(!memcmp(dat, "Channel Message", len)) {
+ set_sync_flag(&channel_data_recieved, true);
+ } else if(!memcmp(dat, "failure", 7)) {
+ assert(false);
+ }
+ } else if(!strcmp(channel->node->name, "app2node2")) {
+ if(!memcmp(dat, "Channel Message", len)) {
+ assert(meshlink_channel_send(mesh, channel, message, strlen(message)) >= 0);
+ } else if(!memcmp(dat, "failure", 7)) {
+ assert(false);
+ }
+ }
+
+ return;
+}
+
+static void poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, size_t len) {
+ char *message = "Channel Message";
+ char *node = (char *)channel->node->name;
+ (void)len;
+ meshlink_set_channel_poll_cb(mesh, channel, NULL);
+ fprintf(stderr, "\tapp2node1's Channel request has been accepted by corenode1 at : %lu\n", time(NULL));
+
+ if(0 == strcmp("corenode1", node)) {
+ set_sync_flag(&channel_opened, true);
+ }
+
+ assert(meshlink_channel_send(mesh, channel, message, strlen(message)) >= 0);
+ return;
+}
+
+
+static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node,
+ bool reachable) {
+ if(!strcasecmp(node->name, "corenode1")) {
+ if(reachable) {
+ fprintf(stderr, "\tNode corenode1 became reachable\n");
+ set_sync_flag(&peer_reachable, true);
+ }
+ }
+
+ return;
+}
+
+void mesh_start_test_handler(int a) {
+ fprintf(stderr, "Starting test in app2node1\n");
+ set_sync_flag(&start_test, true);
+}
+
+int main(int argc, char *argv[]) {
+ struct timeval main_loop_wait = { 2, 0 };
+ meshlink_channel_t *channel = NULL;
+ meshlink_node_t *core_node = NULL;
+
+ fprintf(stderr, "\tMesh node 'app2node1' starting up........\n");
+
+ // Import mesh event handler
+
+ if((argv[CMD_LINE_ARG_CLIENTID]) && (argv[CMD_LINE_ARG_IMPORTSTR])) {
+ client_id = atoi(argv[CMD_LINE_ARG_CLIENTID]);
+ mesh_event_sock_connect(argv[CMD_LINE_ARG_IMPORTSTR]);
+ }
+
+ // Setup required signals
+
+ setup_signals();
+ signal(SIGIO, mesh_start_test_handler);
+
+ // Run peer node instance
+
+ mesh = meshlink_open("app2node1conf", argv[CMD_LINE_ARG_NODENAME],
+ "test_channel_conn", atoi(argv[CMD_LINE_ARG_DEVCLASS]));
+ assert(mesh);
+ meshlink_set_log_cb(mesh, MESHLINK_DEBUG, meshlink_callback_logger);
+ meshlink_set_channel_accept_cb(mesh, channel_accept);
+ meshlink_set_node_status_cb(mesh, node_status_cb);
+
+ if(argv[CMD_LINE_ARG_INVITEURL]) {
+ assert(meshlink_join(mesh, argv[CMD_LINE_ARG_INVITEURL]));
+ }
+
+ assert(meshlink_start(mesh));
+
+ send_event(NODE_STARTED);
+
+ // Wait for peer node to join
+
+ assert(wait_sync_flag(&peer_reachable, 15));
+ send_event(NODE_JOINED);
+
+ while(false == wait_sync_flag(&start_test, 10));
+
+ // Open a channel to peer node
+ core_node = meshlink_get_node(mesh, "corenode1");
+ assert(core_node);
+ fprintf(stderr, "\tapp2node1 Sending Channel request to corenode1 at : %lu\n", time(NULL));
+ channel = meshlink_channel_open(mesh, core_node, CHANNEL_PORT,
+ channel_receive_cb, NULL, 0);
+ meshlink_set_channel_poll_cb(mesh, channel, poll_cb);
+ assert(wait_sync_flag(&channel_opened, 15));
+ send_event(CHANNEL_OPENED);
+
+ assert(wait_sync_flag(&channel_data_recieved, 30));
+ send_event(CHANNEL_DATA_RECIEVED);
+
+ // All test steps executed - wait for signals to stop/start or close the mesh
+
+ while(test_running) {
+ select(1, NULL, NULL, NULL, &main_loop_wait);
+ }
+
+ meshlink_close(mesh);
+
+ return EXIT_SUCCESS;
+}
\ No newline at end of file
--- /dev/null
+/*
+ node_sim_peer.c -- Implementation of Node Simulation for Meshlink Testing
+ for meta connection test case 01 - re-connection of
+ two nodes when relay node goes down
+ Copyright (C) 2018 Guus Sliepen <guus@meshlink.io>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <assert.h>
+#include <signal.h>
+#include <time.h>
+#include "../common/common_handlers.h"
+#include "../common/test_step.h"
+#include "../common/mesh_event_handler.h"
+#include "../../utils.h"
+
+#define CMD_LINE_ARG_NODENAME 1
+#define CMD_LINE_ARG_DEVCLASS 2
+#define CMD_LINE_ARG_CLIENTID 3
+#define CMD_LINE_ARG_IMPORTSTR 4
+#define CMD_LINE_ARG_INVITEURL 5
+#define CHANNEL_PORT 1234
+
+static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len);
+static bool channel_accept(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *dat, size_t len);
+
+static int client_id = -1;
+static meshlink_handle_t *mesh = NULL;
+
+static struct sync_flag peer_reachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag start_test = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag app_reachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag channel_opened = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag channel_data_recieved = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+
+static void send_event(mesh_event_t event) {
+ int attempts;
+
+ for(attempts = 0; attempts < 5; attempts += 1) {
+ if(mesh_event_sock_send(client_id, event, NULL, 0)) {
+ break;
+ }
+ }
+
+ assert(attempts < 5);
+
+ return;
+}
+
+static bool channel_accept(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *dat, size_t len) {
+ (void)dat;
+ (void)len;
+
+ assert(port == CHANNEL_PORT);
+
+ fprintf(stderr, "\tapp2node2 got channel request from %s\n", channel->node->name);
+
+ if(!strcmp(channel->node->name, "corenode1")) {
+ meshlink_set_channel_receive_cb(mesh, channel, channel_receive_cb);
+ mesh->priv = channel;
+
+ return true;
+ }
+
+ return false;
+}
+
+/* channel receive callback */
+static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) {
+ char data[100] = {0};
+
+ if(len == 0) {
+ fprintf(stderr, "\tapp2node2 got error from %s at %lu\n", channel->node->name, time(NULL));
+ send_event(ERR_NETWORK);
+ return;
+ }
+
+ memcpy(data, dat, len);
+
+ fprintf(stderr, "\tapp2node2 got message from %s as %s\n", channel->node->name, data);
+
+ if(!strcmp(channel->node->name, "corenode1")) {
+ if(!memcmp(dat, "Channel Message", len)) {
+ set_sync_flag(&channel_data_recieved, true);
+ } else if(!memcmp(dat, "failure", 7)) {
+ assert(false);
+ }
+ } else if(!strcmp(channel->node->name, "app2node1")) {
+ if(!memcmp(dat, "Channel Message", len)) {
+ set_sync_flag(&channel_data_recieved, true);
+ } else if(!memcmp(dat, "failure", 7)) {
+ assert(false);
+ }
+ } else {
+ assert(false);
+ }
+
+ return;
+}
+
+static void poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, size_t len) {
+ char *message = "Channel Message";
+ char *node = (char *)channel->node->name;
+ (void)len;
+ meshlink_set_channel_poll_cb(mesh, channel, NULL);
+ fprintf(stderr, "\tapp2node2's Channel request has been accepted by %s at : %lu\n", node, time(NULL));
+ set_sync_flag(&channel_opened, true);
+ assert(meshlink_channel_send(mesh, channel, message, strlen(message)) >= 0);
+ return;
+}
+
+
+static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node,
+ bool reachable) {
+ if(!strcasecmp(node->name, "corenode1")) {
+ if(reachable) {
+ fprintf(stderr, "\tNode corenode1 became reachable\n");
+ set_sync_flag(&peer_reachable, true);
+ }
+ } else if(!strcasecmp(node->name, "app2node1")) {
+ if(reachable) {
+ fprintf(stderr, "\tNode app2node1 became reachable\n");
+ set_sync_flag(&app_reachable, true);
+ }
+ }
+
+ return;
+}
+
+void mesh_start_test_handler(int a) {
+ fprintf(stderr, "Starting test in app2node2\n");
+ set_sync_flag(&start_test, true);
+}
+
+int main(int argc, char *argv[]) {
+ size_t num_nodes, i;
+ struct timeval main_loop_wait = { 2, 0 };
+ meshlink_channel_t *channel = NULL;
+ meshlink_node_t *core_node = NULL;
+ meshlink_node_t **node_handles = NULL;
+
+ fprintf(stderr, "\tMesh node 'app2node2' starting up........\n");
+
+ // Import mesh event handler
+
+ if((argv[CMD_LINE_ARG_CLIENTID]) && (argv[CMD_LINE_ARG_IMPORTSTR])) {
+ client_id = atoi(argv[CMD_LINE_ARG_CLIENTID]);
+ mesh_event_sock_connect(argv[CMD_LINE_ARG_IMPORTSTR]);
+ }
+
+ // Setup required signals
+
+ setup_signals();
+ signal(SIGIO, mesh_start_test_handler);
+
+ // Run peer node instance
+
+ mesh = meshlink_open("app2node2conf", argv[CMD_LINE_ARG_NODENAME],
+ "test_channel_conn", atoi(argv[CMD_LINE_ARG_DEVCLASS]));
+ assert(mesh);
+ meshlink_set_log_cb(mesh, MESHLINK_DEBUG, meshlink_callback_logger);
+ meshlink_set_channel_accept_cb(mesh, channel_accept);
+ meshlink_set_node_status_cb(mesh, node_status_cb);
+
+ if(argv[CMD_LINE_ARG_INVITEURL]) {
+ assert(meshlink_join(mesh, argv[CMD_LINE_ARG_INVITEURL]));
+ }
+
+ assert(meshlink_start(mesh));
+
+ send_event(NODE_STARTED);
+
+ // Wait for peer node to join
+
+ assert(wait_sync_flag(&peer_reachable, 15));
+ send_event(NODE_JOINED);
+
+ while(false == wait_sync_flag(&start_test, 10));
+
+ // Open a channel to peer node
+ core_node = meshlink_get_node(mesh, "corenode1");
+ assert(core_node);
+ fprintf(stderr, "\tapp2node2 Sending Channel request to corenode1 at : %lu\n", time(NULL));
+ channel = meshlink_channel_open(mesh, core_node, CHANNEL_PORT,
+ channel_receive_cb, NULL, 0);
+ meshlink_set_channel_poll_cb(mesh, channel, poll_cb);
+ assert(wait_sync_flag(&channel_opened, 30));
+ send_event(CHANNEL_OPENED);
+
+ assert(wait_sync_flag(&channel_data_recieved, 30));
+ send_event(CHANNEL_DATA_RECIEVED);
+
+ // Open a channel to peer node
+ channel_opened.flag = false;
+ channel_data_recieved.flag = false;
+
+ assert(wait_sync_flag(&app_reachable, 60));
+
+ core_node = meshlink_get_node(mesh, "app2node1");
+ assert(core_node);
+ fprintf(stderr, "\tapp2node2 Sending Channel request to app2node1 at : %lu\n", time(NULL));
+ channel = meshlink_channel_open(mesh, core_node, CHANNEL_PORT,
+ channel_receive_cb, NULL, 0);
+ meshlink_set_channel_poll_cb(mesh, channel, poll_cb);
+ assert(wait_sync_flag(&channel_opened, 15));
+ send_event(CHANNEL_OPENED);
+
+ assert(wait_sync_flag(&channel_data_recieved, 30));
+ send_event(CHANNEL_DATA_RECIEVED);
+
+ num_nodes = 0;
+ node_handles = meshlink_get_all_nodes(mesh, NULL, &num_nodes);
+ fprintf(stderr, "\tGot %d nodes in list with error : %s\n", num_nodes, meshlink_strerror(meshlink_errno));
+ assert(node_handles);
+ assert((num_nodes == 4));
+
+ for(i = 0; i < num_nodes; i++) {
+ fprintf(stderr, "\tChecking the node : %s\n", node_handles[i]->name);
+
+ if(0 == strcmp(node_handles[i]->name, "app1node1")) {
+ send_event(SIG_ABORT);
+ assert(false);
+ } else if(0 == strcmp(node_handles[i]->name, "app1node2")) {
+ send_event(SIG_ABORT);
+ assert(false);
+ }
+ }
+
+ meshlink_node_t *node = meshlink_get_self(mesh);
+ assert(node);
+ meshlink_submesh_t *submesh = meshlink_get_node_submesh(mesh, node);
+ assert(submesh);
+
+ node_handles = meshlink_get_all_nodes_by_submesh(mesh, submesh, node_handles, &num_nodes);
+ assert(node_handles);
+ assert((num_nodes == 2));
+
+ for(i = 0; i < num_nodes; i++) {
+ fprintf(stderr, "\tChecking the node : %s\n", node_handles[i]->name);
+
+ if((0 == strcmp(node_handles[i]->name, "app1node1")) || (0 == strcmp(node_handles[i]->name, "app1node2"))) {
+ send_event(SIG_ABORT);
+ assert(false);
+ }
+ }
+
+ send_event(MESH_EVENT_COMPLETED);
+
+ // All test steps executed - wait for signals to stop/start or close the mesh
+
+ while(test_running) {
+ select(1, NULL, NULL, NULL, &main_loop_wait);
+ }
+
+ meshlink_close(mesh);
+
+ return EXIT_SUCCESS;
+}
\ No newline at end of file
--- /dev/null
+/*
+ node_sim.c -- Implementation of Node Simulation for Meshlink Testing
+ for meta connection test case 01 - re-connection of
+ two nodes when relay node goes down
+ Copyright (C) 2018 Guus Sliepen <guus@meshlink.io>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <signal.h>
+#include "../common/common_handlers.h"
+#include "../common/test_step.h"
+#include "../common/mesh_event_handler.h"
+#include "../../utils.h"
+
+#define CMD_LINE_ARG_NODENAME 1
+#define CMD_LINE_ARG_DEVCLASS 2
+#define CMD_LINE_ARG_CLIENTID 3
+#define CMD_LINE_ARG_IMPORTSTR 4
+#define CMD_LINE_ARG_INVITEURL 5
+#define CHANNEL_PORT 1234
+
+static bool conn_status = false;
+static int client_id = -1;
+
+static struct sync_flag peer_reachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag channel_opened = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag channel_data_recieved = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+
+static meshlink_handle_t *mesh = NULL;
+
+static void mesh_send_message_handler(char *destination);
+
+static void send_event(mesh_event_t event) {
+ int attempts;
+
+ for(attempts = 0; attempts < 5; attempts += 1) {
+ if(mesh_event_sock_send(client_id, event, NULL, 0)) {
+ break;
+ }
+ }
+
+ assert(attempts < 5);
+
+ return;
+}
+
+/* channel receive callback */
+static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) {
+ char data[100] = {0};
+
+ if(len == 0) {
+ send_event(ERR_NETWORK);
+ return;
+ }
+
+ memcpy(data, dat, len);
+
+ fprintf(stderr, "corenode1 got message from %s as %s\n", channel->node->name, data);
+
+ if(!memcmp(dat, "Channel Message", len)) {
+ mesh_send_message_handler(channel->node->name);
+
+ if(0 == strcmp("corenode2", channel->node->name)) {
+ set_sync_flag(&channel_data_recieved, true);
+ }
+ } else if(!memcmp(dat, "failure", 7)) {
+ assert(false);
+ }
+
+ return;
+}
+
+static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node,
+ bool reachable) {
+ if(reachable) {
+ fprintf(stderr, "Node %s became reachable\n", node->name);
+ } else {
+ fprintf(stderr, "Node %s is unreachable\n", node->name);
+ }
+
+ return;
+}
+
+static void poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, size_t len) {
+ char *message = "Channel Message";
+ char *node = channel->node->name;
+ (void)len;
+ meshlink_set_channel_poll_cb(mesh, channel, NULL);
+ fprintf(stderr, "corenode1's Channel request has been accepted by %s at : %lu\n", node, time(NULL));
+
+ if(0 == strcmp("corenode2", node)) {
+ set_sync_flag(&channel_opened, true);
+ }
+
+ assert(meshlink_channel_send(mesh, channel, message, strlen(message)) >= 0);
+ return;
+}
+
+/* channel receive callback */
+static bool channel_accept(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *dat, size_t len) {
+ (void)dat;
+ (void)len;
+
+ assert(port == CHANNEL_PORT);
+
+ fprintf(stderr, "corenode1 got channel request from %s\n", channel->node->name);
+ meshlink_set_channel_receive_cb(mesh, channel, channel_receive_cb);
+
+ return true;
+}
+
+void mesh_send_message_handler(char *destination) {
+ meshlink_channel_t *channel = NULL;
+ meshlink_node_t *target_node = NULL;
+
+ // Open a channel to destination node
+ target_node = meshlink_get_node(mesh, destination);
+ assert(target_node);
+ fprintf(stderr, "corenode1 Sending Channel request to %s at : %lu\n", destination, time(NULL));
+ channel = meshlink_channel_open(mesh, target_node, CHANNEL_PORT,
+ channel_receive_cb, NULL, 0);
+ meshlink_set_channel_poll_cb(mesh, channel, poll_cb);
+}
+
+int main(int argc, char *argv[]) {
+ struct timeval main_loop_wait = { 5, 0 };
+ int i;
+
+ // Import mesh event handler
+
+ fprintf(stderr, "Mesh node 'corenode1' starting up........\n");
+
+ if((argv[CMD_LINE_ARG_CLIENTID]) && (argv[CMD_LINE_ARG_IMPORTSTR])) {
+ client_id = atoi(argv[CMD_LINE_ARG_CLIENTID]);
+ mesh_event_sock_connect(argv[CMD_LINE_ARG_IMPORTSTR]);
+ }
+
+ setup_signals();
+
+ // Execute test steps
+
+ mesh = meshlink_open("testconf", argv[CMD_LINE_ARG_NODENAME],
+ "test_channel_conn", atoi(argv[CMD_LINE_ARG_DEVCLASS]));
+ assert(mesh);
+ meshlink_set_log_cb(mesh, MESHLINK_DEBUG, meshlink_callback_logger);
+ meshlink_set_channel_accept_cb(mesh, channel_accept);
+ meshlink_set_node_status_cb(mesh, node_status_cb);
+
+ if(argv[CMD_LINE_ARG_INVITEURL]) {
+ assert(meshlink_join(mesh, argv[CMD_LINE_ARG_INVITEURL]));
+ }
+
+ assert(meshlink_start(mesh));
+
+ send_event(NODE_STARTED);
+
+ assert(wait_sync_flag(&channel_opened, 10));
+ send_event(CHANNEL_OPENED);
+
+ assert(wait_sync_flag(&channel_data_recieved, 10));
+ send_event(CHANNEL_DATA_RECIEVED);
+
+ // All test steps executed - wait for signals to stop/start or close the mesh
+
+ while(test_running) {
+ select(1, NULL, NULL, NULL, &main_loop_wait);
+ }
+
+ meshlink_close(mesh);
+
+ return 0;
+}
--- /dev/null
+/*
+ node_sim_peer.c -- Implementation of Node Simulation for Meshlink Testing
+ for meta connection test case 01 - re-connection of
+ two nodes when relay node goes down
+ Copyright (C) 2018 Guus Sliepen <guus@meshlink.io>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <assert.h>
+#include <signal.h>
+#include <time.h>
+#include "../common/common_handlers.h"
+#include "../common/test_step.h"
+#include "../common/mesh_event_handler.h"
+#include "../../utils.h"
+
+#define CMD_LINE_ARG_NODENAME 1
+#define CMD_LINE_ARG_DEVCLASS 2
+#define CMD_LINE_ARG_CLIENTID 3
+#define CMD_LINE_ARG_IMPORTSTR 4
+#define CMD_LINE_ARG_INVITEURL 5
+#define CHANNEL_PORT 1234
+
+static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len);
+static bool channel_accept(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *dat, size_t len);
+
+static int client_id = -1;
+static meshlink_handle_t *mesh = NULL;
+
+static struct sync_flag peer_reachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag start_test = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag channel_opened = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag channel_data_recieved = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+
+static void send_event(mesh_event_t event) {
+ int attempts;
+
+ for(attempts = 0; attempts < 5; attempts += 1) {
+ if(mesh_event_sock_send(client_id, event, NULL, 0)) {
+ break;
+ }
+ }
+
+ assert(attempts < 5);
+
+ return;
+}
+
+static bool channel_accept(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *dat, size_t len) {
+ (void)dat;
+ (void)len;
+
+ assert(port == CHANNEL_PORT);
+
+ fprintf(stderr, "corenode2 got channel request from %s", channel->node->name);
+
+ if(!strcmp(channel->node->name, "corenode1")) {
+ meshlink_set_channel_receive_cb(mesh, channel, channel_receive_cb);
+ mesh->priv = channel;
+
+ return true;
+ }
+
+ return false;
+}
+
+/* channel receive callback */
+static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) {
+ char data[100] = {0};
+
+ if(len == 0) {
+ send_event(ERR_NETWORK);
+ return;
+ }
+
+ memcpy(data, dat, len);
+
+ fprintf(stderr, "corenode2 got message from %s as %s", channel->node->name, data);
+
+ if(!strcmp(channel->node->name, "corenode1")) {
+ if(!memcmp(dat, "Channel Message", len)) {
+ set_sync_flag(&channel_data_recieved, true);
+ } else if(!memcmp(dat, "failure", 7)) {
+ assert(false);
+ }
+ }
+
+ return;
+}
+
+static void poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, size_t len) {
+ char *message = "Channel Message";
+ (void)len;
+ meshlink_set_channel_poll_cb(mesh, channel, NULL);
+ fprintf(stderr, "corenode2's Channel request has been accepted by corenode1 at : %lu", time(NULL));
+ set_sync_flag(&channel_opened, true);
+ assert(meshlink_channel_send(mesh, channel, message, strlen(message)) >= 0);
+ return;
+}
+
+
+static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node,
+ bool reachable) {
+ if(!strcasecmp(node->name, "corenode1")) {
+ if(reachable) {
+ fprintf(stderr, "Node corenode2 became reachable");
+ set_sync_flag(&peer_reachable, true);
+ }
+ }
+
+ return;
+}
+
+void mesh_start_test_handler(int a) {
+ fprintf(stderr, "Starting test in corenode2\n");
+ set_sync_flag(&start_test, true);
+}
+
+int main(int argc, char *argv[]) {
+ struct timeval main_loop_wait = { 2, 0 };
+ meshlink_channel_t *channel = NULL;
+ meshlink_node_t *core_node = NULL;
+
+ fprintf(stderr, "Mesh node 'corenode2' starting up........\n");
+
+ // Import mesh event handler
+
+ if((argv[CMD_LINE_ARG_CLIENTID]) && (argv[CMD_LINE_ARG_IMPORTSTR])) {
+ client_id = atoi(argv[CMD_LINE_ARG_CLIENTID]);
+ mesh_event_sock_connect(argv[CMD_LINE_ARG_IMPORTSTR]);
+ }
+
+ // Setup required signals
+
+ setup_signals();
+ signal(SIGIO, mesh_start_test_handler);
+
+ // Run peer node instance
+
+ mesh = meshlink_open("corenode1conf", argv[CMD_LINE_ARG_NODENAME],
+ "test_channel_conn", atoi(argv[CMD_LINE_ARG_DEVCLASS]));
+ assert(mesh);
+ meshlink_set_log_cb(mesh, MESHLINK_DEBUG, meshlink_callback_logger);
+ meshlink_set_channel_accept_cb(mesh, channel_accept);
+ meshlink_set_node_status_cb(mesh, node_status_cb);
+
+ if(argv[CMD_LINE_ARG_INVITEURL]) {
+ assert(meshlink_join(mesh, argv[CMD_LINE_ARG_INVITEURL]));
+ }
+
+ assert(meshlink_start(mesh));
+
+ send_event(NODE_STARTED);
+
+ // Wait for peer node to join
+
+ assert(wait_sync_flag(&peer_reachable, 15));
+ send_event(NODE_JOINED);
+
+ while(false == wait_sync_flag(&start_test, 10));
+
+ // Open a channel to peer node
+ core_node = meshlink_get_node(mesh, "corenode1");
+ assert(core_node);
+ fprintf(stderr, "corenode2 Sending Channel request to corenode1 at : %lu", time(NULL));
+ channel = meshlink_channel_open(mesh, core_node, CHANNEL_PORT,
+ channel_receive_cb, NULL, 0);
+ meshlink_set_channel_poll_cb(mesh, channel, poll_cb);
+ assert(wait_sync_flag(&channel_opened, 15));
+ send_event(CHANNEL_OPENED);
+
+ assert(wait_sync_flag(&channel_data_recieved, 10));
+ send_event(CHANNEL_DATA_RECIEVED);
+
+ // All test steps executed - wait for signals to stop/start or close the mesh
+
+ while(test_running) {
+ select(1, NULL, NULL, NULL, &main_loop_wait);
+ }
+
+ meshlink_close(mesh);
+
+ return EXIT_SUCCESS;
+}
\ No newline at end of file
--- /dev/null
+check_PROGRAMS = node_sim_corenode1 node_sim_app1node1 node_sim_app1node2
+
+node_sim_corenode1_SOURCES = node_sim_corenode1.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c
+node_sim_corenode1_LDADD = ../../../src/libmeshlink.la
+node_sim_corenode1_CFLAGS = -D_GNU_SOURCE
+
+node_sim_app1node1_SOURCES = node_sim_app1node1.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c
+node_sim_app1node1_LDADD = ../../../src/libmeshlink.la
+node_sim_app1node1_CFLAGS = -D_GNU_SOURCE
+
+node_sim_app1node2_SOURCES = node_sim_app1node2.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c
+node_sim_app1node2_LDADD = ../../../src/libmeshlink.la
+node_sim_app1node2_CFLAGS = -D_GNU_SOURCE
--- /dev/null
+/*
+ node_sim_peer.c -- Implementation of Node Simulation for Meshlink Testing
+ for meta connection test case 01 - re-connection of
+ two nodes when relay node goes down
+ Copyright (C) 2018 Guus Sliepen <guus@meshlink.io>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <assert.h>
+#include <signal.h>
+#include <time.h>
+#include "../common/common_handlers.h"
+#include "../common/test_step.h"
+#include "../common/mesh_event_handler.h"
+#include "../../utils.h"
+
+#define CMD_LINE_ARG_NODENAME 1
+#define CMD_LINE_ARG_DEVCLASS 2
+#define CMD_LINE_ARG_CLIENTID 3
+#define CMD_LINE_ARG_IMPORTSTR 4
+#define CMD_LINE_ARG_INVITEURL 5
+#define CHANNEL_PORT 1234
+
+static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len);
+static bool channel_accept(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *dat, size_t len);
+
+static int client_id = -1;
+static meshlink_handle_t *mesh = NULL;
+
+static struct sync_flag peer_reachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag start_test = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag channel_opened = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag channel_data_recieved = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+
+static void send_event(mesh_event_t event) {
+ int attempts;
+
+ for(attempts = 0; attempts < 5; attempts += 1) {
+ if(mesh_event_sock_send(client_id, event, NULL, 0)) {
+ break;
+ }
+ }
+
+ assert(attempts < 5);
+
+ return;
+}
+
+static bool channel_accept(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *dat, size_t len) {
+ (void)dat;
+ (void)len;
+
+ assert(port == CHANNEL_PORT);
+
+ fprintf(stderr, "\tapp1node1 got channel request from %s\n", channel->node->name);
+
+ if(!strcmp(channel->node->name, "corenode1")) {
+ fprintf(stderr, "\tapp1node1 accepting channel request from %s at %lu\n", channel->node->name, time(NULL));
+ meshlink_set_channel_receive_cb(mesh, channel, channel_receive_cb);
+ mesh->priv = channel;
+
+ return true;
+ } else if(!strcmp(channel->node->name, "app1node2")) {
+ fprintf(stderr, "\tapp1node1 accepting channel request from %s at %lu\n", channel->node->name, time(NULL));
+ meshlink_set_channel_receive_cb(mesh, channel, channel_receive_cb);
+ mesh->priv = channel;
+
+ return true;
+ }
+
+ fprintf(stderr, "\tapp1node1 rejecting channel request from %s at %lu\n", channel->node->name, time(NULL));
+ return false;
+}
+
+/* channel receive callback */
+static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) {
+ char data[100] = {0};
+ char *message = "Channel Message";
+
+ if(len == 0) {
+ fprintf(stderr, "\tapp1node1 got error from %s at %lu\n", channel->node->name, time(NULL));
+ send_event(ERR_NETWORK);
+ return;
+ }
+
+ memcpy(data, dat, len);
+
+ fprintf(stderr, "\tapp1node1 got message from %s as %s\n", channel->node->name, data);
+
+ if(!strcmp(channel->node->name, "corenode1")) {
+ if(!memcmp(dat, "Channel Message", len)) {
+ set_sync_flag(&channel_data_recieved, true);
+ } else if(!memcmp(dat, "failure", 7)) {
+ assert(false);
+ }
+ } else if(!strcmp(channel->node->name, "app1node2")) {
+ if(!memcmp(dat, "Channel Message", len)) {
+ assert(meshlink_channel_send(mesh, channel, message, strlen(message)) >= 0);
+ } else if(!memcmp(dat, "failure", 7)) {
+ assert(false);
+ }
+ }
+
+ return;
+}
+
+static void poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, size_t len) {
+ char *message = "Channel Message";
+ char *node = (char *)channel->node->name;
+ (void)len;
+ meshlink_set_channel_poll_cb(mesh, channel, NULL);
+ fprintf(stderr, "\tapp1node1's Channel request has been accepted by %s at : %lu\n", node, time(NULL));
+
+ if(0 == strcmp("corenode1", node)) {
+ set_sync_flag(&channel_opened, true);
+ }
+
+ assert(meshlink_channel_send(mesh, channel, message, strlen(message)) >= 0);
+ return;
+}
+
+
+static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node,
+ bool reachable) {
+ if(!strcasecmp(node->name, "corenode1")) {
+ if(reachable) {
+ fprintf(stderr, "\tNode corenode1 became reachable\n");
+ set_sync_flag(&peer_reachable, true);
+ }
+ }
+
+ return;
+}
+
+void mesh_start_test_handler(int a) {
+ fprintf(stderr, "Starting test in app1node1\n");
+ set_sync_flag(&start_test, true);
+}
+
+int main(int argc, char *argv[]) {
+ struct timeval main_loop_wait = { 2, 0 };
+ meshlink_channel_t *channel = NULL;
+ meshlink_node_t *core_node = NULL;
+
+ fprintf(stderr, "\tMesh node 'app1node1' starting up........\n");
+
+ // Import mesh event handler
+
+ if((argv[CMD_LINE_ARG_CLIENTID]) && (argv[CMD_LINE_ARG_IMPORTSTR])) {
+ client_id = atoi(argv[CMD_LINE_ARG_CLIENTID]);
+ mesh_event_sock_connect(argv[CMD_LINE_ARG_IMPORTSTR]);
+ }
+
+ // Setup required signals
+
+ setup_signals();
+ signal(SIGIO, mesh_start_test_handler);
+
+ // Run peer node instance
+
+ mesh = meshlink_open("app1node1conf", argv[CMD_LINE_ARG_NODENAME],
+ "test_channel_conn", atoi(argv[CMD_LINE_ARG_DEVCLASS]));
+ assert(mesh);
+ meshlink_set_log_cb(mesh, MESHLINK_DEBUG, meshlink_callback_logger);
+ meshlink_set_channel_accept_cb(mesh, channel_accept);
+ meshlink_set_node_status_cb(mesh, node_status_cb);
+
+ if(argv[CMD_LINE_ARG_INVITEURL]) {
+ assert(meshlink_join(mesh, argv[CMD_LINE_ARG_INVITEURL]));
+ }
+
+ assert(meshlink_start(mesh));
+
+ send_event(NODE_STARTED);
+
+ // Wait for peer node to join
+
+ assert(wait_sync_flag(&peer_reachable, 15));
+ send_event(NODE_JOINED);
+
+ while(false == wait_sync_flag(&start_test, 10));
+
+ // Open a channel to peer node
+ core_node = meshlink_get_node(mesh, "corenode1");
+ assert(core_node);
+ fprintf(stderr, "\tapp1node1 Sending Channel request to corenode1 at : %lu\n", time(NULL));
+ channel = meshlink_channel_open(mesh, core_node, CHANNEL_PORT,
+ channel_receive_cb, NULL, 0);
+ meshlink_set_channel_poll_cb(mesh, channel, poll_cb);
+ assert(wait_sync_flag(&channel_opened, 15));
+ send_event(CHANNEL_OPENED);
+
+ assert(wait_sync_flag(&channel_data_recieved, 30));
+ send_event(CHANNEL_DATA_RECIEVED);
+
+ // All test steps executed - wait for signals to stop/start or close the mesh
+
+ while(test_running) {
+ select(1, NULL, NULL, NULL, &main_loop_wait);
+ }
+
+ meshlink_close(mesh);
+
+ return EXIT_SUCCESS;
+}
\ No newline at end of file
--- /dev/null
+/*
+ node_sim_peer.c -- Implementation of Node Simulation for Meshlink Testing
+ for meta connection test case 01 - re-connection of
+ two nodes when relay node goes down
+ Copyright (C) 2018 Guus Sliepen <guus@meshlink.io>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <assert.h>
+#include <signal.h>
+#include <time.h>
+#include "../common/common_handlers.h"
+#include "../common/test_step.h"
+#include "../common/mesh_event_handler.h"
+#include "../../utils.h"
+
+#define CMD_LINE_ARG_NODENAME 1
+#define CMD_LINE_ARG_DEVCLASS 2
+#define CMD_LINE_ARG_CLIENTID 3
+#define CMD_LINE_ARG_IMPORTSTR 4
+#define CMD_LINE_ARG_INVITEURL 5
+#define CHANNEL_PORT 1234
+
+static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len);
+static bool channel_accept(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *dat, size_t len);
+
+static int client_id = -1;
+static meshlink_handle_t *mesh = NULL;
+
+static struct sync_flag peer_reachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag start_test = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag app_reachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag channel_opened = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag channel_data_recieved = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+
+static void send_event(mesh_event_t event) {
+ int attempts;
+
+ for(attempts = 0; attempts < 5; attempts += 1) {
+ if(mesh_event_sock_send(client_id, event, NULL, 0)) {
+ break;
+ }
+ }
+
+ assert(attempts < 5);
+
+ return;
+}
+
+static bool channel_accept(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *dat, size_t len) {
+ (void)dat;
+ (void)len;
+
+ assert(port == CHANNEL_PORT);
+
+ fprintf(stderr, "\tapp1node2 got channel request from %s\n", channel->node->name);
+
+ if(!strcmp(channel->node->name, "corenode1")) {
+ meshlink_set_channel_receive_cb(mesh, channel, channel_receive_cb);
+ mesh->priv = channel;
+
+ return true;
+ }
+
+ return false;
+}
+
+/* channel receive callback */
+static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) {
+ char data[100] = {0};
+
+ if(len == 0) {
+ fprintf(stderr, "\tapp1node2 got error from %s at %lu\n", channel->node->name, time(NULL));
+ send_event(ERR_NETWORK);
+ return;
+ }
+
+ memcpy(data, dat, len);
+
+ fprintf(stderr, "\tapp1node2 got message from %s as %s\n", channel->node->name, data);
+
+ if(!strcmp(channel->node->name, "corenode1")) {
+ if(!memcmp(dat, "Channel Message", len)) {
+ set_sync_flag(&channel_data_recieved, true);
+ } else if(!memcmp(dat, "failure", 7)) {
+ assert(false);
+ }
+ } else if(!strcmp(channel->node->name, "app1node1")) {
+ if(!memcmp(dat, "Channel Message", len)) {
+ set_sync_flag(&channel_data_recieved, true);
+ } else if(!memcmp(dat, "failure", 7)) {
+ assert(false);
+ }
+ } else {
+ assert(false);
+ }
+
+ return;
+}
+
+static void poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, size_t len) {
+ char *message = "Channel Message";
+ char *node = (char *)channel->node->name;
+ (void)len;
+ meshlink_set_channel_poll_cb(mesh, channel, NULL);
+ fprintf(stderr, "\tapp1node2's Channel request has been accepted by %s at : %lu\n", node, time(NULL));
+ set_sync_flag(&channel_opened, true);
+ assert(meshlink_channel_send(mesh, channel, message, strlen(message)) >= 0);
+ return;
+}
+
+
+static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node,
+ bool reachable) {
+ if(!strcasecmp(node->name, "corenode1")) {
+ if(reachable) {
+ fprintf(stderr, "\tNode corenode1 became reachable\n");
+ set_sync_flag(&peer_reachable, true);
+ }
+ } else if(!strcasecmp(node->name, "app1node1")) {
+ if(reachable) {
+ fprintf(stderr, "\tNode app1node1 became reachable\n");
+ set_sync_flag(&app_reachable, true);
+ }
+ }
+
+ return;
+}
+
+void mesh_start_test_handler(int a) {
+ fprintf(stderr, "Starting test in app1node2\n");
+ set_sync_flag(&start_test, true);
+}
+
+int main(int argc, char *argv[]) {
+ size_t num_nodes, i;
+ struct timeval main_loop_wait = { 2, 0 };
+ meshlink_channel_t *channel = NULL;
+ meshlink_node_t *core_node = NULL;
+ meshlink_node_t **node_handles = NULL;
+
+ fprintf(stderr, "\tMesh node 'app1node2' starting up........\n");
+
+ // Import mesh event handler
+
+ if((argv[CMD_LINE_ARG_CLIENTID]) && (argv[CMD_LINE_ARG_IMPORTSTR])) {
+ client_id = atoi(argv[CMD_LINE_ARG_CLIENTID]);
+ mesh_event_sock_connect(argv[CMD_LINE_ARG_IMPORTSTR]);
+ }
+
+ // Setup required signals
+
+ setup_signals();
+ signal(SIGIO, mesh_start_test_handler);
+
+ // Run peer node instance
+
+ mesh = meshlink_open("app1node2conf", argv[CMD_LINE_ARG_NODENAME],
+ "test_channel_conn", atoi(argv[CMD_LINE_ARG_DEVCLASS]));
+ assert(mesh);
+ meshlink_set_log_cb(mesh, MESHLINK_DEBUG, meshlink_callback_logger);
+ meshlink_set_channel_accept_cb(mesh, channel_accept);
+ meshlink_set_node_status_cb(mesh, node_status_cb);
+
+ if(argv[CMD_LINE_ARG_INVITEURL]) {
+ assert(meshlink_join(mesh, argv[CMD_LINE_ARG_INVITEURL]));
+ }
+
+ assert(meshlink_start(mesh));
+
+ send_event(NODE_STARTED);
+
+ // Wait for peer node to join
+
+ assert(wait_sync_flag(&peer_reachable, 15));
+ send_event(NODE_JOINED);
+
+ while(false == wait_sync_flag(&start_test, 10));
+
+ // Open a channel to peer node
+ core_node = meshlink_get_node(mesh, "corenode1");
+ assert(core_node);
+ fprintf(stderr, "\tapp1node2 Sending Channel request to corenode1 at : %lu\n", time(NULL));
+ channel = meshlink_channel_open(mesh, core_node, CHANNEL_PORT,
+ channel_receive_cb, NULL, 0);
+ meshlink_set_channel_poll_cb(mesh, channel, poll_cb);
+ assert(wait_sync_flag(&channel_opened, 15));
+ send_event(CHANNEL_OPENED);
+
+ assert(wait_sync_flag(&channel_data_recieved, 30));
+ send_event(CHANNEL_DATA_RECIEVED);
+
+ // Open a channel to peer node
+ channel_opened.flag = false;
+ channel_data_recieved.flag = false;
+
+ assert(wait_sync_flag(&app_reachable, 60));
+
+ core_node = meshlink_get_node(mesh, "app1node1");
+ assert(core_node);
+ fprintf(stderr, "\tapp1node2 Sending Channel request to app1node1 at : %lu\n", time(NULL));
+ channel = meshlink_channel_open(mesh, core_node, CHANNEL_PORT,
+ channel_receive_cb, NULL, 0);
+ meshlink_set_channel_poll_cb(mesh, channel, poll_cb);
+ assert(wait_sync_flag(&channel_opened, 15));
+ send_event(CHANNEL_OPENED);
+
+ assert(wait_sync_flag(&channel_data_recieved, 30));
+ send_event(CHANNEL_DATA_RECIEVED);
+
+ num_nodes = 0;
+ node_handles = meshlink_get_all_nodes(mesh, NULL, &num_nodes);
+ fprintf(stderr, "\tGot %lu nodes in list with error : %s\n", num_nodes, meshlink_strerror(meshlink_errno));
+ assert(node_handles);
+
+ for(i = 0; i < num_nodes; i++) {
+ fprintf(stderr, "\tChecking the node : %s\n", node_handles[i]->name);
+
+ if(0 == strcmp(node_handles[i]->name, "app2node1")) {
+ send_event(SIG_ABORT);
+ assert(false);
+ } else if(0 == strcmp(node_handles[i]->name, "app2node2")) {
+ send_event(SIG_ABORT);
+ assert(false);
+ }
+ }
+
+ send_event(MESH_EVENT_COMPLETED);
+
+ // All test steps executed - wait for signals to stop/start or close the mesh
+
+ while(test_running) {
+ select(1, NULL, NULL, NULL, &main_loop_wait);
+ }
+
+ meshlink_close(mesh);
+
+ return EXIT_SUCCESS;
+}
--- /dev/null
+/*
+ node_sim.c -- Implementation of Node Simulation for Meshlink Testing
+ for meta connection test case 01 - re-connection of
+ two nodes when relay node goes down
+ Copyright (C) 2018 Guus Sliepen <guus@meshlink.io>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <signal.h>
+#include "../common/common_handlers.h"
+#include "../common/test_step.h"
+#include "../common/mesh_event_handler.h"
+#include "../../utils.h"
+
+#define CMD_LINE_ARG_NODENAME 1
+#define CMD_LINE_ARG_DEVCLASS 2
+#define CMD_LINE_ARG_CLIENTID 3
+#define CMD_LINE_ARG_IMPORTSTR 4
+#define CMD_LINE_ARG_INVITEURL 5
+#define CHANNEL_PORT 1234
+
+static bool conn_status = false;
+static int client_id = -1;
+
+static struct sync_flag peer_reachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag channel_opened = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag channel_data_recieved = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+
+static meshlink_handle_t *mesh = NULL;
+
+static void mesh_send_message_handler(char *destination);
+
+static void send_event(mesh_event_t event) {
+ int attempts;
+
+ for(attempts = 0; attempts < 5; attempts += 1) {
+ if(mesh_event_sock_send(client_id, event, NULL, 0)) {
+ break;
+ }
+ }
+
+ assert(attempts < 5);
+
+ return;
+}
+
+/* channel receive callback */
+static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) {
+ char data[100] = {0};
+
+ if(len == 0) {
+ send_event(ERR_NETWORK);
+ return;
+ }
+
+ memcpy(data, dat, len);
+
+ fprintf(stderr, "corenode1 got message from %s as %s\n", channel->node->name, data);
+
+ if(!memcmp(dat, "Channel Message", len)) {
+ mesh_send_message_handler((char *)channel->node->name);
+
+ if(0 == strcmp("app1node1", channel->node->name)) {
+ set_sync_flag(&channel_data_recieved, true);
+ }
+ } else if(!memcmp(dat, "failure", 7)) {
+ assert(false);
+ }
+
+ return;
+}
+
+static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node,
+ bool reachable) {
+ if(reachable) {
+ fprintf(stderr, "Node %s became reachable\n", node->name);
+ } else {
+ fprintf(stderr, "Node %s is unreachable\n", node->name);
+ }
+
+ return;
+}
+
+static void poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, size_t len) {
+ char *message = "Channel Message";
+ char *node = (char *)channel->node->name;
+ (void)len;
+ meshlink_set_channel_poll_cb(mesh, channel, NULL);
+ fprintf(stderr, "corenode1's Channel request has been accepted by %s at : %lu\n", node, time(NULL));
+
+ if(0 == strcmp("app1node1", node)) {
+ set_sync_flag(&channel_opened, true);
+ }
+
+ assert(meshlink_channel_send(mesh, channel, message, strlen(message)) >= 0);
+ return;
+}
+
+/* channel receive callback */
+static bool channel_accept(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *dat, size_t len) {
+ (void)dat;
+ (void)len;
+
+ assert(port == CHANNEL_PORT);
+
+ fprintf(stderr, "corenode1 got channel request from %s\n", channel->node->name);
+ meshlink_set_channel_receive_cb(mesh, channel, channel_receive_cb);
+
+ return true;
+}
+
+void mesh_send_message_handler(char *destination) {
+ meshlink_channel_t *channel = NULL;
+ meshlink_node_t *target_node = NULL;
+
+ // Open a channel to destination node
+ target_node = meshlink_get_node(mesh, destination);
+ assert(target_node);
+ fprintf(stderr, "corenode1 Sending Channel request to %s at : %lu\n", destination, time(NULL));
+ channel = meshlink_channel_open(mesh, target_node, CHANNEL_PORT,
+ channel_receive_cb, NULL, 0);
+ meshlink_set_channel_poll_cb(mesh, channel, poll_cb);
+}
+
+int main(int argc, char *argv[]) {
+ struct timeval main_loop_wait = { 5, 0 };
+ int i;
+
+ // Import mesh event handler
+
+ fprintf(stderr, "Mesh node 'corenode1' starting up........\n");
+
+ if((argv[CMD_LINE_ARG_CLIENTID]) && (argv[CMD_LINE_ARG_IMPORTSTR])) {
+ client_id = atoi(argv[CMD_LINE_ARG_CLIENTID]);
+ mesh_event_sock_connect(argv[CMD_LINE_ARG_IMPORTSTR]);
+ }
+
+ setup_signals();
+
+ // Execute test steps
+
+ mesh = meshlink_open("testconf", argv[CMD_LINE_ARG_NODENAME],
+ "test_channel_conn", atoi(argv[CMD_LINE_ARG_DEVCLASS]));
+ assert(mesh);
+ meshlink_set_log_cb(mesh, MESHLINK_DEBUG, meshlink_callback_logger);
+ meshlink_set_channel_accept_cb(mesh, channel_accept);
+ meshlink_set_node_status_cb(mesh, node_status_cb);
+
+ if(argv[CMD_LINE_ARG_INVITEURL]) {
+ assert(meshlink_join(mesh, argv[CMD_LINE_ARG_INVITEURL]));
+ }
+
+ assert(meshlink_start(mesh));
+
+ send_event(NODE_STARTED);
+
+ assert(wait_sync_flag(&channel_opened, 10));
+ send_event(CHANNEL_OPENED);
+
+ assert(wait_sync_flag(&channel_data_recieved, 10));
+ send_event(CHANNEL_DATA_RECIEVED);
+
+ // All test steps executed - wait for signals to stop/start or close the mesh
+
+ while(test_running) {
+ select(1, NULL, NULL, NULL, &main_loop_wait);
+ }
+
+ meshlink_close(mesh);
+
+ return 0;
+}
--- /dev/null
+check_PROGRAMS = node_sim_corenode1 node_sim_app1node1 node_sim_app1node2
+
+node_sim_corenode1_SOURCES = node_sim_corenode1.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c
+node_sim_corenode1_LDADD = ../../../src/libmeshlink.la
+node_sim_corenode1_CFLAGS = -D_GNU_SOURCE
+
+node_sim_app1node1_SOURCES = node_sim_app1node1.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c
+node_sim_app1node1_LDADD = ../../../src/libmeshlink.la
+node_sim_app1node1_CFLAGS = -D_GNU_SOURCE
+
+node_sim_app1node2_SOURCES = node_sim_app1node2.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c
+node_sim_app1node2_LDADD = ../../../src/libmeshlink.la
+node_sim_app1node2_CFLAGS = -D_GNU_SOURCE
--- /dev/null
+/*
+ node_sim_peer.c -- Implementation of Node Simulation for Meshlink Testing
+ for meta connection test case 01 - re-connection of
+ two nodes when relay node goes down
+ Copyright (C) 2018 Guus Sliepen <guus@meshlink.io>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <assert.h>
+#include <signal.h>
+#include <time.h>
+#include "../common/common_handlers.h"
+#include "../common/test_step.h"
+#include "../common/mesh_event_handler.h"
+#include "../../utils.h"
+
+#define CMD_LINE_ARG_NODENAME 1
+#define CMD_LINE_ARG_DEVCLASS 2
+#define CMD_LINE_ARG_CLIENTID 3
+#define CMD_LINE_ARG_IMPORTSTR 4
+#define CMD_LINE_ARG_INVITEURL 5
+#define CHANNEL_PORT 1234
+
+static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len);
+static bool channel_accept(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *dat, size_t len);
+
+static int client_id = -1;
+static meshlink_handle_t *mesh = NULL;
+
+static struct sync_flag peer_reachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag start_test = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag channel_opened = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag channel_data_recieved = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+
+static void send_event(mesh_event_t event) {
+ int attempts;
+
+ for(attempts = 0; attempts < 5; attempts += 1) {
+ if(mesh_event_sock_send(client_id, event, NULL, 0)) {
+ break;
+ }
+ }
+
+ assert(attempts < 5);
+
+ return;
+}
+
+static bool channel_accept(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *dat, size_t len) {
+ (void)dat;
+ (void)len;
+
+ assert(port == CHANNEL_PORT);
+
+ fprintf(stderr, "\tapp1node1 got channel request from %s\n", channel->node->name);
+
+ if(!strcmp(channel->node->name, "corenode1")) {
+ fprintf(stderr, "\tapp1node1 accepting channel request from %s at %lu\n", channel->node->name, time(NULL));
+ meshlink_set_channel_receive_cb(mesh, channel, channel_receive_cb);
+ mesh->priv = channel;
+
+ return true;
+ } else if(!strcmp(channel->node->name, "app1node2")) {
+ fprintf(stderr, "\tapp1node1 accepting channel request from %s at %lu\n", channel->node->name, time(NULL));
+ meshlink_set_channel_receive_cb(mesh, channel, channel_receive_cb);
+ mesh->priv = channel;
+
+ return true;
+ }
+
+ fprintf(stderr, "\tapp1node1 rejecting channel request from %s at %lu\n", channel->node->name, time(NULL));
+ return false;
+}
+
+/* channel receive callback */
+static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) {
+ char data[100] = {0};
+ char *message = "Channel Message";
+
+ if(len == 0) {
+ fprintf(stderr, "\tapp1node1 got error from %s at %lu\n", channel->node->name, time(NULL));
+ send_event(ERR_NETWORK);
+ return;
+ }
+
+ memcpy(data, dat, len);
+
+ fprintf(stderr, "\tapp1node1 got message from %s as %s\n", channel->node->name, data);
+
+ if(!strcmp(channel->node->name, "corenode1")) {
+ if(!memcmp(dat, "Channel Message", len)) {
+ set_sync_flag(&channel_data_recieved, true);
+ } else if(!memcmp(dat, "failure", 7)) {
+ assert(false);
+ }
+ } else if(!strcmp(channel->node->name, "app1node2")) {
+ if(!memcmp(dat, "Channel Message", len)) {
+ assert(meshlink_channel_send(mesh, channel, message, strlen(message)) >= 0);
+ } else if(!memcmp(dat, "failure", 7)) {
+ assert(false);
+ }
+ }
+
+ return;
+}
+
+static void poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, size_t len) {
+ char *message = "Channel Message";
+ char *node = (char *)channel->node->name;
+ (void)len;
+ meshlink_set_channel_poll_cb(mesh, channel, NULL);
+ fprintf(stderr, "\tapp1node1's Channel request has been accepted by %s at : %lu\n", node, time(NULL));
+
+ if(0 == strcmp("corenode1", node)) {
+ set_sync_flag(&channel_opened, true);
+ }
+
+ assert(meshlink_channel_send(mesh, channel, message, strlen(message)) >= 0);
+ return;
+}
+
+
+static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node,
+ bool reachable) {
+ if(!strcasecmp(node->name, "corenode1")) {
+ if(reachable) {
+ fprintf(stderr, "\tNode corenode1 became reachable\n");
+ set_sync_flag(&peer_reachable, true);
+ }
+ }
+
+ return;
+}
+
+void mesh_start_test_handler(int a) {
+ fprintf(stderr, "Starting test in app1node1\n");
+ set_sync_flag(&start_test, true);
+}
+
+int main(int argc, char *argv[]) {
+ struct timeval main_loop_wait = { 2, 0 };
+ meshlink_channel_t *channel = NULL;
+ meshlink_node_t *core_node = NULL;
+
+ fprintf(stderr, "\tMesh node 'app1node1' starting up........\n");
+
+ // Import mesh event handler
+
+ if((argv[CMD_LINE_ARG_CLIENTID]) && (argv[CMD_LINE_ARG_IMPORTSTR])) {
+ client_id = atoi(argv[CMD_LINE_ARG_CLIENTID]);
+ mesh_event_sock_connect(argv[CMD_LINE_ARG_IMPORTSTR]);
+ }
+
+ // Setup required signals
+
+ setup_signals();
+ signal(SIGIO, mesh_start_test_handler);
+
+ // Run peer node instance
+
+ mesh = meshlink_open("app1node1conf", argv[CMD_LINE_ARG_NODENAME],
+ "test_channel_conn", atoi(argv[CMD_LINE_ARG_DEVCLASS]));
+ assert(mesh);
+ meshlink_set_log_cb(mesh, MESHLINK_DEBUG, meshlink_callback_logger);
+ meshlink_set_channel_accept_cb(mesh, channel_accept);
+ meshlink_set_node_status_cb(mesh, node_status_cb);
+
+ if(argv[CMD_LINE_ARG_INVITEURL]) {
+ assert(meshlink_join(mesh, argv[CMD_LINE_ARG_INVITEURL]));
+ }
+
+ assert(meshlink_start(mesh));
+
+ send_event(NODE_STARTED);
+
+ // Wait for peer node to join
+
+ assert(wait_sync_flag(&peer_reachable, 15));
+ send_event(NODE_JOINED);
+
+ while(false == wait_sync_flag(&start_test, 10));
+
+ // Open a channel to peer node
+ core_node = meshlink_get_node(mesh, "corenode1");
+ assert(core_node);
+ fprintf(stderr, "\tapp1node1 Sending Channel request to corenode1 at : %lu\n", time(NULL));
+ channel = meshlink_channel_open(mesh, core_node, CHANNEL_PORT,
+ channel_receive_cb, NULL, 0);
+ meshlink_set_channel_poll_cb(mesh, channel, poll_cb);
+ assert(wait_sync_flag(&channel_opened, 15));
+ send_event(CHANNEL_OPENED);
+
+ assert(wait_sync_flag(&channel_data_recieved, 30));
+ send_event(CHANNEL_DATA_RECIEVED);
+
+ // All test steps executed - wait for signals to stop/start or close the mesh
+
+ while(test_running) {
+ select(1, NULL, NULL, NULL, &main_loop_wait);
+ }
+
+ meshlink_close(mesh);
+
+ return EXIT_SUCCESS;
+}
\ No newline at end of file
--- /dev/null
+/*
+ node_sim_peer.c -- Implementation of Node Simulation for Meshlink Testing
+ for meta connection test case 01 - re-connection of
+ two nodes when relay node goes down
+ Copyright (C) 2018 Guus Sliepen <guus@meshlink.io>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <assert.h>
+#include <signal.h>
+#include <time.h>
+#include "../common/common_handlers.h"
+#include "../common/test_step.h"
+#include "../common/mesh_event_handler.h"
+#include "../../utils.h"
+
+#define CMD_LINE_ARG_NODENAME 1
+#define CMD_LINE_ARG_DEVCLASS 2
+#define CMD_LINE_ARG_CLIENTID 3
+#define CMD_LINE_ARG_IMPORTSTR 4
+#define CMD_LINE_ARG_INVITEURL 5
+#define CHANNEL_PORT 1234
+
+static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len);
+static bool channel_accept(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *dat, size_t len);
+
+static int client_id = -1;
+static meshlink_handle_t *mesh = NULL;
+
+static struct sync_flag peer_reachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag start_test = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag app_reachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag channel_opened = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag channel_data_recieved = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static meshlink_channel_t *ch_app1node1 = NULL;
+
+static void send_event(mesh_event_t event) {
+ int attempts;
+
+ for(attempts = 0; attempts < 5; attempts += 1) {
+ if(mesh_event_sock_send(client_id, event, NULL, 0)) {
+ break;
+ }
+ }
+
+ assert(attempts < 5);
+
+ return;
+}
+
+static bool channel_accept(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *dat, size_t len) {
+ (void)dat;
+ (void)len;
+
+ assert(port == CHANNEL_PORT);
+
+ fprintf(stderr, "\tapp1node2 got channel request from %s\n", channel->node->name);
+
+ if(!strcmp(channel->node->name, "corenode1")) {
+ meshlink_set_channel_receive_cb(mesh, channel, channel_receive_cb);
+ mesh->priv = channel;
+
+ return true;
+ }
+
+ return false;
+}
+
+/* channel receive callback */
+static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) {
+ char data[100] = {0};
+
+ if(len == 0) {
+ fprintf(stderr, "\tapp1node2 got error from %s at %lu\n", channel->node->name, time(NULL));
+ send_event(ERR_NETWORK);
+ return;
+ }
+
+ memcpy(data, dat, len);
+
+ fprintf(stderr, "\tapp1node2 got message from %s as %s\n", channel->node->name, data);
+
+ if(!strcmp(channel->node->name, "corenode1")) {
+ if(!memcmp(dat, "Channel Message", len)) {
+ set_sync_flag(&channel_data_recieved, true);
+ } else if(!memcmp(dat, "failure", 7)) {
+ assert(false);
+ }
+ } else if(!strcmp(channel->node->name, "app1node1")) {
+ if(!memcmp(dat, "Channel Message", len)) {
+ ch_app1node1 = channel;
+ set_sync_flag(&channel_data_recieved, true);
+ } else if(!memcmp(dat, "failure", 7)) {
+ assert(false);
+ }
+ } else {
+ assert(false);
+ }
+
+ return;
+}
+
+static void poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, size_t len) {
+ char *message = "Channel Message";
+ char *node = (char *)channel->node->name;
+ (void)len;
+ meshlink_set_channel_poll_cb(mesh, channel, NULL);
+ fprintf(stderr, "\tapp1node2's Channel request has been accepted by %s at : %lu\n", node, time(NULL));
+ set_sync_flag(&channel_opened, true);
+ assert(meshlink_channel_send(mesh, channel, message, strlen(message)) >= 0);
+ return;
+}
+
+
+static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node,
+ bool reachable) {
+ if(!strcasecmp(node->name, "corenode1")) {
+ if(reachable) {
+ fprintf(stderr, "\tNode corenode1 became reachable\n");
+ set_sync_flag(&peer_reachable, true);
+ }
+ } else if(!strcasecmp(node->name, "app1node1")) {
+ if(reachable) {
+ fprintf(stderr, "\tNode app1node1 became reachable\n");
+ set_sync_flag(&app_reachable, true);
+ }
+ }
+
+ return;
+}
+
+void mesh_start_test_handler(int a) {
+ fprintf(stderr, "Starting test in app1node2\n");
+ set_sync_flag(&start_test, true);
+}
+
+int main(int argc, char *argv[]) {
+ size_t num_nodes, i;
+ struct timeval main_loop_wait = { 2, 0 };
+ meshlink_channel_t *channel = NULL;
+ meshlink_node_t *core_node = NULL;
+ meshlink_node_t **node_handles = NULL;
+ ssize_t retvalue = -1;
+
+ fprintf(stderr, "\tMesh node 'app1node2' starting up........\n");
+
+ // Import mesh event handler
+
+ if((argv[CMD_LINE_ARG_CLIENTID]) && (argv[CMD_LINE_ARG_IMPORTSTR])) {
+ client_id = atoi(argv[CMD_LINE_ARG_CLIENTID]);
+ mesh_event_sock_connect(argv[CMD_LINE_ARG_IMPORTSTR]);
+ }
+
+ // Setup required signals
+
+ setup_signals();
+ signal(SIGIO, mesh_start_test_handler);
+
+ // Run peer node instance
+
+ mesh = meshlink_open("app1node2conf", argv[CMD_LINE_ARG_NODENAME],
+ "test_channel_conn", atoi(argv[CMD_LINE_ARG_DEVCLASS]));
+ assert(mesh);
+ meshlink_set_log_cb(mesh, MESHLINK_DEBUG, meshlink_callback_logger);
+ meshlink_set_channel_accept_cb(mesh, channel_accept);
+ meshlink_set_node_status_cb(mesh, node_status_cb);
+
+ if(argv[CMD_LINE_ARG_INVITEURL]) {
+ assert(meshlink_join(mesh, argv[CMD_LINE_ARG_INVITEURL]));
+ }
+
+ assert(meshlink_start(mesh));
+
+ send_event(NODE_STARTED);
+
+ // Wait for peer node to join
+
+ assert(wait_sync_flag(&peer_reachable, 15));
+ send_event(NODE_JOINED);
+
+ while(false == wait_sync_flag(&start_test, 10));
+
+ // Open a channel to peer node
+ core_node = meshlink_get_node(mesh, "corenode1");
+ assert(core_node);
+ fprintf(stderr, "\tapp1node2 Sending Channel request to corenode1 at : %lu\n", time(NULL));
+ channel = meshlink_channel_open(mesh, core_node, CHANNEL_PORT,
+ channel_receive_cb, NULL, 0);
+ meshlink_set_channel_poll_cb(mesh, channel, poll_cb);
+ assert(wait_sync_flag(&channel_opened, 15));
+ send_event(CHANNEL_OPENED);
+
+ assert(wait_sync_flag(&channel_data_recieved, 30));
+ send_event(CHANNEL_DATA_RECIEVED);
+
+ // Open a channel to peer node
+ channel_opened.flag = false;
+ channel_data_recieved.flag = false;
+
+ assert(wait_sync_flag(&app_reachable, 60));
+
+ core_node = meshlink_get_node(mesh, "app1node1");
+ assert(core_node);
+ fprintf(stderr, "\tapp1node2 Sending Channel request to app1node1 at : %lu\n", time(NULL));
+ channel = meshlink_channel_open(mesh, core_node, CHANNEL_PORT,
+ channel_receive_cb, NULL, 0);
+ meshlink_set_channel_poll_cb(mesh, channel, poll_cb);
+ assert(wait_sync_flag(&channel_opened, 15));
+ send_event(CHANNEL_OPENED);
+
+ assert(wait_sync_flag(&channel_data_recieved, 30));
+ send_event(CHANNEL_DATA_RECIEVED);
+
+ num_nodes = 0;
+ node_handles = meshlink_get_all_nodes(mesh, NULL, &num_nodes);
+ fprintf(stderr, "\tGot %lu nodes in list with error : %s\n", num_nodes, meshlink_strerror(meshlink_errno));
+ assert(node_handles);
+
+ for(i = 0; i < num_nodes; i++) {
+ fprintf(stderr, "\tChecking the node : %s\n", node_handles[i]->name);
+
+ if(0 == strcmp(node_handles[i]->name, "app2node1")) {
+ send_event(SIG_ABORT);
+ assert(false);
+ } else if(0 == strcmp(node_handles[i]->name, "app2node2")) {
+ send_event(SIG_ABORT);
+ assert(false);
+ }
+ }
+
+ meshlink_node_t *app1_node1 = meshlink_get_node(mesh, "app1node1");
+
+ if(!app1_node1) {
+ send_event(SIG_ABORT);
+ assert(app1_node1);
+ }
+
+ channel_data_recieved.flag = false;
+ meshlink_blacklist(mesh, app1_node1);
+
+ sleep(2);
+
+ meshlink_channel_send(mesh, ch_app1node1, "test", 5);
+
+ wait_sync_flag(&channel_data_recieved, 30);
+
+ if(true == channel_data_recieved.flag) {
+ send_event(SIG_ABORT);
+ assert(false);
+ }
+
+ channel_data_recieved.flag = false;
+ meshlink_whitelist(mesh, app1_node1);
+
+ sleep(2);
+
+ meshlink_channel_send(mesh, ch_app1node1, "Channel Message", strlen("Channel Message"));
+
+ assert(wait_sync_flag(&channel_data_recieved, 60));
+
+ send_event(MESH_EVENT_COMPLETED);
+
+ // All test steps executed - wait for signals to stop/start or close the mesh
+
+ while(test_running) {
+ select(1, NULL, NULL, NULL, &main_loop_wait);
+ }
+
+ meshlink_close(mesh);
+
+ return EXIT_SUCCESS;
+}
--- /dev/null
+/*
+ node_sim.c -- Implementation of Node Simulation for Meshlink Testing
+ for meta connection test case 01 - re-connection of
+ two nodes when relay node goes down
+ Copyright (C) 2018 Guus Sliepen <guus@meshlink.io>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <signal.h>
+#include "../common/common_handlers.h"
+#include "../common/test_step.h"
+#include "../common/mesh_event_handler.h"
+#include "../../utils.h"
+
+#define CMD_LINE_ARG_NODENAME 1
+#define CMD_LINE_ARG_DEVCLASS 2
+#define CMD_LINE_ARG_CLIENTID 3
+#define CMD_LINE_ARG_IMPORTSTR 4
+#define CMD_LINE_ARG_INVITEURL 5
+#define CHANNEL_PORT 1234
+
+static bool conn_status = false;
+static int client_id = -1;
+
+static struct sync_flag peer_reachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag channel_opened = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+static struct sync_flag channel_data_recieved = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .flag = false};
+
+static meshlink_handle_t *mesh = NULL;
+
+static void mesh_send_message_handler(char *destination);
+
+static void send_event(mesh_event_t event) {
+ int attempts;
+
+ for(attempts = 0; attempts < 5; attempts += 1) {
+ if(mesh_event_sock_send(client_id, event, NULL, 0)) {
+ break;
+ }
+ }
+
+ assert(attempts < 5);
+
+ return;
+}
+
+/* channel receive callback */
+static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) {
+ char data[100] = {0};
+
+ if(len == 0) {
+ send_event(ERR_NETWORK);
+ return;
+ }
+
+ memcpy(data, dat, len);
+
+ fprintf(stderr, "corenode1 got message from %s as %s\n", channel->node->name, data);
+
+ if(!memcmp(dat, "Channel Message", len)) {
+ mesh_send_message_handler((char *)channel->node->name);
+
+ if(0 == strcmp("app1node2", channel->node->name)) {
+ set_sync_flag(&channel_data_recieved, true);
+ }
+ } else if(!memcmp(dat, "failure", 7)) {
+ assert(false);
+ }
+
+ return;
+}
+
+static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node,
+ bool reachable) {
+ if(reachable) {
+ fprintf(stderr, "Node %s became reachable\n", node->name);
+ } else {
+ fprintf(stderr, "Node %s is unreachable\n", node->name);
+ }
+
+ return;
+}
+
+static void poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, size_t len) {
+ char *message = "Channel Message";
+ char *node = (char *)channel->node->name;
+ (void)len;
+ meshlink_set_channel_poll_cb(mesh, channel, NULL);
+ fprintf(stderr, "corenode1's Channel request has been accepted by %s at : %lu\n", node, time(NULL));
+
+ if(0 == strcmp("app1node2", node)) {
+ set_sync_flag(&channel_opened, true);
+ }
+
+ assert(meshlink_channel_send(mesh, channel, message, strlen(message)) >= 0);
+ return;
+}
+
+/* channel receive callback */
+static bool channel_accept(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *dat, size_t len) {
+ (void)dat;
+ (void)len;
+
+ assert(port == CHANNEL_PORT);
+
+ fprintf(stderr, "corenode1 got channel request from %s\n", channel->node->name);
+ meshlink_set_channel_receive_cb(mesh, channel, channel_receive_cb);
+
+ return true;
+}
+
+void mesh_send_message_handler(char *destination) {
+ meshlink_channel_t *channel = NULL;
+ meshlink_node_t *target_node = NULL;
+
+ // Open a channel to destination node
+ target_node = meshlink_get_node(mesh, destination);
+ assert(target_node);
+ fprintf(stderr, "corenode1 Sending Channel request to %s at : %lu\n", destination, time(NULL));
+ channel = meshlink_channel_open(mesh, target_node, CHANNEL_PORT,
+ channel_receive_cb, NULL, 0);
+ meshlink_set_channel_poll_cb(mesh, channel, poll_cb);
+}
+
+int main(int argc, char *argv[]) {
+ struct timeval main_loop_wait = { 5, 0 };
+ int i;
+
+ // Import mesh event handler
+
+ fprintf(stderr, "Mesh node 'corenode1' starting up........\n");
+
+ if((argv[CMD_LINE_ARG_CLIENTID]) && (argv[CMD_LINE_ARG_IMPORTSTR])) {
+ client_id = atoi(argv[CMD_LINE_ARG_CLIENTID]);
+ mesh_event_sock_connect(argv[CMD_LINE_ARG_IMPORTSTR]);
+ }
+
+ setup_signals();
+
+ // Execute test steps
+
+ mesh = meshlink_open("testconf", argv[CMD_LINE_ARG_NODENAME],
+ "test_channel_conn", atoi(argv[CMD_LINE_ARG_DEVCLASS]));
+ assert(mesh);
+ meshlink_set_log_cb(mesh, MESHLINK_DEBUG, meshlink_callback_logger);
+ meshlink_set_channel_accept_cb(mesh, channel_accept);
+ meshlink_set_node_status_cb(mesh, node_status_cb);
+
+ if(argv[CMD_LINE_ARG_INVITEURL]) {
+ assert(meshlink_join(mesh, argv[CMD_LINE_ARG_INVITEURL]));
+ }
+
+ assert(meshlink_start(mesh));
+
+ send_event(NODE_STARTED);
+
+ assert(wait_sync_flag(&channel_opened, 50));
+ send_event(CHANNEL_OPENED);
+
+ assert(wait_sync_flag(&channel_data_recieved, 50));
+ send_event(CHANNEL_DATA_RECIEVED);
+
+ // All test steps executed - wait for signals to stop/start or close the mesh
+
+ while(test_running) {
+ select(1, NULL, NULL, NULL, &main_loop_wait);
+ }
+
+ meshlink_close(mesh);
+
+ return 0;
+}
#define CMD_LINE_ARG_NODENAME 1
#define CMD_LINE_ARG_INVITEE 2
-
-void logger_cb(meshlink_handle_t *mesh, meshlink_log_level_t level,
- const char *text) {
- (void)mesh;
- (void)level;
-
- fprintf(stderr, "meshlink>> %s\n", text);
-}
+#define CMD_LINE_ARG_SUBMESH 3
int main(int argc, char *argv[]) {
char *invite = NULL;
+ meshlink_submesh_t *s = NULL;
/* Start mesh, generate an invite and print out the invite */
- /* Set up logging for Meshlink */
- meshlink_set_log_cb(NULL, MESHLINK_DEBUG, logger_cb);
-
- /* Create meshlink instance */
- meshlink_handle_t *mesh = meshlink_open("testconf", argv[1], "node_sim", DEV_CLASS_STATIONARY);
- assert(mesh);
-
- /* Set up logging for Meshlink with the newly acquired Mesh Handle */
- meshlink_set_log_cb(mesh, MESHLINK_DEBUG, logger_cb);
- meshlink_enable_discovery(mesh, false);
- assert(meshlink_start(mesh));
- invite = meshlink_invite_ex(mesh, NULL, argv[2], MESHLINK_INVITE_LOCAL | MESHLINK_INVITE_NUMERIC);
+ meshlink_handle_t *mesh = execute_open(argv[CMD_LINE_ARG_NODENAME], "1");
+ execute_start();
+
+ if(argc > CMD_LINE_ARG_SUBMESH) {
+ s = meshlink_submesh_open(mesh, argv[CMD_LINE_ARG_SUBMESH]);
+ }
+
+ invite = execute_invite(argv[CMD_LINE_ARG_INVITEE], s);
printf("%s\n", invite);
- meshlink_close(mesh);
+ execute_close();
return EXIT_SUCCESS;
}