test/Makefile
test/blackbox/Makefile
test/blackbox/run_blackbox_tests/Makefile
+ test/blackbox/test_case_channel_conn_01/Makefile
+ test/blackbox/test_case_channel_conn_02/Makefile
+ test/blackbox/test_case_channel_conn_03/Makefile
+ test/blackbox/test_case_channel_conn_04/Makefile
+ test/blackbox/test_case_channel_conn_05/Makefile
+ test/blackbox/test_case_channel_conn_06/Makefile
+ test/blackbox/test_case_channel_conn_07/Makefile
+ test/blackbox/test_case_channel_conn_08/Makefile
test/blackbox/test_case_meta_conn_01/Makefile
test/blackbox/test_case_meta_conn_02/Makefile
test/blackbox/test_case_meta_conn_03/Makefile
check_PROGRAMS = gen_invite
-
SUBDIRS = \
run_blackbox_tests \
+ test_case_channel_conn_01 \
+ test_case_channel_conn_02 \
+ test_case_channel_conn_03 \
+ test_case_channel_conn_04 \
+ test_case_channel_conn_05 \
+ test_case_channel_conn_06 \
+ test_case_channel_conn_07 \
+ test_case_channel_conn_08 \
test_case_meta_conn_01 \
test_case_meta_conn_02 \
test_case_meta_conn_03 \
test_case_meta_conn_04 \
test_case_meta_conn_05
+
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
gen_invite_CFLAGS = -D_GNU_SOURCE
#include "test_step.h"
#include "common_handlers.h"
+#define GET_IP_FAMILY AF_INET
+
char *lxc_bridge = NULL;
black_box_state_t *state_ptr = NULL;
bool meta_conn_status[10];
+bool node_reachable_status[10];
bool test_running;
-static int meshlink_get_node_in_container(const char *name) {
- int i;
-
- for(i = 0; i < state_ptr->num_nodes; i++) {
- if(!strcasecmp(state_ptr->node_names[i], name)) {
- return i;
- break;
- }
- }
-
- return -1;
-}
-
void mesh_close_signal_handler(int a) {
test_running = false;
exit(EXIT_SUCCESS);
}
+void mesh_stop_start_signal_handler(int a) {
+ /* Stop the Mesh if it is running, otherwise start it again */
+ (mesh_started) ? execute_stop() : execute_start();
+}
+
void setup_signals(void) {
test_running = true;
signal(SIGTERM, mesh_close_signal_handler);
+ signal(SIGINT, mesh_stop_start_signal_handler);
}
/* Return the IP Address of the Interface 'if_name'
family = ifa->ifa_addr->sa_family;
- if(family == AF_INET && !strcmp(ifa->ifa_name, if_name)) {
- assert(!getnameinfo(ifa->ifa_addr, (family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6), ip, NI_MAXHOST, NULL, 0, NI_NUMERICHOST));
+ if(family == GET_IP_FAMILY && !strcmp(ifa->ifa_name, if_name)) {
+ assert(!getnameinfo(ifa->ifa_addr, (family == GET_IP_FAMILY) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6), ip, NI_MAXHOST, NULL, 0, NI_NUMERICHOST));
break;
}
}
family = ifa->ifa_addr->sa_family;
- if(family == AF_INET && !strcmp(ifa->ifa_name, if_name)) {
- assert(!getnameinfo(ifa->ifa_netmask, (family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6), ip, NI_MAXHOST, NULL, 0, NI_NUMERICHOST));
+ if(family == GET_IP_FAMILY && !strcmp(ifa->ifa_name, if_name)) {
+ assert(!getnameinfo(ifa->ifa_netmask, (family == GET_IP_FAMILY) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6), ip, NI_MAXHOST, NULL, 0, NI_NUMERICHOST));
break;
}
}
void meshlink_callback_node_status(meshlink_handle_t *mesh, meshlink_node_t *node,
bool reachable) {
+ int i;
+
(void)mesh;
fprintf(stderr, "Node %s became %s\n", node->name, (reachable) ? "reachable" : "unreachable");
+
+ if(state_ptr)
+ for(i = 0; i < state_ptr->num_nodes; i++)
+ if(strcmp(node->name, state_ptr->node_names[i]) == 0) {
+ node_reachable_status[i] = reachable;
+ }
}
void meshlink_callback_logger(meshlink_handle_t *mesh, meshlink_log_level_t level,
const char *text) {
+ int i;
+ char connection_match_msg[100];
(void)mesh;
(void)level;
fprintf(stderr, "meshlink>> %s\n", text);
- if(state_ptr) {
- bool status;
- char name[100];
-
- if(sscanf(text, "Connection with %s activated", name) == 1) {
- status = true;
- } else if(sscanf(text, "Already connected to %s", name) == 1) {
- status = true;
- } else if(sscanf(text, "Connection closed by %s", name) == 1) {
- status = false;
- } else if(sscanf(text, "Closing connection with %s", name) == 1) {
- status = false;
- } else {
- return;
- }
+ if(state_ptr && (strstr(text, "Connection") || strstr(text, "connection"))) {
+ for(i = 0; i < state_ptr->num_nodes; i++) {
+ assert(snprintf(connection_match_msg, sizeof(connection_match_msg),
+ "Connection with %s", state_ptr->node_names[i]) >= 0);
+
+ if(strstr(text, connection_match_msg) && strstr(text, "activated")) {
+ meta_conn_status[i] = true;
+ continue;
+ }
+
+ assert(snprintf(connection_match_msg, sizeof(connection_match_msg),
+ "Already connected to %s", state_ptr->node_names[i]) >= 0);
- int i = meshlink_get_node_in_container(name);
- assert(i != -1);
- meta_conn_status[i] = status;
+ if(strstr(text, connection_match_msg)) {
+ meta_conn_status[i] = true;
+ continue;
+ }
+
+ assert(snprintf(connection_match_msg, sizeof(connection_match_msg),
+ "Connection closed by %s", state_ptr->node_names[i]) >= 0);
+
+ if(strstr(text, connection_match_msg)) {
+ meta_conn_status[i] = false;
+ continue;
+ }
+
+ assert(snprintf(connection_match_msg, sizeof(connection_match_msg),
+ "Closing connection with %s", state_ptr->node_names[i]) >= 0);
+
+ if(strstr(text, connection_match_msg)) {
+ meta_conn_status[i] = false;
+ continue;
+ }
+ }
}
}
void meshlink_callback_logger(meshlink_handle_t *mesh, meshlink_log_level_t level,
const char *text);
+void change_ip(int node);
+void create_bridge(const char *bridgeName);
+void add_interface(const char *bridgeName, const char *interfaceName);
+void add_veth_pair(const char *vethName1, const char *vethName2);
+void bring_if_up(const char *bridgeName);
+void replaceAll(char *str, const char *oldWord, const char *newWord);
+void switch_bridge(const char *containerName, const char *currentBridge, const char *newBridge);
+void bring_if_down(const char *bridgeName);
+void del_interface(const char *bridgeName, const char *interfaceName);
+void delete_bridge(const char *bridgeName);
+void create_container_on_bridge(const char *containerName, const char *bridgeName, const char *ifName);
+void config_dnsmasq(const char *containerName, const char *ifName, const char *listenAddress, const char *dhcpRange);
+void config_nat(const char *containerName, const char *listenAddress);
+void create_nat_layer(const char *containerName, const char *bridgeName, const char *ifName, const char *listenAddress, char *dhcpRange);
+void destroy_nat_layer(const char *containerName, const char *bridgeName);
+void incoming_firewall_ipv4(const char *packetType, int portNumber);
+void incoming_firewall_ipv6(const char *packetType, int portNumber);
+void outgoing_firewall_ipv4(const char *packetType, int portNumber);
+void outgoing_firewall_ipv6(const char *packetType, int portNumber);
+
#endif // COMMON_HANDLERS_H
test_containers[i]->stop(test_containers[i]);
/* Destroy the Container */
test_containers[i]->destroy(test_containers[i]);
- /* call destroy_with_snapshots() in case destroy() fails
+ /* Call destroy_with_snapshots() in case destroy() fails
one of these two calls will always succeed */
test_containers[i]->destroy_with_snapshots(test_containers[i]);
}
PRINT_TEST_CASE_MSG("node_sim_%s started in Container\n", node);
}
-/* Run the node_sim_<nodename> program inside the 'node''s container with event handling capable*/
+/* Run the node_sim_<nodename> program inside the 'node''s container with event handling capable */
void node_sim_in_container_event(const char *node, const char *device_class,
const char *invite_url, const char *clientId, const char *import) {
char node_sim_command[200];
run_in_container(node_sim_command, node, true);
PRINT_TEST_CASE_MSG("node_sim_%s(Client Id :%s) started in Container with event handling\n",
node, clientId);
- PRINT_TEST_CASE_MSG("node_sim_%s mesh event import string : %s\n",
- node, import);
}
/* Run the node_step.sh script inside the 'node''s container to send the 'sig' signal to the
PRINT_TEST_CASE_MSG("Node '%s' IP Address changed to %s\n", state_ptr->node_names[node],
container_ips[node]);
}
+
+/* Return container's IP address */
+char *get_container_ip(const char *node_name) {
+ char *ip;
+ int n, node = -1, i;
+
+ for(i = 0; i < state_ptr->num_nodes; i++) {
+ if(!strcasecmp(state_ptr->node_names[i], node_name)) {
+ node = i;
+ break;
+ }
+ }
+
+ if(i == state_ptr->num_nodes) {
+ return NULL;
+ }
+
+ n = strlen(container_ips[node]) + 1;
+ ip = malloc(n);
+ assert(ip);
+ strncpy(ip, container_ips[node], n);
+
+ return ip;
+}
+
+/* Install an app in a container */
+void install_in_container(const char *node, const char *app) {
+ char install_cmd[100];
+
+ assert(snprintf(install_cmd, sizeof(install_cmd),
+ "apt-get install %s -y >> /dev/null", app) >= 0);
+ char *ret = run_in_container(install_cmd, node, false);
+ // TODO: Check in container whether app has installed or not with a timeout
+ sleep(10);
+}
+
+/* Simulate a network failure by adding NAT rule in the container with it's IP address */
+void block_node_ip(const char *node) {
+ char block_cmd[100];
+ char *node_ip;
+
+ node_ip = get_container_ip(node);
+ assert(node_ip);
+ assert(snprintf(block_cmd, sizeof(block_cmd), "iptables -A OUTPUT -p all -s %s -j DROP", node_ip) >= 0);
+ run_in_container(block_cmd, node, false);
+
+ assert(snprintf(block_cmd, sizeof(block_cmd), "iptables -A INPUT -p all -s %s -j DROP", node_ip) >= 0);
+ run_in_container(block_cmd, node, false);
+
+ assert(snprintf(block_cmd, sizeof(block_cmd), "iptables -A FORWARD -p all -s %s -j DROP", node_ip) >= 0);
+ run_in_container(block_cmd, node, false);
+
+ free(node_ip);
+}
+
+void accept_port_rule(const char *node, const char *chain, const char *protocol, int port) {
+ char block_cmd[100];
+
+ assert(port >= 0 && port < 65536);
+ assert(!strcmp(chain, "INPUT") || !strcmp(chain, "FORWARD") || !strcmp(chain, "OUTPUT"));
+ assert(!strcmp(protocol, "all") || !strcmp(protocol, "tcp") || !strcmp(protocol, "udp"));
+ assert(snprintf(block_cmd, sizeof(block_cmd), "iptables -A %s -p %s --dport %d -j ACCEPT", chain, protocol, port) >= 0);
+ run_in_container(block_cmd, node, false);
+}
+
+/* Restore the network that was blocked before by the NAT rule with it's own IP address */
+void unblock_node_ip(const char *node) {
+ char unblock_cmd[100];
+ char *node_ip;
+
+ node_ip = get_container_ip(node);
+ assert(node_ip);
+ assert(snprintf(unblock_cmd, sizeof(unblock_cmd), "iptables -D OUTPUT -p all -s %s -j DROP", node_ip) >= 0);
+ run_in_container(unblock_cmd, node, false);
+
+ assert(snprintf(unblock_cmd, sizeof(unblock_cmd), "iptables -D INPUT -p all -s %s -j DROP", node_ip) >= 0);
+ run_in_container(unblock_cmd, node, false);
+
+ assert(snprintf(unblock_cmd, sizeof(unblock_cmd), "iptables -D FORWARD -p all -s %s -j DROP", node_ip) >= 0);
+ run_in_container(unblock_cmd, node, false);
+}
+
+/* Takes bridgeName as input parameter and creates a bridge */
+void create_bridge(const char *bridgeName) {
+ char command[100] = "brctl addbr ";
+ strcat(command, bridgeName);
+ int create_bridge_status = system(command);
+ assert(create_bridge_status == 0);
+ PRINT_TEST_CASE_MSG("%s bridge created\n", bridgeName);
+}
+
+/* Add interface for the bridge created */
+void add_interface(const char *bridgeName, const char *interfaceName) {
+ char command[100] = "brctl addif ";
+ char cmd[100] = "dhclient ";
+
+ strcat(command, bridgeName);
+ strcat(command, " ");
+ strcat(command, interfaceName);
+ int addif_status = system(command);
+ assert(addif_status == 0);
+ strcat(cmd, bridgeName);
+ int dhclient_status = system(cmd);
+ assert(dhclient_status == 0);
+ PRINT_TEST_CASE_MSG("Added interface for %s\n", bridgeName);
+}
+
+/* Create a veth pair and bring them up */
+void add_veth_pair(const char *vethName1, const char *vethName2) {
+ char command[100] = "ip link add ";
+ char upCommand1[100] = "ip link set ";
+ char upCommand2[100] = "ip link set ";
+
+ strcat(command, vethName1);
+ strcat(command, " type veth peer name ");
+ strcat(command, vethName2);
+ int link_add_status = system(command);
+ assert(link_add_status == 0);
+ strcat(upCommand1, vethName1);
+ strcat(upCommand1, " up");
+ int link_set_veth1_status = system(upCommand1);
+ assert(link_set_veth1_status == 0);
+ strcat(upCommand2, vethName2);
+ strcat(upCommand2, " up");
+ int link_set_veth2_status = system(upCommand2);
+ assert(link_set_veth2_status == 0);
+ PRINT_TEST_CASE_MSG("Added veth pairs %s and %s\n", vethName1, vethName2);
+}
+
+/* Bring the interface up for the bridge created */
+void bring_if_up(const char *bridgeName) {
+ char command[300] = "ifconfig ";
+ char dhcommand[300] = "dhclient ";
+ strcat(command, bridgeName);
+ strcat(command, " up");
+ int if_up_status = system(command);
+ assert(if_up_status == 0);
+ sleep(2);
+ PRINT_TEST_CASE_MSG("Interface brought up for %s created\n", bridgeName);
+}
+
+/**
+ * Replace all occurrences of a given a word in string.
+ */
+void replaceAll(char *str, const char *oldWord, const char *newWord) {
+ char *pos, temp[BUFSIZ];
+ int index = 0;
+ int owlen;
+ owlen = strlen(oldWord);
+
+ while((pos = strstr(str, oldWord)) != NULL) {
+ strcpy(temp, str);
+ index = pos - str;
+ str[index] = '\0';
+ strcat(str, newWord);
+ strcat(str, temp + index + owlen);
+ }
+}
+
+/* Switches the bridge for a given container */
+void switch_bridge(const char *containerName, const char *currentBridge, const char *newBridge) {
+ char command[100] = "lxc-stop -n ";
+ char command_start[100] = "lxc-start -n ";
+ PRINT_TEST_CASE_MSG("Switching %s container to %s\n", containerName, newBridge);
+ strcat(command, containerName);
+ strcat(command_start, containerName);
+ int container_stop_status = system(command);
+ assert(container_stop_status == 0);
+ sleep(2);
+ FILE *fPtr;
+ FILE *fTemp;
+ char path[300] = "/var/lib/lxc/";
+ strcat(path, containerName);
+ strcat(path, "/config");
+
+ char buffer[BUFSIZ];
+ /* Open all required files */
+ fPtr = fopen(path, "r");
+ fTemp = fopen("replace.tmp", "w");
+
+ if(fPtr == NULL || fTemp == NULL) {
+ PRINT_TEST_CASE_MSG("\nUnable to open file.\n");
+ PRINT_TEST_CASE_MSG("Please check whether file exists and you have read/write privilege.\n");
+ exit(EXIT_SUCCESS);
+ }
+
+ while((fgets(buffer, BUFSIZ, fPtr)) != NULL) {
+ replaceAll(buffer, currentBridge, newBridge);
+ fputs(buffer, fTemp);
+ }
+
+ fclose(fPtr);
+ fclose(fTemp);
+ remove(path);
+ rename("replace.tmp", path);
+ PRINT_TEST_CASE_MSG("Switching procedure done successfully\n");
+ int container_start_status = system(command_start);
+ assert(container_start_status == 0);
+ sleep(2);
+}
+
+/* Bring the interface down for the bridge created */
+void bring_if_down(const char *bridgeName) {
+ char command[300] = "ip link set dev ";
+ strcat(command, bridgeName);
+ strcat(command, " down");
+ int if_down_status = system(command);
+ assert(if_down_status == 0);
+ PRINT_TEST_CASE_MSG("Interface brought down for %s created\n", bridgeName);
+}
+
+/* Delete interface for the bridge created */
+void del_interface(const char *bridgeName, const char *interfaceName) {
+ char command[300] = "brctl delif ";
+ strcat(command, bridgeName);
+ strcat(command, interfaceName);
+ int if_delete_status = system(command);
+ assert(if_delete_status == 0);
+ PRINT_TEST_CASE_MSG("Deleted interface for %s\n", bridgeName);
+}
+
+/* Takes bridgeName as input parameter and deletes a bridge */
+void delete_bridge(const char *bridgeName) {
+ bring_if_down(bridgeName);
+ char command[300] = "brctl delbr ";
+ strcat(command, bridgeName);
+ int bridge_delete = system(command);
+ assert(bridge_delete == 0);
+ PRINT_TEST_CASE_MSG("%s bridge deleted\n", bridgeName);
+ sleep(2);
+}
+
+/* Creates container on a specified bridge with added interface */
+void create_container_on_bridge(const char *containerName, const char *bridgeName, const char *ifName) {
+ char command[100] = "lxc-create -t download -n ";
+ char cmd[100] = " -- -d ubuntu -r trusty -a ";
+ char start[100] = "lxc-start -n ";
+ FILE *fPtr;
+ char path[300] = "/var/lib/lxc/";
+ strcat(path, containerName);
+ strcat(path, "/config");
+ strcat(command, containerName);
+ strcat(command, cmd);
+ strcat(command, choose_arch);
+ int container_create_status = system(command);
+ assert(container_create_status == 0);
+ sleep(3);
+ assert(fPtr = fopen(path, "a+"));
+ fprintf(fPtr, "lxc.net.0.name = eth0\n");
+ fprintf(fPtr, "\n");
+ fprintf(fPtr, "lxc.net.1.type = veth\n");
+ fprintf(fPtr, "lxc.net.1.flags = up\n");
+ fprintf(fPtr, "lxc.net.1.link = %s\n", bridgeName);
+ fprintf(fPtr, "lxc.net.1.name = %s\n", ifName);
+ fprintf(fPtr, "lxc.net.1.hwaddr = 00:16:3e:ab:xx:xx\n");
+ fclose(fPtr);
+ strcat(start, containerName);
+ int container_start_status = system(start);
+ assert(container_start_status == 0);
+ sleep(3);
+ PRINT_TEST_CASE_MSG("Created %s on %s with interface name %s\n", containerName, bridgeName, ifName);
+}
+
+/* Configures dnsmasq and iptables for the specified container with inputs of listen address and dhcp range */
+void config_dnsmasq(const char *containerName, const char *ifName, const char *listenAddress, const char *dhcpRange) {
+ char command[500] = "echo \"apt-get install dnsmasq iptables -y\" | lxc-attach -n ";
+ strcat(command, containerName);
+ strcat(command, " --");
+ int iptables_install_status = system(command);
+ assert(iptables_install_status == 0);
+ sleep(5);
+ char com1[300] = "echo \"echo \"interface=eth1\" >> /etc/dnsmasq.conf\" | lxc-attach -n ";
+ strcat(com1, containerName);
+ strcat(com1, " --");
+ int dnsmasq_status = system(com1);
+ assert(dnsmasq_status == 0);
+ sleep(5);
+ char com2[300] = "echo \"echo \"bind-interfaces\" >> /etc/dnsmasq.conf\" | lxc-attach -n ";
+ strcat(com2, containerName);
+ strcat(com2, " --");
+ dnsmasq_status = system(com2);
+ assert(dnsmasq_status == 0);
+ sleep(5);
+ char com3[300] = "echo \"echo \"listen-address=";
+ strcat(com3, listenAddress);
+ strcat(com3, "\" >> /etc/dnsmasq.conf\" | lxc-attach -n ");
+ strcat(com3, containerName);
+ strcat(com3, " --");
+ dnsmasq_status = system(com3);
+ assert(dnsmasq_status == 0);
+ sleep(5);
+ char com4[300] = "echo \"echo \"dhcp-range=";
+ strcat(com4, dhcpRange);
+ strcat(com4, "\" >> /etc/dnsmasq.conf\" | lxc-attach -n ");
+ strcat(com4, containerName);
+ strcat(com4, " --");
+ dnsmasq_status = system(com4);
+ assert(dnsmasq_status == 0);
+ sleep(5);
+ char cmd[300] = "echo \"ifconfig ";
+ strcat(cmd, ifName);
+ strcat(cmd, " ");
+ strcat(cmd, listenAddress);
+ strcat(cmd, " netmask 255.255.255.0 up\" | lxc-attach -n ");
+ strcat(cmd, containerName);
+ strcat(cmd, " --");
+ dnsmasq_status = system(cmd);
+ assert(dnsmasq_status == 0);
+ sleep(2);
+ char com[500] = "echo \"service dnsmasq restart >> /dev/null\" | lxc-attach -n ";
+ strcat(com, containerName);
+ strcat(com, " --");
+ dnsmasq_status = system(com);
+ assert(dnsmasq_status == 0);
+ sleep(2);
+ PRINT_TEST_CASE_MSG("Configured dnsmasq in %s with interface name %s, listen-address = %s, dhcp-range = %s\n", containerName, ifName, listenAddress, dhcpRange);
+}
+
+/* Configure the NAT rules inside the container */
+void config_nat(const char *containerName, const char *listenAddress) {
+ char *last_dot_in_ip;
+ int last_ip_byte = 0;
+ char new_ip[300] = {0};
+ strncpy(new_ip, listenAddress, sizeof(new_ip));
+ assert(last_dot_in_ip = strrchr(new_ip, '.'));
+ assert(snprintf(last_dot_in_ip + 1, 4, "%d", last_ip_byte) >= 0);
+ char comd[300] = "echo \"iptables -t nat -A POSTROUTING -s ";
+ strcat(comd, new_ip);
+ strcat(comd, "/24 ! -d ");
+ strcat(comd, new_ip);
+ strcat(comd, "/24 -j MASQUERADE\" | lxc-attach -n ");
+ strcat(comd, containerName);
+ strcat(comd, " --");
+ int conf_nat_status = system(comd);
+ assert(conf_nat_status == 0);
+ sleep(2);
+ PRINT_TEST_CASE_MSG("Configured NAT on %s\n", containerName);
+}
+
+/* Creates a NAT layer on a specified bridge with certain dhcp range to allocate ips for nodes */
+void create_nat_layer(const char *containerName, const char *bridgeName, const char *ifName, const char *listenAddress, char *dhcpRange) {
+ create_bridge(bridgeName);
+ bring_if_up(bridgeName);
+ create_container_on_bridge(containerName, bridgeName, ifName);
+ config_dnsmasq(containerName, ifName, listenAddress, dhcpRange);
+ config_nat(containerName, listenAddress);
+ PRINT_TEST_CASE_MSG("NAT layer created with %s\n", containerName);
+}
+
+/* Destroys the NAT layer created */
+void destroy_nat_layer(const char *containerName, const char *bridgeName) {
+ bring_if_down(bridgeName);
+ delete_bridge(bridgeName);
+ char command[100] = "lxc-stop -n ";
+ strcat(command, containerName);
+ int container_stop_status = system(command);
+ assert(container_stop_status == 0);
+ char destroy[100] = "lxc-destroy -n ";
+ strcat(destroy, containerName);
+ strcat(destroy, " -s");
+ int container_destroy_status = system(destroy);
+ assert(container_destroy_status == 0);
+ PRINT_TEST_CASE_MSG("NAT layer destroyed with %s\n", containerName);
+}
+
+/* Add incoming firewall rules for ipv4 addresses with packet type and port number */
+void incoming_firewall_ipv4(const char *packetType, int portNumber) {
+ char buf[5];
+ snprintf(buf, sizeof(buf), "%d", portNumber);
+ assert(system("iptables -F") == 0);
+ assert(system("iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT") == 0);
+ assert(system("iptables -A INPUT -s 127.0.0.1 -d 127.0.0.1 -j ACCEPT") == 0);
+ char command[100] = "iptables -A INPUT -p ";
+ strcat(command, packetType);
+ strcat(command, " --dport ");
+ strcat(command, buf);
+ strcat(command, " -j ACCEPT");
+ assert(system(command) == 0);
+ sleep(2);
+ assert(system("iptables -A INPUT -j DROP") == 0);
+ PRINT_TEST_CASE_MSG("Firewall for incoming requests added on IPv4");
+ assert(system("iptables -L") == 0);
+}
+
+/* Add incoming firewall rules for ipv6 addresses with packet type and port number */
+void incoming_firewall_ipv6(const char *packetType, int portNumber) {
+ char buf[5];
+ snprintf(buf, sizeof(buf), "%d", portNumber);
+ assert(system("ip6tables -F") == 0);
+ assert(system("ip6tables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT") == 0);
+ assert(system("ip6tables -A INPUT -s ::1 -d ::1 -j ACCEPT") == 0);
+ char command[100] = "ip6tables -A INPUT -p ";
+ strcat(command, packetType);
+ strcat(command, " --dport ");
+ strcat(command, buf);
+ strcat(command, " -j ACCEPT");
+ assert(system(command) == 0);
+ sleep(2);
+ assert(system("ip6tables -A INPUT -j DROP") == 0);
+ PRINT_TEST_CASE_MSG("Firewall for incoming requests added on IPv6");
+ assert(system("ip6tables -L") == 0);
+}
+
+/* Add outgoing firewall rules for ipv4 addresses with packet type and port number */
+void outgoing_firewall_ipv4(const char *packetType, int portNumber) {
+ char buf[5];
+ snprintf(buf, sizeof(buf), "%d", portNumber);
+ assert(system("iptables -F") == 0);
+ assert(system("iptables -A OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT") == 0);
+ assert(system("iptables -A OUTPUT -s 127.0.0.1 -d 127.0.0.1 -j ACCEPT") == 0);
+ char command[100] = "iptables -A OUTPUT -p ";
+ strcat(command, packetType);
+ strcat(command, " --dport ");
+ strcat(command, buf);
+ strcat(command, " -j ACCEPT");
+ assert(system(command) == 0);
+ sleep(2);
+ assert(system("iptables -A OUTPUT -j DROP") == 0);
+ PRINT_TEST_CASE_MSG("Firewall for outgoing requests added on IPv4");
+ assert(system("iptables -L") == 0);
+}
+
+/* Add outgoing firewall rules for ipv6 addresses with packet type and port number */
+void outgoing_firewall_ipv6(const char *packetType, int portNumber) {
+ char buf[5];
+ snprintf(buf, sizeof(buf), "%d", portNumber);
+ assert(system("ip6tables -F") == 0);
+ assert(system("ip6tables -A OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT") == 0);
+ assert(system("ip6tables -A OUTPUT -s ::1 -d ::1 -j ACCEPT") == 0);
+ char command[100] = "ip6tables -A OUTPUT -p ";
+ strcat(command, packetType);
+ strcat(command, " --dport ");
+ strcat(command, buf);
+ strcat(command, " -j ACCEPT");
+ assert(system(command) == 0);
+ sleep(2);
+ assert(system("ip6tables -A OUTPUT -j DROP") == 0);
+ PRINT_TEST_CASE_MSG("Firewall for outgoing requests added on IPv6");
+ assert(system("ip6tables -L") == 0);
+}
extern char *lxc_path;
-struct lxc_container *find_container(const char *name);
-void rename_container(const char *old_name, const char *new_name);
-char *run_in_container(const char *cmd, const char *node, bool daemonize);
-void container_wait_ip(int node);
-void create_containers(const char *node_names[], int num_nodes);
-void setup_containers(void **state);
-void destroy_containers(void);
-void restart_all_containers(void);
-char *invite_in_container(const char *inviter, const char *invitee);
-void node_sim_in_container(const char *node, const char *device_class, const char *invite_url);
-void node_sim_in_container_event(const char *node, const char *device_class,
- const char *invite_url, const char *clientId, const char *import);
-void node_step_in_container(const char *node, const char *sig);
-void change_ip(int node);
-
-char *get_container_ip(int node);
+extern struct lxc_container *find_container(const char *name);
+extern void rename_container(const char *old_name, const char *new_name);
+extern char *run_in_container(const char *cmd, const char *node, bool daemonize);
+extern void container_wait_ip(int node);
+extern void create_containers(const char *node_names[], int num_nodes);
+extern void setup_containers(void **state);
+extern void destroy_containers(void);
+extern void restart_all_containers(void);
+extern char *invite_in_container(const char *inviter, const char *invitee);
+extern void node_sim_in_container(const char *node, const char *device_class, const char *invite_url);
+extern void node_sim_in_container_event(const char *node, const char *device_class,
+ const char *invite_url, const char *clientId, const char *import);
+extern void node_step_in_container(const char *node, const char *sig);
+extern void change_ip(int node);
+
+extern char *get_container_ip(const char *node_name);
+extern void install_in_container(const char *node, const char *app);
+extern void unblock_node_ip(const char *node);
+extern void block_node_ip(const char *node);
+void accept_port_rule(const char *node, const char *chain, const char *protocol, int port);
#endif // CONTAINERS_H
test_cases_channel_open.c \
test_cases_channel_close.c \
test_cases_channel_send.c \
- test_cases_channel_shutdown.c
+ test_cases_channel_shutdown.c \
+ test_cases_channel_conn.c
run_blackbox_tests_LDADD = ../../../src/libmeshlink.la -llxc -lcmocka
run_blackbox_tests_CFLAGS = -D_GNU_SOURCE
for(i = 0; i < state_ptr->num_nodes; i++) {
meta_conn_status[i] = false;
+ node_reachable_status[i] = false;
}
setup_containers(state);
#include "test_cases_channel_set_poll_cb.h"
#include "test_cases_channel_set_receive_cb.h"
#include "test_cases_hint_address.h"
+
+#include "test_cases_channel_conn.h"
+
#include "../common/containers.h"
#include "../common/common_handlers.h"
failed_tests += test_meshlink_channel_open();
failed_tests += test_meshlink_channel_close();
+ failed_tests += test_meshlink_channel_conn();
+
printf("[ PASSED ] %d test(s).\n", total_tests - failed_tests);
printf("[ FAILED ] %d test(s).\n", failed_tests);
--- /dev/null
+/*
+ test_cases_channel_conn.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 <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <setjmp.h>
+#include <pthread.h>
+#include <cmocka.h>
+#include "execute_tests.h"
+#include "test_cases_channel_conn.h"
+#include "../common/containers.h"
+#include "../common/test_step.h"
+#include "../common/common_handlers.h"
+#include "../common/mesh_event_handler.h"
+
+#define PEER_ID "0"
+#define NUT_ID "1"
+#define RELAY_ID "2"
+
+static void test_case_channel_conn_01(void **state);
+static bool test_steps_channel_conn_01(void);
+static void test_case_channel_conn_02(void **state);
+static bool test_steps_channel_conn_02(void);
+static void test_case_channel_conn_03(void **state);
+static bool test_steps_channel_conn_03(void);
+static void test_case_channel_conn_04(void **state);
+static bool test_steps_channel_conn_04(void);
+static void test_case_channel_conn_05(void **state);
+static bool test_steps_channel_conn_05(void);
+static void test_case_channel_conn_06(void **state);
+static bool test_steps_channel_conn_06(void);
+static void test_case_channel_conn_07(void **state);
+static bool test_steps_channel_conn_07(void);
+static void test_case_channel_conn_08(void **state);
+static bool test_steps_channel_conn_08(void);
+
+static char *test_channel_conn_2_nodes[] = { "peer", "nut" };
+static char *test_channel_conn_3_nodes[] = { "peer", "nut", "relay" };
+
+static black_box_state_t test_case_channel_conn_01_state = {
+ .test_case_name = "test_case_channel_conn_01",
+ .node_names = test_channel_conn_2_nodes,
+ .num_nodes = 2,
+};
+static black_box_state_t test_case_channel_conn_02_state = {
+ .test_case_name = "test_case_channel_conn_02",
+ .node_names = test_channel_conn_2_nodes,
+ .num_nodes = 2,
+};
+static black_box_state_t test_case_channel_conn_03_state = {
+ .test_case_name = "test_case_channel_conn_03",
+ .node_names = test_channel_conn_2_nodes,
+ .num_nodes = 2,
+};
+static black_box_state_t test_case_channel_conn_04_state = {
+ .test_case_name = "test_case_channel_conn_04",
+ .node_names = test_channel_conn_2_nodes,
+ .num_nodes = 2,
+};
+static black_box_state_t test_case_channel_conn_05_state = {
+ .test_case_name = "test_case_channel_conn_05",
+ .node_names = test_channel_conn_3_nodes,
+ .num_nodes = 3,
+};
+static black_box_state_t test_case_channel_conn_06_state = {
+ .test_case_name = "test_case_channel_conn_06",
+ .node_names = test_channel_conn_3_nodes,
+ .num_nodes = 3,
+};
+static black_box_state_t test_case_channel_conn_07_state = {
+ .test_case_name = "test_case_channel_conn_07",
+ .node_names = test_channel_conn_3_nodes,
+ .num_nodes = 3,
+};
+static black_box_state_t test_case_channel_conn_08_state = {
+ .test_case_name = "test_case_channel_conn_08",
+ .node_names = test_channel_conn_3_nodes,
+ .num_nodes = 3,
+};
+
+static bool joined;
+static bool channel_opened;
+static bool node_restarted;
+static bool received_error;
+static bool channel_received;
+static bool node_reachable;
+static bool node_unreachable;
+
+/* Callback function for handling channel connection test cases mesh events */
+static void channel_conn_cb(mesh_event_payload_t payload) {
+ switch(payload.mesh_event) {
+ case NODE_JOINED :
+ joined = true;
+ break;
+
+ case CHANNEL_OPENED :
+ channel_opened = true;
+ break;
+
+ case NODE_RESTARTED :
+ node_restarted = true;
+ break;
+
+ case ERR_NETWORK :
+ received_error = true;
+ break;
+
+ case CHANNEL_DATA_RECIEVED :
+ channel_received = true;
+ break;
+
+ case NODE_UNREACHABLE :
+ node_unreachable = true;
+ break;
+
+ case NODE_REACHABLE :
+ node_reachable = true;
+ break;
+
+ default :
+ PRINT_TEST_CASE_MSG("Undefined event occurred\n");
+ }
+
+ return;
+}
+
+/* Execute channel connections Test Case # 1 - simulate a temporary network
+ failure of about 30 seconds, messages sent while the network was down
+ should be received by the other side after the network comes up again. */
+static void test_case_channel_conn_01(void **state) {
+ execute_test(test_steps_channel_conn_01, state);
+ return;
+}
+
+/* Test Steps for channel connections Test Case # 1
+
+ Test Steps:
+ 1. Run NUT & peer node instances and open a channel between them
+ 2. Simulate a network failure in NUT's container for about 30 secs,
+ meanwhile send data via channel from NUT to peer.
+ 3. After restoring network, peer node receive's data via channel.
+
+ Expected Result:
+ Peer node receives data via channel without any error after restoring network.
+*/
+static bool test_steps_channel_conn_01(void) {
+ char *invite_nut;
+ char *import;
+
+ joined = false;
+ channel_opened = false;
+ channel_received = false;
+
+ // Setup Containers
+
+ install_in_container("nut", "iptables");
+ accept_port_rule("nut", "OUTPUT", "udp", 9000);
+ import = mesh_event_sock_create(eth_if_name);
+ invite_nut = invite_in_container("peer", "nut");
+ assert(invite_nut);
+
+ // Run node instances in containers & open a channel
+
+ node_sim_in_container_event("peer", "1", NULL, PEER_ID, import);
+ node_sim_in_container_event("nut", "1", invite_nut, NUT_ID, import);
+
+ wait_for_event(channel_conn_cb, 30);
+ assert_int_equal(joined, true);
+
+ wait_for_event(channel_conn_cb, 30);
+ assert_int_equal(channel_opened, true);
+
+ // Simulate network failure in NUT's LXC container with it's IP address as NAT rule
+
+ block_node_ip("nut");
+ sleep(2);
+
+ // Sending SIGUSR1 signal to node-under-test indicating the network failure
+
+ node_step_in_container("nut", "SIGUSR1");
+ sleep(30);
+
+ // Restore NUT's network
+
+ unblock_node_ip("nut");
+
+ // Wait for peer node to receive data via channel from NUT
+
+ wait_for_event(channel_conn_cb, 60);
+ assert_int_equal(channel_received, true);
+
+ free(invite_nut);
+ free(import);
+ return true;
+}
+
+/* Execute channel connections Test Case # 2 - a simulated network failure
+ of more than 1 minute, and sending messages over the channel during the
+ failure. Then after about 1 minute, the channel should receive an error */
+static void test_case_channel_conn_02(void **state) {
+ execute_test(test_steps_channel_conn_02, state);
+ return;
+}
+
+/* Test Steps for channel connections Test Case # 2
+
+ Test Steps:
+ 1. Run NUT and peer node instances in containers and open a channel between them.
+ 2. Create a network failure for about 90 secs in NUT container
+ and signal NUT node about the network failure.
+ 3. Meanwhile NUT sends data to peer via channel and restore the network after
+ 90 secs.
+
+ Expected Result:
+ Peer node should receive error closing the channel after channel timeout(60 secs).
+*/
+static bool test_steps_channel_conn_02(void) {
+ char *invite_nut;
+ char *import;
+
+ joined = false;
+ channel_opened = false;
+ received_error = false;
+
+ // Setup containers
+
+ install_in_container("nut", "iptables");
+ accept_port_rule("nut", "OUTPUT", "udp", 9000);
+ import = mesh_event_sock_create(eth_if_name);
+ invite_nut = invite_in_container("peer", "nut");
+ assert(invite_nut);
+
+ // Run NUT and peer node instances in containers & open a channel
+
+ node_sim_in_container_event("peer", "1", NULL, PEER_ID, import);
+ node_sim_in_container_event("nut", "1", invite_nut, NUT_ID, import);
+
+ wait_for_event(channel_conn_cb, 30);
+ assert_int_equal(joined, true);
+
+ wait_for_event(channel_conn_cb, 10);
+ assert_int_equal(channel_opened, true);
+
+ // Simulate network failure in NUT's LXC container with it's IP address as NAT rule
+
+ block_node_ip("nut");
+
+ // Sending SIGUSR1 signal to node-under-test indicating the network failure
+
+ node_step_in_container("nut", "SIGUSR1");
+ sleep(90);
+
+ // Restore NUT containers network after 90 secs
+
+ unblock_node_ip("nut");
+
+ // Wait for peer node to send the event about the channel error occurred with length = 0
+
+ wait_for_event(channel_conn_cb, 90);
+ assert_int_equal(received_error, true);
+
+ free(invite_nut);
+ free(import);
+ return true;
+}
+
+/* Execute channel connections Test Case # 3 - a simulated network failure
+ once node instance is made offline restore the network and send data via
+ channel */
+static void test_case_channel_conn_03(void **state) {
+ execute_test(test_steps_channel_conn_03, state);
+ return;
+}
+
+/* Test Steps for channel connections Test Case # 3
+
+ Test Steps:
+ 1. Run NUT and peer node instances and open a channel between them.
+ 2. Create a network failure in NUT container, bring NUT node offline
+ and receive the status at test driver and restore the network
+ 3. After peer node instance is reachable to NUT node send data via channel
+
+ Expected Result:
+ Peer node should receive data from NUT without any error.
+*/
+static bool test_steps_channel_conn_03(void) {
+ char *invite_nut;
+ char *import;
+
+ joined = false;
+ channel_opened = false;
+ node_unreachable = false;
+ node_reachable = false;
+ channel_received = false;
+
+ // Setup containers
+
+ install_in_container("nut", "iptables");
+ accept_port_rule("nut", "OUTPUT", "udp", 9000);
+ import = mesh_event_sock_create(eth_if_name);
+ invite_nut = invite_in_container("peer", "nut");
+ assert(invite_nut);
+
+ // Run NUT and peer node instances in containers & open a channel
+
+ node_sim_in_container_event("peer", "1", NULL, PEER_ID, import);
+ node_sim_in_container_event("nut", "1", invite_nut, NUT_ID, import);
+
+ wait_for_event(channel_conn_cb, 30);
+ assert_int_equal(joined, true);
+
+ wait_for_event(channel_conn_cb, 10);
+ assert_int_equal(channel_opened, true);
+
+ // Simulate network failure in NUT's LXC container with it's IP address as NAT rule
+
+ node_reachable = false;
+ block_node_ip("nut");
+
+ // Sending SIGUSR1 signal to node-under-test indicating the network failure
+
+ node_step_in_container("nut", "SIGUSR1");
+
+ // Wait for the node status to become unreachable
+
+ wait_for_event(channel_conn_cb, 100);
+ assert_int_equal(node_unreachable, true);
+
+ // Restore NUT container's network
+
+ unblock_node_ip("nut");
+
+ // Wait for the node status to become reachable
+
+ wait_for_event(channel_conn_cb, 100);
+ assert_int_equal(node_reachable, true);
+
+ // Wait for data to be received at peer via channel from NUT after restoring n/w
+
+ wait_for_event(channel_conn_cb, 90);
+ assert_int_equal(channel_received, true);
+
+ free(invite_nut);
+ free(import);
+ return true;
+}
+
+/* Execute channel connections Test Case # 4 - receiving an error when node-under-test
+ tries to send data on channel to peer node after peer node stops and starts the
+ node instance */
+static void test_case_channel_conn_04(void **state) {
+ execute_test(test_steps_channel_conn_04, state);
+ return;
+}
+
+/* Test Steps for Meta-connections Test Case # 4
+
+ Test Steps:
+ 1. Run peer and NUT node instances in containers and open a channel between them.
+ 2. Stop and start the NUT node instance and wait for about > 60 secs.
+ 3. Send data via channel from Peer node and wait for event in test driver.
+
+ Expected Result:
+ Peer node should receive error(as length = 0) in receive callback of peer node's instance.
+*/
+static bool test_steps_channel_conn_04(void) {
+ char *invite_nut;
+ char *import;
+
+ joined = false;
+ channel_opened = false;
+ node_restarted = false;
+ received_error = false;
+ import = mesh_event_sock_create(eth_if_name);
+ invite_nut = invite_in_container("peer", "nut");
+ assert(invite_nut);
+
+ // Run NUT and peer node instances in containers and open a channel
+
+ node_sim_in_container_event("peer", "1", NULL, PEER_ID, import);
+ node_sim_in_container_event("nut", "1", invite_nut, NUT_ID, import);
+
+ wait_for_event(channel_conn_cb, 10);
+ assert_int_equal(joined, true);
+
+ wait_for_event(channel_conn_cb, 10);
+ assert_int_equal(channel_opened, true);
+
+ // Wait for NUT node instance to stop and start
+
+ wait_for_event(channel_conn_cb, 60);
+ assert_int_equal(node_restarted, true);
+
+ sleep(60);
+
+ // After 1 min the channel between NUT and peer should result in error
+
+ wait_for_event(channel_conn_cb, 10);
+ assert_int_equal(received_error, true);
+
+ return true;
+}
+
+/* Execute channel connections Test Case # 5 - simulate a temporary network
+ failure of about 30 seconds, messages sent while the network was down
+ should be received by the other side after the network comes up again. */
+static void test_case_channel_conn_05(void **state) {
+ execute_test(test_steps_channel_conn_05, state);
+ return;
+}
+
+/* Test Steps for channel connections Test Case # 5
+
+ Test Steps:
+ 1. Run NUT, relay & peer node instances with relay inviting NUT and peer
+ and open a channel between them
+ 2. Simulate a network failure in NUT's container for about 30 secs,
+ meanwhile send data via channel from NUT to peer.
+ 3. After restoring network, peer node receive's data via channel.
+
+ Expected Result:
+ Peer node receives data via channel without any error after restoring network.
+*/
+static bool test_steps_channel_conn_05(void) {
+ char *invite_nut, *invite_peer;
+ char *import;
+
+ joined = false;
+ channel_opened = false;
+ channel_received = false;
+
+ // Setup containers
+
+ install_in_container("nut", "iptables");
+ accept_port_rule("nut", "OUTPUT", "udp", 9000);
+ import = mesh_event_sock_create(eth_if_name);
+ invite_peer = invite_in_container("relay", "peer");
+ invite_nut = invite_in_container("relay", "nut");
+ assert(invite_nut);
+ assert(invite_peer);
+
+ // Run node instances and open a channel between NUT and peer nodes
+
+ node_sim_in_container_event("relay", "1", NULL, RELAY_ID, import);
+ node_sim_in_container_event("peer", "1", invite_peer, PEER_ID, import);
+ node_sim_in_container_event("nut", "1", invite_nut, NUT_ID, import);
+
+ wait_for_event(channel_conn_cb, 30);
+ assert_int_equal(joined, true);
+
+ wait_for_event(channel_conn_cb, 30);
+ assert_int_equal(channel_opened, true);
+
+ // Create a network failure in NUT node's container with it's IP address
+
+ block_node_ip("nut");
+
+ // Sending SIGUSR1 signal to node-under-test indicating the network failure
+
+ node_step_in_container("nut", "SIGUSR1");
+ sleep(30);
+
+ // Restore the network
+
+ unblock_node_ip("nut");
+
+ // Wait for peer to get data from NUT node via channel after restoring network in < 60 secs
+
+ wait_for_event(channel_conn_cb, 60);
+ assert_int_equal(channel_received, true);
+
+ free(invite_nut);
+ free(invite_peer);
+ free(import);
+ return true;
+}
+
+/* Execute channel connections Test Case # 6 - a simulated network failure
+ of more than 1 minute, and sending messages over the channel during the
+ failure. Then after about 1 minute, the channel should receive an error */
+static void test_case_channel_conn_06(void **state) {
+ execute_test(test_steps_channel_conn_06, state);
+ return;
+}
+
+/* Test Steps for channel connections Test Case # 6
+
+ Test Steps:
+ 1. Run NUT, relay & peer node instances with relay inviting NUT and peer
+ and open a channel between them
+ 2. Create a network failure for about 90 secs in NUT container
+ and signal NUT node about the network failure.
+ 3. Meanwhile NUT sends data to peer via channel and restore the network after
+ 90 secs.
+
+ Expected Result:
+ Peer node should receive error closing the channel after channel timeout(60 secs).
+*/
+static bool test_steps_channel_conn_06(void) {
+ char *invite_nut, *invite_peer;
+ char *import;
+
+ joined = false;
+ channel_opened = false;
+ received_error = false;
+
+ // Setup containers
+
+ install_in_container("nut", "iptables");
+ accept_port_rule("nut", "OUTPUT", "udp", 9000);
+ import = mesh_event_sock_create(eth_if_name);
+ invite_peer = invite_in_container("relay", "peer");
+ assert(invite_peer);
+ invite_nut = invite_in_container("relay", "nut");
+ assert(invite_nut);
+
+ // Run nodes in containers and open a channel between NUt and peer
+
+ node_sim_in_container_event("relay", "1", NULL, RELAY_ID, import);
+ node_sim_in_container_event("peer", "1", invite_peer, PEER_ID, import);
+ node_sim_in_container_event("nut", "1", invite_nut, NUT_ID, import);
+
+ wait_for_event(channel_conn_cb, 30);
+ assert_int_equal(joined, true);
+
+ wait_for_event(channel_conn_cb, 10);
+ assert_int_equal(channel_opened, true);
+
+ // Simulate a network failure in NUT's container for > 60 secs
+
+ block_node_ip("nut");
+
+ // Sending SIGUSR1 signal to node-under-test indicating the network failure
+
+ node_step_in_container("nut", "SIGUSR1");
+ sleep(90);
+
+ // Restore the network after 90 secs
+
+ unblock_node_ip("nut");
+
+ // Wait for channel to receive error and receive the event
+
+ wait_for_event(channel_conn_cb, 90);
+ assert_int_equal(received_error, true);
+
+ free(invite_nut);
+ free(invite_peer);
+ free(import);
+ return true;
+}
+
+/* Execute channel connections Test Case # 7 - a simulated network failure
+ once node instance is made offline restore the network and send data via
+ channel */
+static void test_case_channel_conn_07(void **state) {
+ execute_test(test_steps_channel_conn_07, state);
+ return;
+}
+
+/* Test Steps for channel connections Test Case # 7
+
+ Test Steps:
+ 1. Run NUT, relay & peer node instances with relay inviting NUT and peer
+ and open a channel between them
+ 2. Create a network failure in NUT container, bring NUT node offline
+ and receive the status at test driver and restore the network
+ 3. After peer node instance is reachable to NUT node send data via channel
+
+ Expected Result:
+ Peer node should receive data from NUT without any error.
+*/
+static bool test_steps_channel_conn_07(void) {
+ char *invite_nut, *invite_peer;
+ char *import;
+
+ joined = false;
+ channel_opened = false;
+ node_unreachable = false;
+ node_reachable = false;
+ channel_received = false;
+
+ // Setup containers
+
+ install_in_container("nut", "iptables");
+ accept_port_rule("nut", "OUTPUT", "udp", 9000);
+ import = mesh_event_sock_create(eth_if_name);
+ invite_peer = invite_in_container("relay", "peer");
+ invite_nut = invite_in_container("relay", "nut");
+ assert(invite_nut);
+ assert(invite_peer);
+
+ // Run nodes and open a channel
+
+ node_sim_in_container_event("relay", "1", NULL, RELAY_ID, import);
+ node_sim_in_container_event("peer", "1", invite_peer, PEER_ID, import);
+ node_sim_in_container_event("nut", "1", invite_nut, NUT_ID, import);
+
+ wait_for_event(channel_conn_cb, 30);
+ assert_int_equal(joined, true);
+
+ wait_for_event(channel_conn_cb, 15);
+ assert_int_equal(channel_opened, true);
+
+ // Simulate a network failure
+
+ node_reachable = false;
+ block_node_ip("nut");
+
+ // Sending SIGUSR1 signal to node-under-test indicating the network failure
+
+ node_step_in_container("nut", "SIGUSR1");
+
+ // Wait for node to become unreachable
+
+ wait_for_event(channel_conn_cb, 100);
+ assert_int_equal(node_unreachable, true);
+
+ // Restore the network
+
+ unblock_node_ip("nut");
+
+ // Wait for node to become reachable after restoring n/w
+
+ wait_for_event(channel_conn_cb, 100);
+ assert_int_equal(node_reachable, true);
+
+ // Wait for peer node to receive data via channel without any error
+
+ wait_for_event(channel_conn_cb, 90);
+ assert_int_equal(channel_received, true);
+
+ free(invite_nut);
+ free(invite_peer);
+ free(import);
+ return true;
+}
+
+/* Execute channel connections Test Case # 8 - receiving an error when node-under-test
+ tries to send data on channel to peer node after peer node stops and starts the
+ node instance */
+static void test_case_channel_conn_08(void **state) {
+ execute_test(test_steps_channel_conn_08, state);
+ return;
+}
+
+/* Test Steps for Meta-connections Test Case # 8
+
+ Test Steps:
+ 1. Run NUT, relay & peer node instances with relay inviting NUT and peer
+ and open a channel between them
+ 2. Stop and start the NUT node instance and wait for about > 60 secs.
+ 3. Send data via channel from Peer node and wait for event in test driver.
+
+ Expected Result:
+ Peer node should receive error(as length = 0) in receive callback of peer node's instance.
+*/
+static bool test_steps_channel_conn_08(void) {
+ char *invite_nut, *invite_peer;
+ char *import;
+
+ joined = false;
+ channel_opened = false;
+ node_restarted = false;
+ received_error = false;
+
+ // Setup containers
+
+ import = mesh_event_sock_create(eth_if_name);
+ invite_peer = invite_in_container("relay", "peer");
+ invite_nut = invite_in_container("relay", "nut");
+ assert(invite_nut);
+ assert(invite_peer);
+
+ // Run nodes and open a channel between NUT and peer
+
+ node_sim_in_container_event("relay", "1", NULL, RELAY_ID, import);
+ node_sim_in_container_event("peer", "1", invite_peer, PEER_ID, import);
+ node_sim_in_container_event("nut", "1", invite_nut, NUT_ID, import);
+
+ wait_for_event(channel_conn_cb, 10);
+ assert_int_equal(joined, true);
+
+ wait_for_event(channel_conn_cb, 10);
+ assert_int_equal(channel_opened, true);
+
+ // Wait for NUT node to restart it's instance
+
+ wait_for_event(channel_conn_cb, 60);
+ assert_int_equal(node_restarted, true);
+
+ sleep(60);
+
+ // Signal peer to send data to NUT node via channel
+
+ node_step_in_container("peer", "SIGUSR1");
+
+ // Wait for peer to receive channel error
+
+ wait_for_event(channel_conn_cb, 10);
+ assert_int_equal(received_error, true);
+
+ free(invite_nut);
+ free(invite_peer);
+ free(import);
+ return true;
+}
+
+static int black_box_group_setup(void **state) {
+ const char *nodes[] = { "peer", "nut", "relay" };
+ int num_nodes = sizeof(nodes) / sizeof(nodes[0]);
+
+ printf("Creating Containers\n");
+ destroy_containers();
+ create_containers(nodes, num_nodes);
+
+ return 0;
+}
+
+static int black_box_group_teardown(void **state) {
+ printf("Destroying Containers\n");
+ destroy_containers();
+
+ return 0;
+}
+
+int test_meshlink_channel_conn(void) {
+ const struct CMUnitTest blackbox_group0_tests[] = {
+ cmocka_unit_test_prestate_setup_teardown(test_case_channel_conn_01, setup_test, teardown_test,
+ (void *)&test_case_channel_conn_01_state),
+ cmocka_unit_test_prestate_setup_teardown(test_case_channel_conn_02, setup_test, teardown_test,
+ (void *)&test_case_channel_conn_02_state),
+ cmocka_unit_test_prestate_setup_teardown(test_case_channel_conn_03, setup_test, teardown_test,
+ (void *)&test_case_channel_conn_03_state),
+ cmocka_unit_test_prestate_setup_teardown(test_case_channel_conn_04, setup_test, teardown_test,
+ (void *)&test_case_channel_conn_04_state),
+ cmocka_unit_test_prestate_setup_teardown(test_case_channel_conn_05, setup_test, teardown_test,
+ (void *)&test_case_channel_conn_05_state),
+ cmocka_unit_test_prestate_setup_teardown(test_case_channel_conn_06, setup_test, teardown_test,
+ (void *)&test_case_channel_conn_06_state),
+ cmocka_unit_test_prestate_setup_teardown(test_case_channel_conn_07, setup_test, teardown_test,
+ (void *)&test_case_channel_conn_07_state),
+ cmocka_unit_test_prestate_setup_teardown(test_case_channel_conn_08, setup_test, teardown_test,
+ (void *)&test_case_channel_conn_08_state)
+ };
+ total_tests += sizeof(blackbox_group0_tests) / sizeof(blackbox_group0_tests[0]);
+
+ return cmocka_run_group_tests(blackbox_group0_tests, black_box_group_setup, black_box_group_teardown);
+}
#include <stdbool.h>
extern int total_tests;
-extern int test_case_channel_conn(void);
+extern int test_meshlink_channel_conn(void);
#endif // TEST_CASES_CHANNEL_CONN_H
--- /dev/null
+check_PROGRAMS = node_sim_peer node_sim_nut
+
+node_sim_peer_SOURCES = node_sim_peer.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c
+node_sim_peer_LDADD = ../../../src/libmeshlink.la
+node_sim_peer_CFLAGS = -D_GNU_SOURCE
+
+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
--- /dev/null
+/*
+ node_sim_nut.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 "../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 int client_id = -1;
+
+static struct sync_flag peer_reachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
+static struct sync_flag channel_opened = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
+static struct sync_flag sigusr_received = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
+static struct sync_flag channel_received = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
+
+static void send_event(mesh_event_t event);
+static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node,
+ bool reachable);
+static void mesh_siguser1_signal_handler(int sig_num);
+
+static void mesh_siguser1_signal_handler(int sig_num) {
+ set_sync_flag(&sigusr_received, true);
+
+ return;
+}
+
+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 void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node,
+ bool reachable) {
+ if(!strcasecmp(node->name, "peer") && reachable) {
+ set_sync_flag(&peer_reachable, true);
+ }
+
+ return;
+}
+
+static void poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, size_t len) {
+ (void)len;
+ meshlink_set_channel_poll_cb(mesh, channel, NULL);
+ assert(meshlink_channel_send(mesh, channel, "test", 5) >= 0);
+ return;
+}
+
+static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) {
+ if(len == 0) {
+ send_event(ERR_NETWORK);
+ assert(false);
+ }
+
+ if(!strcmp(channel->node->name, "peer")) {
+ if(len == 5 && !memcmp(dat, "reply", 5)) {
+ set_sync_flag(&channel_opened, true);
+ }
+ }
+
+ return;
+}
+
+int main(int argc, char *argv[]) {
+ struct timeval main_loop_wait = { 2, 0 };
+ struct timespec timeout = {0};
+ int i;
+
+ // 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(SIGUSR1, mesh_siguser1_signal_handler);
+
+ // Execute test steps
+
+ meshlink_handle_t *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_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));
+
+ // Wait for peer node to join
+
+ assert(wait_sync_flag(&peer_reachable, 30));
+ send_event(NODE_JOINED);
+
+ // Open a channel to peer node
+
+ meshlink_node_t *peer_node = meshlink_get_node(mesh, "peer");
+ assert(peer_node);
+ meshlink_channel_t *channel = meshlink_channel_open(mesh, peer_node, CHANNEL_PORT,
+ channel_receive_cb, NULL, 0);
+ meshlink_set_channel_poll_cb(mesh, channel, poll_cb);
+
+ assert(wait_sync_flag(&channel_opened, 10));
+ send_event(CHANNEL_OPENED);
+
+ assert(wait_sync_flag(&sigusr_received, 10));
+
+ sleep(10);
+
+ assert(meshlink_channel_send(mesh, channel, "after", 6) >= 0);
+
+ // 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);
+}
--- /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 "../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 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);
+
+ if(!strcmp(channel->node->name, "nut")) {
+ 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) {
+ (void)mesh;
+ (void)channel;
+ (void)dat;
+ (void)len;
+
+ if(len == 0) {
+ mesh_event_sock_send(client_id, ERR_NETWORK, NULL, 0);
+ assert(false);
+ }
+
+ if(!strcmp(channel->node->name, "nut")) {
+ if(!memcmp(dat, "test", 5)) {
+ assert(meshlink_channel_send(mesh, channel, "reply", 5) >= 0);
+ } else if(!memcmp(dat, "after", 6)) {
+ assert(mesh_event_sock_send(client_id, CHANNEL_DATA_RECIEVED, NULL, 0));
+ }
+ }
+
+ return;
+}
+
+int main(int argc, char *argv[]) {
+ struct timeval main_loop_wait = { 2, 0 };
+
+ // 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();
+
+ // Run peer node instance
+
+ meshlink_handle_t *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);
+
+ if(argv[CMD_LINE_ARG_INVITEURL]) {
+ assert(meshlink_join(mesh, argv[CMD_LINE_ARG_INVITEURL]));
+ }
+
+ assert(meshlink_start(mesh));
+
+ // 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
+check_PROGRAMS = node_sim_peer node_sim_nut
+
+node_sim_peer_SOURCES = node_sim_peer.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c
+node_sim_peer_LDADD = ../../../src/libmeshlink.la
+node_sim_peer_CFLAGS = -D_GNU_SOURCE
+
+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
--- /dev/null
+/*
+ node_sim_nut.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 "../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 int client_id = -1;
+
+static struct sync_flag peer_reachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
+static struct sync_flag channel_opened = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
+static struct sync_flag channel_closed = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
+static struct sync_flag sigusr_received = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
+
+static void send_event(mesh_event_t event);
+static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node,
+ bool reachable);
+static void mesh_siguser1_signal_handler(int sig_num);
+
+static void mesh_siguser1_signal_handler(int sig_num) {
+ set_sync_flag(&sigusr_received, true);
+ return;
+}
+
+static void send_event(mesh_event_t event) {
+ bool send_ret = false;
+ int attempts;
+
+ for(attempts = 0; attempts < 5; attempts += 1) {
+ send_ret = mesh_event_sock_send(client_id, event, NULL, 0);
+
+ if(send_ret) {
+ break;
+ }
+ }
+
+ return;
+}
+
+static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node,
+ bool reachable) {
+ if(!strcasecmp(node->name, "peer") && reachable) {
+ set_sync_flag(&peer_reachable, true);
+ }
+
+ return;
+}
+
+static void poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, size_t len) {
+ (void)len;
+ meshlink_set_channel_poll_cb(mesh, channel, NULL);
+ assert(meshlink_channel_send(mesh, channel, "test", 5) >= 0);
+ return;
+}
+
+static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) {
+ if(len == 0) {
+ set_sync_flag(&channel_closed, true);
+ send_event(ERR_NETWORK);
+ return;
+ }
+
+ if(!strcmp(channel->node->name, "peer")) {
+ if(len == 5 && !memcmp(dat, "reply", 5)) {
+ set_sync_flag(&channel_opened, true);
+ }
+ }
+
+ return;
+}
+
+int main(int argc, char *argv[]) {
+ struct timeval main_loop_wait = { 2, 0 };
+ struct timespec timeout = {0};
+ int i;
+
+ // 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(SIGUSR1, mesh_siguser1_signal_handler);
+
+ // Execute test steps
+
+ meshlink_handle_t *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_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));
+
+ // Wait for peer node to join
+
+ assert(wait_sync_flag(&peer_reachable, 30));
+ send_event(NODE_JOINED);
+
+ // Open a channel to peer node
+
+ meshlink_node_t *peer_node = meshlink_get_node(mesh, "peer");
+ assert(peer_node);
+ meshlink_channel_t *channel = meshlink_channel_open(mesh, peer_node, CHANNEL_PORT,
+ channel_receive_cb, NULL, 0);
+ meshlink_set_channel_poll_cb(mesh, channel, poll_cb);
+
+ assert(wait_sync_flag(&channel_opened, 10));
+ send_event(CHANNEL_OPENED);
+
+ assert(wait_sync_flag(&sigusr_received, 10));
+
+ assert(meshlink_channel_send(mesh, channel, "after", 6) >= 0);
+
+ assert(wait_sync_flag(&channel_closed, 180));
+
+ // 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);
+}
--- /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 "../common/common_handlers.h"
+#include "../common/test_step.h"
+#include "../common/mesh_event_handler.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 int client_id = -1;
+static bool channel_rec;
+static bool channel_reply;
+static pthread_mutex_t reply_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t reply_cond = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t recv_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t recv_cond = PTHREAD_COND_INITIALIZER;
+
+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) {
+ (void)dat;
+ (void)len;
+
+ assert(port == CHANNEL_PORT);
+
+ if(!strcmp(channel->node->name, "nut")) {
+ meshlink_set_channel_receive_cb(mesh, channel, channel_receive_cb);
+ mesh->priv = channel;
+
+ return true;
+ }
+
+ return false;
+}
+
+static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) {
+ if(len == 0) {
+ assert(mesh_event_sock_send(client_id, ERR_NETWORK, NULL, 0));
+ return;
+ }
+
+ if(!strcmp(channel->node->name, "nut")) {
+ if(!memcmp(dat, "test", 5)) {
+ assert(meshlink_channel_send(mesh, channel, "reply", 5) >= 0);
+ }
+ }
+
+ return;
+}
+
+int main(int argc, char *argv[]) {
+ struct timeval main_loop_wait = { 2, 0 };
+ struct timespec timeout = {0};
+
+ // 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]);
+ }
+
+ // Run peer node instance
+
+ setup_signals();
+
+ meshlink_handle_t *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);
+
+ if(argv[CMD_LINE_ARG_INVITEURL]) {
+ assert(meshlink_join(mesh, argv[CMD_LINE_ARG_INVITEURL]));
+ }
+
+ assert(meshlink_start(mesh));
+
+ // 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
+check_PROGRAMS = node_sim_peer node_sim_nut
+
+node_sim_peer_SOURCES = node_sim_peer.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c
+node_sim_peer_LDADD = ../../../src/libmeshlink.la
+node_sim_peer_CFLAGS = -D_GNU_SOURCE
+
+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
--- /dev/null
+/*
+ node_sim_nut.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 "../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 int client_id = -1;
+
+static struct sync_flag peer_reachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
+static struct sync_flag channel_opened = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
+static struct sync_flag peer_unreachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
+static struct sync_flag sigusr_received = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
+
+static void send_event(mesh_event_t event);
+static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node,
+ bool reachable);
+static void mesh_siguser1_signal_handler(int sig_num);
+
+static void mesh_siguser1_signal_handler(int sig_num) {
+ set_sync_flag(&sigusr_received, true);
+ return;
+}
+
+static void send_event(mesh_event_t event) {
+ bool send_ret = false;
+ 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 void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node,
+ bool reachable) {
+ if(!strcasecmp(node->name, "peer")) {
+ if(reachable) {
+ set_sync_flag(&peer_reachable, true);
+ } else {
+ set_sync_flag(&peer_unreachable, true);
+ }
+ }
+
+ return;
+}
+
+static void poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, size_t len) {
+ (void)len;
+ meshlink_set_channel_poll_cb(mesh, channel, NULL);
+ assert(meshlink_channel_send(mesh, channel, "test", 5) >= 0);
+ return;
+}
+
+static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) {
+ if(!strcmp(channel->node->name, "peer")) {
+ if(len == 5 && !memcmp(dat, "reply", 5)) {
+ set_sync_flag(&channel_opened, true);
+ }
+ }
+
+ return;
+}
+
+int main(int argc, char *argv[]) {
+ struct timeval main_loop_wait = { 2, 0 };
+ struct timespec timeout = {0};
+ int i;
+
+ // 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(SIGUSR1, mesh_siguser1_signal_handler);
+
+ // Execute test steps
+
+ meshlink_handle_t *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_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));
+
+ // Wait for peer node to join
+
+ assert(wait_sync_flag(&peer_reachable, 30));
+ send_event(NODE_JOINED);
+
+ // Open a channel to peer node
+
+ meshlink_node_t *peer_node = meshlink_get_node(mesh, "peer");
+ assert(peer_node);
+ meshlink_channel_t *channel = meshlink_channel_open(mesh, peer_node, CHANNEL_PORT,
+ channel_receive_cb, NULL, 0);
+ meshlink_set_channel_poll_cb(mesh, channel, poll_cb);
+
+ assert(wait_sync_flag(&channel_opened, 10));
+ send_event(CHANNEL_OPENED);
+
+ peer_unreachable.flag = false;
+ peer_reachable.flag = false;
+ assert(wait_sync_flag(&sigusr_received, 10));
+
+ assert(wait_sync_flag(&peer_unreachable, 100));
+ send_event(NODE_UNREACHABLE);
+
+ assert(wait_sync_flag(&peer_reachable, 100));
+ send_event(NODE_REACHABLE);
+
+ assert(meshlink_channel_send(mesh, channel, "after", 6) >= 0);
+
+ // 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);
+}
--- /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 "../common/common_handlers.h"
+#include "../common/test_step.h"
+#include "../common/mesh_event_handler.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 int client_id = -1;
+
+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) {
+ (void)dat;
+ (void)len;
+
+ assert(port == CHANNEL_PORT);
+
+ if(!strcmp(channel->node->name, "nut")) {
+ meshlink_set_channel_receive_cb(mesh, channel, channel_receive_cb);
+ mesh->priv = channel;
+
+ return true;
+ }
+
+ return false;
+}
+
+static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) {
+ if(len == 0) {
+ assert(mesh_event_sock_send(client_id, ERR_NETWORK, NULL, 0));
+ return;
+ }
+
+ if(!strcmp(channel->node->name, "nut")) {
+ if(!memcmp(dat, "test", 5)) {
+ assert(meshlink_channel_send(mesh, channel, "reply", 5) >= 0);
+ } else if(!memcmp(dat, "after", 5)) {
+ assert(mesh_event_sock_send(client_id, CHANNEL_DATA_RECIEVED, NULL, 0));
+ }
+ }
+
+ return;
+}
+
+int main(int argc, char *argv[]) {
+ struct timeval main_loop_wait = { 2, 0 };
+ struct timespec timeout = {0};
+
+ // 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]);
+ }
+
+ // Run peer node instance
+
+ setup_signals();
+
+ meshlink_handle_t *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);
+
+ if(argv[CMD_LINE_ARG_INVITEURL]) {
+ assert(meshlink_join(mesh, argv[CMD_LINE_ARG_INVITEURL]));
+ }
+
+ assert(meshlink_start(mesh));
+
+ // 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
+check_PROGRAMS = node_sim_peer node_sim_nut
+
+node_sim_peer_SOURCES = node_sim_peer.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c
+node_sim_peer_LDADD = ../../../src/libmeshlink.la
+node_sim_peer_CFLAGS = -D_GNU_SOURCE
+
+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
--- /dev/null
+/*
+ node_sim_nut.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 "../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 int client_id = -1;
+
+static struct sync_flag peer_reachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
+static struct sync_flag channel_opened = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
+static struct sync_flag channel_closed = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
+
+static void send_event(mesh_event_t event);
+static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node,
+ bool reachable);
+
+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 void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node,
+ bool reachable) {
+ if(!strcasecmp(node->name, "peer")) {
+ if(reachable) {
+ set_sync_flag(&peer_reachable, true);
+ } else {
+ peer_reachable.flag = false;
+ }
+ }
+
+ return;
+}
+
+static void poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, size_t len) {
+ (void)len;
+ meshlink_set_channel_poll_cb(mesh, channel, NULL);
+ assert(meshlink_channel_send(mesh, channel, "test", 5) >= 0);
+ return;
+}
+
+/* channel receive callback */
+static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) {
+ if(len == 0) {
+ //send_event(ERR_NETWORK);
+ return;
+ }
+
+ if(!strcmp(channel->node->name, "peer")) {
+ if(!memcmp(dat, "reply", 5)) {
+ set_sync_flag(&channel_opened, true);
+ } else if(!memcmp(dat, "failure", 7)) {
+ assert(false);
+ }
+ }
+
+ return;
+}
+
+int main(int argc, char *argv[]) {
+ struct timeval main_loop_wait = { 5, 0 };
+ int i;
+
+ // 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_signals();
+
+ // Execute test steps
+
+ meshlink_handle_t *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_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));
+
+ // Wait for peer node to join
+
+ assert(wait_sync_flag(&peer_reachable, 10));
+ send_event(NODE_JOINED);
+
+ // Open a channel to peer node
+
+ meshlink_node_t *peer_node = meshlink_get_node(mesh, "peer");
+ assert(peer_node);
+ meshlink_channel_t *channel = meshlink_channel_open(mesh, peer_node, CHANNEL_PORT,
+ channel_receive_cb, NULL, 0);
+ meshlink_set_channel_poll_cb(mesh, channel, poll_cb);
+
+ assert(wait_sync_flag(&channel_opened, 10));
+ send_event(CHANNEL_OPENED);
+
+ // Restarting the node instance
+
+ meshlink_stop(mesh);
+ meshlink_start(mesh);
+
+ assert(wait_sync_flag(&peer_reachable, 60));
+ send_event(NODE_RESTARTED);
+
+ // 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);
+}
--- /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 "../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 struct sync_flag sigusr = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
+static int client_id = -1;
+
+static void mesh_siguser1_signal_handler(int sig_num) {
+ set_sync_flag(&sigusr, true);
+
+ 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);
+
+ if(!strcmp(channel->node->name, "nut")) {
+ 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) {
+ (void)mesh;
+ (void)channel;
+ (void)dat;
+ (void)len;
+
+ if(len == 0) {
+ mesh_event_sock_send(client_id, ERR_NETWORK, NULL, 0);
+ return;
+ }
+
+ if(!strcmp(channel->node->name, "nut") && !memcmp(dat, "test", 5)) {
+ assert(meshlink_channel_send(mesh, channel, "reply", 5) >= 0);
+ }
+
+ return;
+}
+
+int main(int argc, char *argv[]) {
+ struct timeval main_loop_wait = { 2, 0 };
+
+ // 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(SIGUSR1, mesh_siguser1_signal_handler);
+
+ // Run peer node instance
+
+ meshlink_handle_t *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);
+
+ if(argv[CMD_LINE_ARG_INVITEURL]) {
+ assert(meshlink_join(mesh, argv[CMD_LINE_ARG_INVITEURL]));
+ }
+
+ assert(meshlink_start(mesh));
+
+ assert(wait_sync_flag(&sigusr, 140));
+ meshlink_channel_t *channel = mesh->priv;
+ assert(meshlink_channel_send(mesh, channel, "failure", 7));
+
+ // 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
+check_PROGRAMS = node_sim_peer node_sim_nut node_sim_relay
+
+node_sim_peer_SOURCES = node_sim_peer.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c
+node_sim_peer_LDADD = ../../../src/libmeshlink.la
+node_sim_peer_CFLAGS = -D_GNU_SOURCE
+
+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_relay_SOURCES = node_sim_relay.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c
+node_sim_relay_LDADD = ../../../src/libmeshlink.la
+node_sim_relay_CFLAGS = -D_GNU_SOURCE
--- /dev/null
+/*
+ node_sim_nut.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 "../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 int client_id = -1;
+
+static struct sync_flag peer_reachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
+static struct sync_flag channel_opened = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
+static struct sync_flag sigusr_received = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
+static struct sync_flag channel_received = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
+
+static void send_event(mesh_event_t event);
+static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node,
+ bool reachable);
+static void mesh_siguser1_signal_handler(int sig_num);
+
+static void mesh_siguser1_signal_handler(int sig_num) {
+ set_sync_flag(&sigusr_received, true);
+
+ return;
+}
+
+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 void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node,
+ bool reachable) {
+ if(!strcasecmp(node->name, "peer") && reachable) {
+ set_sync_flag(&peer_reachable, true);
+ }
+
+ return;
+}
+
+static void poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, size_t len) {
+ (void)len;
+ meshlink_set_channel_poll_cb(mesh, channel, NULL);
+ assert(meshlink_channel_send(mesh, channel, "test", 5) >= 0);
+ return;
+}
+
+static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) {
+ if(len == 0) {
+ send_event(ERR_NETWORK);
+ assert(false);
+ }
+
+ if(!strcmp(channel->node->name, "peer")) {
+ if(len == 5 && !memcmp(dat, "reply", 5)) {
+ set_sync_flag(&channel_opened, true);
+ }
+ }
+
+ return;
+}
+
+int main(int argc, char *argv[]) {
+ struct timeval main_loop_wait = { 2, 0 };
+ struct timespec timeout = {0};
+ int i;
+
+ // 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(SIGUSR1, mesh_siguser1_signal_handler);
+
+ // Execute test steps
+
+ meshlink_handle_t *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_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));
+
+ // Wait for peer node to join
+
+ assert(wait_sync_flag(&peer_reachable, 30));
+ send_event(NODE_JOINED);
+
+ // Open a channel to peer node
+
+ meshlink_node_t *peer_node = meshlink_get_node(mesh, "peer");
+ assert(peer_node);
+ meshlink_channel_t *channel = meshlink_channel_open(mesh, peer_node, CHANNEL_PORT,
+ channel_receive_cb, NULL, 0);
+ meshlink_set_channel_poll_cb(mesh, channel, poll_cb);
+
+ assert(wait_sync_flag(&channel_opened, 10));
+ send_event(CHANNEL_OPENED);
+
+ assert(wait_sync_flag(&sigusr_received, 10));
+
+ sleep(10);
+
+ assert(meshlink_channel_send(mesh, channel, "after", 6) >= 0);
+
+ // 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);
+}
--- /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 "../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 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);
+
+ if(!strcmp(channel->node->name, "nut")) {
+ 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) {
+ (void)mesh;
+ (void)channel;
+ (void)dat;
+ (void)len;
+
+ if(len == 0) {
+ mesh_event_sock_send(client_id, ERR_NETWORK, NULL, 0);
+ assert(false);
+ }
+
+ if(!strcmp(channel->node->name, "nut")) {
+ if(!memcmp(dat, "test", 5)) {
+ assert(meshlink_channel_send(mesh, channel, "reply", 5) >= 0);
+ } else if(!memcmp(dat, "after", 6)) {
+ assert(mesh_event_sock_send(client_id, CHANNEL_DATA_RECIEVED, NULL, 0));
+ }
+ }
+
+ return;
+}
+
+int main(int argc, char *argv[]) {
+ struct timeval main_loop_wait = { 2, 0 };
+
+ // 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();
+
+ // Run peer node instance
+
+ meshlink_handle_t *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);
+
+ if(argv[CMD_LINE_ARG_INVITEURL]) {
+ assert(meshlink_join(mesh, argv[CMD_LINE_ARG_INVITEURL]));
+ }
+
+ assert(meshlink_start(mesh));
+
+ // 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_relay.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 "../common/common_handlers.h"
+#include "../common/test_step.h"
+#include "../common/mesh_event_handler.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
+
+int main(int argc, char *argv[]) {
+ struct timeval main_loop_wait = { 5, 0 };
+
+ // Setup required signals
+
+ setup_signals();
+
+ // Run relay node instance
+
+ meshlink_handle_t *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_start(mesh);
+
+ /* 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_peer node_sim_nut node_sim_relay
+
+node_sim_peer_SOURCES = node_sim_peer.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c
+node_sim_peer_LDADD = ../../../src/libmeshlink.la
+node_sim_peer_CFLAGS = -D_GNU_SOURCE
+
+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_relay_SOURCES = node_sim_relay.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c
+node_sim_relay_LDADD = ../../../src/libmeshlink.la
+node_sim_relay_CFLAGS = -D_GNU_SOURCE
--- /dev/null
+/*
+ node_sim_nut.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 "../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 int client_id = -1;
+
+static struct sync_flag peer_reachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
+static struct sync_flag channel_opened = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
+static struct sync_flag channel_closed = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
+static struct sync_flag sigusr_received = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
+
+static void send_event(mesh_event_t event);
+static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node,
+ bool reachable);
+static void mesh_siguser1_signal_handler(int sig_num);
+
+static void mesh_siguser1_signal_handler(int sig_num) {
+ set_sync_flag(&sigusr_received, true);
+ return;
+}
+
+static void send_event(mesh_event_t event) {
+ bool send_ret = false;
+ int attempts;
+
+ for(attempts = 0; attempts < 5; attempts += 1) {
+ send_ret = mesh_event_sock_send(client_id, event, NULL, 0);
+
+ if(send_ret) {
+ break;
+ }
+ }
+
+ return;
+}
+
+static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node,
+ bool reachable) {
+ fprintf(stderr, "\n\n\n NODE STATUS CB : %s is %d\n\n\n\n", node->name, reachable);
+
+ if(!strcasecmp(node->name, "peer") && reachable) {
+ set_sync_flag(&peer_reachable, true);
+ }
+
+ return;
+}
+
+static void poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, size_t len) {
+ (void)len;
+ meshlink_set_channel_poll_cb(mesh, channel, NULL);
+ assert(meshlink_channel_send(mesh, channel, "test", 5) >= 0);
+ return;
+}
+
+static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) {
+ fprintf(stderr, "\n\n\n LEN = %u & DATA = %s in RECV CB\n\n\n\n", len, (char *)dat);
+
+ if(len == 0) {
+ set_sync_flag(&channel_closed, true);
+ send_event(ERR_NETWORK);
+ return;
+ }
+
+ if(!strcmp(channel->node->name, "peer")) {
+ if(len == 5 && !memcmp(dat, "reply", 5)) {
+ set_sync_flag(&channel_opened, true);
+ }
+ }
+
+ return;
+}
+
+int main(int argc, char *argv[]) {
+ struct timeval main_loop_wait = { 2, 0 };
+ struct timespec timeout = {0};
+ int i;
+
+ // 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(SIGUSR1, mesh_siguser1_signal_handler);
+
+ // Execute test steps
+
+ meshlink_handle_t *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_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));
+
+ // Wait for peer node to join
+
+ assert(wait_sync_flag(&peer_reachable, 30));
+ send_event(NODE_JOINED);
+
+ // Open a channel to peer node
+
+ meshlink_node_t *peer_node = meshlink_get_node(mesh, "peer");
+ assert(peer_node);
+ meshlink_channel_t *channel = meshlink_channel_open(mesh, peer_node, CHANNEL_PORT,
+ channel_receive_cb, NULL, 0);
+ meshlink_set_channel_poll_cb(mesh, channel, poll_cb);
+
+ assert(wait_sync_flag(&channel_opened, 10));
+ send_event(CHANNEL_OPENED);
+ fprintf(stderr, "\n\n\nChannel opened, Waiting for SIGUSR1\n\n\n\n");
+ assert(wait_sync_flag(&sigusr_received, 10));
+
+ fprintf(stderr, "\n\n\nChannel sending, got SIGUSR1\n\n\n\n");
+ sleep(40);
+ assert(meshlink_channel_send(mesh, channel, "after", 6) >= 0);
+
+ fprintf(stderr, "\n\n\nWaiting for close\n\n\n\n");
+
+ assert(wait_sync_flag(&channel_closed, 140));
+
+ fprintf(stderr, "\n\n\nCHANNEL CLOSED\n\n\n\n");
+
+ // 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);
+}
--- /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 "../common/common_handlers.h"
+#include "../common/test_step.h"
+#include "../common/mesh_event_handler.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 int client_id = -1;
+static bool channel_rec;
+static bool channel_reply;
+static pthread_mutex_t reply_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t reply_cond = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t recv_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t recv_cond = PTHREAD_COND_INITIALIZER;
+
+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) {
+ (void)dat;
+ (void)len;
+
+ assert(port == CHANNEL_PORT);
+
+ if(!strcmp(channel->node->name, "nut")) {
+ meshlink_set_channel_receive_cb(mesh, channel, channel_receive_cb);
+ mesh->priv = channel;
+
+ return true;
+ }
+
+ return false;
+}
+
+static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) {
+ fprintf(stderr, "\n\n\n LEN = %u & DATA = %s in RECV CB\n\n\n\n", len, (char *)dat);
+
+ if(len == 0) {
+ assert(mesh_event_sock_send(client_id, ERR_NETWORK, NULL, 0));
+ return;
+ }
+
+ if(!strcmp(channel->node->name, "nut")) {
+ if(!memcmp(dat, "test", 5)) {
+ assert(meshlink_channel_send(mesh, channel, "reply", 5) >= 0);
+ }
+ }
+
+ return;
+}
+
+int main(int argc, char *argv[]) {
+ struct timeval main_loop_wait = { 5, 0 };
+ struct timespec timeout = {0};
+
+ // 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]);
+ }
+
+ // Run peer node instance
+
+ setup_signals();
+
+ meshlink_set_log_cb(NULL, MESHLINK_DEBUG, meshlink_callback_logger);
+ meshlink_handle_t *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);
+
+ if(argv[CMD_LINE_ARG_INVITEURL]) {
+ assert(meshlink_join(mesh, argv[CMD_LINE_ARG_INVITEURL]));
+ }
+
+ assert(meshlink_start(mesh));
+
+ // 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_relay.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 "../common/common_handlers.h"
+#include "../common/test_step.h"
+#include "../common/mesh_event_handler.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
+
+int main(int argc, char *argv[]) {
+ struct timeval main_loop_wait = { 5, 0 };
+
+ // Setup required signals
+
+ setup_signals();
+
+ // Run relay node instance
+
+ meshlink_handle_t *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_start(mesh);
+
+ /* 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_peer node_sim_nut node_sim_relay
+
+node_sim_peer_SOURCES = node_sim_peer.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c
+node_sim_peer_LDADD = ../../../src/libmeshlink.la
+node_sim_peer_CFLAGS = -D_GNU_SOURCE
+
+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_relay_SOURCES = node_sim_relay.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c
+node_sim_relay_LDADD = ../../../src/libmeshlink.la
+node_sim_relay_CFLAGS = -D_GNU_SOURCE
--- /dev/null
+/*
+ node_sim_nut.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 "../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 int client_id = -1;
+
+static struct sync_flag peer_reachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
+static struct sync_flag channel_opened = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
+static struct sync_flag peer_unreachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
+static struct sync_flag sigusr_received = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
+
+static void send_event(mesh_event_t event);
+static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node,
+ bool reachable);
+static void mesh_siguser1_signal_handler(int sig_num);
+
+static void mesh_siguser1_signal_handler(int sig_num) {
+ set_sync_flag(&sigusr_received, true);
+ return;
+}
+
+static void send_event(mesh_event_t event) {
+ bool send_ret = false;
+ 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 void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node,
+ bool reachable) {
+
+ if(!strcasecmp(node->name, "peer")) {
+ if(reachable) {
+ set_sync_flag(&peer_reachable, true);
+ } else {
+ set_sync_flag(&peer_unreachable, true);
+ }
+ }
+
+ return;
+}
+
+static void poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, size_t len) {
+ (void)len;
+ meshlink_set_channel_poll_cb(mesh, channel, NULL);
+ assert(meshlink_channel_send(mesh, channel, "test", 5) >= 0);
+ return;
+}
+
+static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) {
+ if(len == 0) {
+ send_event(ERR_NETWORK);
+ return;
+ }
+
+ if(!strcmp(channel->node->name, "peer")) {
+ if(len == 5 && !memcmp(dat, "reply", 5)) {
+ set_sync_flag(&channel_opened, true);
+ }
+ }
+
+ return;
+}
+
+int main(int argc, char *argv[]) {
+ struct timeval main_loop_wait = { 2, 0 };
+ struct timespec timeout = {0};
+ int i;
+
+ // 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(SIGUSR1, mesh_siguser1_signal_handler);
+
+ // Execute test steps
+
+ meshlink_handle_t *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_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));
+
+ // Wait for peer node to join
+ assert(wait_sync_flag(&peer_reachable, 30));
+ send_event(NODE_JOINED);
+
+ // Open a channel to peer node
+
+ meshlink_node_t *peer_node = meshlink_get_node(mesh, "peer");
+ assert(peer_node);
+ meshlink_channel_t *channel = meshlink_channel_open(mesh, peer_node, CHANNEL_PORT,
+ channel_receive_cb, NULL, 0);
+ meshlink_set_channel_poll_cb(mesh, channel, poll_cb);
+
+ assert(wait_sync_flag(&channel_opened, 10));
+ send_event(CHANNEL_OPENED);
+
+ peer_unreachable.flag = false;
+ peer_reachable.flag = false;
+ assert(wait_sync_flag(&sigusr_received, 10));
+
+ assert(wait_sync_flag(&peer_unreachable, 100));
+ send_event(NODE_UNREACHABLE);
+
+ assert(wait_sync_flag(&peer_reachable, 100));
+ send_event(NODE_REACHABLE);
+
+ assert(meshlink_channel_send(mesh, channel, "after", 6) >= 0);
+
+ // 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);
+}
--- /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 "../common/common_handlers.h"
+#include "../common/test_step.h"
+#include "../common/mesh_event_handler.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 int client_id = -1;
+
+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) {
+ (void)dat;
+ (void)len;
+
+ assert(port == CHANNEL_PORT);
+
+ if(!strcmp(channel->node->name, "nut")) {
+ meshlink_set_channel_receive_cb(mesh, channel, channel_receive_cb);
+ mesh->priv = channel;
+
+ return true;
+ }
+
+ return false;
+}
+
+static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) {
+ if(len == 0) {
+ assert(mesh_event_sock_send(client_id, ERR_NETWORK, NULL, 0));
+ return;
+ }
+
+ if(!strcmp(channel->node->name, "nut")) {
+ if(!memcmp(dat, "test", 5)) {
+ assert(meshlink_channel_send(mesh, channel, "reply", 5) >= 0);
+ } else if(!memcmp(dat, "after", 5)) {
+ assert(mesh_event_sock_send(client_id, CHANNEL_DATA_RECIEVED, NULL, 0));
+ }
+ }
+
+ return;
+}
+
+int main(int argc, char *argv[]) {
+ struct timeval main_loop_wait = { 2, 0 };
+ struct timespec timeout = {0};
+
+ // 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]);
+ }
+
+ // Run peer node instance
+
+ setup_signals();
+
+ meshlink_handle_t *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);
+
+ if(argv[CMD_LINE_ARG_INVITEURL]) {
+ assert(meshlink_join(mesh, argv[CMD_LINE_ARG_INVITEURL]));
+ }
+
+ assert(meshlink_start(mesh));
+
+ // 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_relay.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 "../common/common_handlers.h"
+#include "../common/test_step.h"
+#include "../common/mesh_event_handler.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
+
+int main(int argc, char *argv[]) {
+ struct timeval main_loop_wait = { 5, 0 };
+
+ // Setup required signals
+
+ setup_signals();
+
+ // Run relay node instance
+
+ meshlink_handle_t *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_start(mesh);
+
+ /* 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_peer node_sim_nut node_sim_relay
+
+node_sim_peer_SOURCES = node_sim_peer.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c
+node_sim_peer_LDADD = ../../../src/libmeshlink.la
+node_sim_peer_CFLAGS = -D_GNU_SOURCE
+
+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_relay_SOURCES = node_sim_relay.c ../common/common_handlers.c ../common/test_step.c ../common/mesh_event_handler.c ../../utils.c
+node_sim_relay_LDADD = ../../../src/libmeshlink.la
+node_sim_relay_CFLAGS = -D_GNU_SOURCE
--- /dev/null
+/*
+ node_sim_nut.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 "../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 int client_id = -1;
+
+static struct sync_flag peer_reachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
+static struct sync_flag channel_opened = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
+static struct sync_flag channel_closed = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
+
+static void send_event(mesh_event_t event);
+static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node,
+ bool reachable);
+
+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 void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node,
+ bool reachable) {
+ if(!strcasecmp(node->name, "peer")) {
+ if(reachable) {
+ set_sync_flag(&peer_reachable, true);
+ } else {
+ peer_reachable.flag = false;
+ }
+ }
+
+ return;
+}
+
+static void poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, size_t len) {
+ (void)len;
+ meshlink_set_channel_poll_cb(mesh, channel, NULL);
+ assert(meshlink_channel_send(mesh, channel, "test", 5) >= 0);
+ return;
+}
+
+/* channel receive callback */
+static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) {
+ if(len == 0) {
+ //send_event(ERR_NETWORK);
+ return;
+ }
+
+ if(!strcmp(channel->node->name, "peer")) {
+ if(!memcmp(dat, "reply", 5)) {
+ set_sync_flag(&channel_opened, true);
+ } else if(!memcmp(dat, "failure", 7)) {
+ assert(false);
+ }
+ }
+
+ return;
+}
+
+int main(int argc, char *argv[]) {
+ struct timeval main_loop_wait = { 5, 0 };
+ int i;
+
+ // 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_signals();
+
+ // Execute test steps
+
+ meshlink_handle_t *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_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));
+
+ // Wait for peer node to join
+
+ assert(wait_sync_flag(&peer_reachable, 10));
+ send_event(NODE_JOINED);
+
+ // Open a channel to peer node
+
+ meshlink_node_t *peer_node = meshlink_get_node(mesh, "peer");
+ assert(peer_node);
+ meshlink_channel_t *channel = meshlink_channel_open(mesh, peer_node, CHANNEL_PORT,
+ channel_receive_cb, NULL, 0);
+ meshlink_set_channel_poll_cb(mesh, channel, poll_cb);
+
+ assert(wait_sync_flag(&channel_opened, 10));
+ send_event(CHANNEL_OPENED);
+
+ // Restarting the node instance
+
+ meshlink_stop(mesh);
+ meshlink_start(mesh);
+
+ assert(wait_sync_flag(&peer_reachable, 60));
+ send_event(NODE_RESTARTED);
+
+ // 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);
+}
--- /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 "../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 struct sync_flag sigusr = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
+static int client_id = -1;
+
+static void mesh_siguser1_signal_handler(int sig_num) {
+ set_sync_flag(&sigusr, true);
+
+ 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);
+
+ if(!strcmp(channel->node->name, "nut")) {
+ 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) {
+ (void)mesh;
+ (void)channel;
+ (void)dat;
+ (void)len;
+
+ if(len == 0) {
+ mesh_event_sock_send(client_id, ERR_NETWORK, NULL, 0);
+ return;
+ }
+
+ if(!strcmp(channel->node->name, "nut") && !memcmp(dat, "test", 5)) {
+ assert(meshlink_channel_send(mesh, channel, "reply", 5) >= 0);
+ }
+
+ return;
+}
+
+int main(int argc, char *argv[]) {
+ struct timeval main_loop_wait = { 2, 0 };
+
+ // 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(SIGUSR1, mesh_siguser1_signal_handler);
+
+ // Run peer node instance
+
+ meshlink_handle_t *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);
+
+ if(argv[CMD_LINE_ARG_INVITEURL]) {
+ assert(meshlink_join(mesh, argv[CMD_LINE_ARG_INVITEURL]));
+ }
+
+ assert(meshlink_start(mesh));
+
+ assert(wait_sync_flag(&sigusr, 140));
+ meshlink_channel_t *channel = mesh->priv;
+ assert(meshlink_channel_send(mesh, channel, "failure", 7));
+
+ // 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_relay.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 "../common/common_handlers.h"
+#include "../common/test_step.h"
+#include "../common/mesh_event_handler.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
+
+int main(int argc, char *argv[]) {
+ struct timeval main_loop_wait = { 5, 0 };
+
+ // Setup required signals
+
+ setup_signals();
+
+ // Run relay node instance
+
+ meshlink_handle_t *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_start(mesh);
+
+ /* 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;
+}