2 node_sim_nut.c -- Implementation of Node Simulation for Meshlink Testing
3 for channel connections with respective to blacklisting their nodes
4 Copyright (C) 2019 Guus Sliepen <guus@meshlink.io>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
31 #include "../common/common_handlers.h"
32 #include "../common/test_step.h"
33 #include "../common/mesh_event_handler.h"
34 #include "../common/network_namespace_framework.h"
35 #include "../../utils.h"
36 #include "node_sim_nut_01.h"
38 #define CHANNEL_PORT 1234
40 static bool blacklist_set;
41 int total_reachable_callbacks_01;
42 int total_unreachable_callbacks_01;
43 int total_channel_closure_callbacks_01;
44 bool channel_discon_case_ping;
45 bool channel_discon_network_failure_01;
46 bool channel_discon_network_failure_02;
47 bool test_blacklist_whitelist_01;
48 bool test_channel_restart_01;
50 static struct sync_flag peer_reachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
51 static struct sync_flag peer_unreachable = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
52 static struct sync_flag channel_opened = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
53 static struct sync_flag channels_closed = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER};
55 static void node_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node, bool reachable) {
58 fprintf(stderr, "Node %s %s\n", node->name, reachable ? "reachable" : "unreachable");
60 if(!strcmp(node->name, "peer")) {
62 set_sync_flag(&peer_reachable, true);
65 ++total_reachable_callbacks_01;
68 set_sync_flag(&peer_unreachable, true);
71 ++total_unreachable_callbacks_01;
79 static void poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, size_t len) {
81 fprintf(stderr, "%s poll cb invoked\n", (char *)channel->priv);
82 meshlink_set_channel_poll_cb(mesh, channel, NULL);
83 assert(meshlink_channel_send(mesh, channel, "test", 5) >= 0);
87 static void channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *dat, size_t len) {
91 fprintf(stderr, "Closed channel with %s\n", (char *)channel->priv);
94 ++total_channel_closure_callbacks_01;
97 if(total_channel_closure_callbacks_01 == 2) {
98 set_sync_flag(&channels_closed, true);
102 if(!strcmp(channel->node->name, "peer")) {
103 if(len == 5 && !memcmp(dat, "reply", 5)) {
104 fprintf(stderr, "Channel opened with %s\n", (char *)channel->priv);
105 set_sync_flag(&channel_opened, true);
112 static void log_message(meshlink_handle_t *mesh, meshlink_log_level_t level, const char *text) {
117 fprintf(stderr, "\x1b[32m nut:\x1b[0m %s\n", text);
120 void *test_channel_blacklist_disonnection_nut_01(void *arg) {
121 mesh_arg_t *mesh_arg = (mesh_arg_t *)arg;
122 total_reachable_callbacks_01 = 0;
123 total_unreachable_callbacks_01 = 0;
124 total_channel_closure_callbacks_01 = 0;
126 set_sync_flag(&peer_reachable, false);
127 set_sync_flag(&peer_unreachable, false);
128 set_sync_flag(&channel_opened, false);
129 blacklist_set = false;
131 assert(!channel_discon_network_failure_01 || !channel_discon_network_failure_02);
133 // Run relay node instance
135 meshlink_handle_t *mesh;
136 mesh = meshlink_open(mesh_arg->node_name, mesh_arg->confbase, mesh_arg->app_name, mesh_arg->dev_class);
138 meshlink_set_log_cb(mesh, MESHLINK_DEBUG, log_message);
139 meshlink_set_node_status_cb(mesh, node_status_cb);
141 // Join relay node and if fails to join then try few more attempts
143 if(mesh_arg->join_invitation) {
144 assert(meshlink_join(mesh, mesh_arg->join_invitation));
147 assert(meshlink_start(mesh));
149 // Wait for peer node to join
151 assert(wait_sync_flag(&peer_reachable, 30));
153 meshlink_node_t *peer_node = meshlink_get_node(mesh, "peer");
155 meshlink_channel_t *channel1 = meshlink_channel_open(mesh, peer_node, CHANNEL_PORT,
156 channel_receive_cb, NULL, 0);
157 channel1->priv = "channel1";
158 meshlink_set_channel_poll_cb(mesh, channel1, poll_cb);
160 assert(wait_sync_flag(&channel_opened, 15));
162 set_sync_flag(&channel_opened, false);
164 meshlink_channel_t *channel2 = meshlink_channel_open(mesh, peer_node, CHANNEL_PORT,
165 channel_receive_cb, NULL, 0);
166 channel2->priv = "channel2";
167 meshlink_set_channel_poll_cb(mesh, channel2, poll_cb);
169 assert(wait_sync_flag(&channel_opened, 15));
171 blacklist_set = true;
173 if(channel_discon_network_failure_01) {
174 fprintf(stderr, "Simulating network failure before blacklisting\n");
175 assert(system("iptables -A INPUT -m statistic --mode random --probability 0.9 -j DROP") == 0);
176 assert(system("iptables -A OUTPUT -m statistic --mode random --probability 0.9 -j DROP") == 0);
180 fprintf(stderr, "Node blacklisted\n");
181 set_sync_flag(&channels_closed, false);
182 meshlink_blacklist(mesh, peer_node);
186 if(channel_discon_network_failure_02) {
187 fprintf(stderr, "Simulating network failure after blacklisting\n");
188 assert(system("iptables -A INPUT -m statistic --mode random --probability 0.9 -j DROP") == 0);
189 assert(system("iptables -A OUTPUT -m statistic --mode random --probability 0.9 -j DROP") == 0);
193 if(channel_discon_case_ping) {
194 fprintf(stderr, "Sending data through channels after blacklisting\n");
195 assert(meshlink_channel_send(mesh, channel1, "ping", 5) >= 0);
196 assert(meshlink_channel_send(mesh, channel2, "ping", 5) >= 0);
199 if(wait_sync_flag(&channels_closed, 120) == false) {
200 set_sync_flag(&test_channel_discon_nut_close, true);
204 if(channel_discon_network_failure_01 || channel_discon_network_failure_02) {
205 fprintf(stderr, "Simulating network failure after blacklisting\n");
206 assert(system("iptables -D INPUT -m statistic --mode random --probability 0.9 -j DROP") == 0);
207 assert(system("iptables -D OUTPUT -m statistic --mode random --probability 0.9 -j DROP") == 0);
210 set_sync_flag(&peer_reachable, false);
212 meshlink_whitelist(mesh, peer_node);
213 fprintf(stderr, "Node whitelisted\n");
215 wait_sync_flag(&peer_reachable, 70);
217 fprintf(stderr, "Closing NUT instance\n");
218 blacklist_set = false;
220 set_sync_flag(&test_channel_discon_nut_close, true);
222 meshlink_close(mesh);