Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix edge slow shutdown on Windows #1121

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/n2n_typedefs.h
Original file line number Diff line number Diff line change
Expand Up @@ -706,6 +706,9 @@ struct n2n_edge {

/* Status */
bool *keep_running; /**< Pointer to edge loop stop/go flag */
#ifdef _WIN32
HANDLE *stop_event_handle; /**< Pointer to edge loop stop signal */
#endif
struct peer_info *curr_sn; /**< Currently active supernode. */
uint8_t sn_wait; /**< Whether we are waiting for a supernode response. */
uint8_t sn_pong; /**< Whether we have seen a PONG since last time reset. */
Expand Down
10 changes: 9 additions & 1 deletion src/edge.c
Original file line number Diff line number Diff line change
Expand Up @@ -959,6 +959,9 @@ static void daemonize () {
/* *************************************************** */

static bool keep_on_running = true;
#ifdef _WIN32
static HANDLE stop_event_handle;
#endif

#if defined(__linux__) || defined(_WIN32)
#ifdef _WIN32
Expand All @@ -979,6 +982,9 @@ BOOL WINAPI term_handler(DWORD sig)

keep_on_running = false;
#ifdef _WIN32
if (!SetEvent(stop_event_handle)) {
traceEvent(TRACE_ERROR, "failed to set stop signal, you may experience slow shutdown, error code: %d", GetLastError());
}
switch (sig) {
case CTRL_CLOSE_EVENT:
case CTRL_LOGOFF_EVENT:
Expand Down Expand Up @@ -1337,7 +1343,9 @@ int main (int argc, char* argv[]) {
signal(SIGINT, term_handler);
#endif
#ifdef _WIN32
SetConsoleCtrlHandler(term_handler, TRUE);
SetConsoleCtrlHandler(term_handler, true);
stop_event_handle = CreateEvent(NULL, true, false, NULL);
eee->stop_event_handle = stop_event_handle;
#endif

eee->keep_running = &keep_on_running;
Expand Down
170 changes: 125 additions & 45 deletions src/edge_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -2872,6 +2872,19 @@ void print_edge_stats (const n2n_edge_t *eee) {

/* ************************************** */

#ifdef _WIN32
bool add_read_event_select(int *total_events, HANDLE *events, SOCKET socket) {
HANDLE event_handle = WSACreateEvent();
int result = WSAEventSelect(socket, event_handle, FD_READ);
if (result != NO_ERROR) {
traceEvent(TRACE_ERROR, "can't select event, error code: %d", WSAGetLastError());
return false;
}
events[*total_events] = event_handle;
*total_events += 1;
return true;
}
#endif

int run_edge_loop (n2n_edge_t *eee) {

Expand All @@ -2894,7 +2907,6 @@ int run_edge_loop (n2n_edge_t *eee) {
HANDLE tun_read_thread = startTunReadThread(&arg);
#endif

*eee->keep_running = true;
update_supernode_reg(eee, time(NULL));

/* Main loop
Expand All @@ -2906,10 +2918,69 @@ int run_edge_loop (n2n_edge_t *eee) {

while(*eee->keep_running) {

int rc, max_sock = 0;
bool management_has_message = false;
bool sock_has_message = false;
bool multicast_has_message = false;
#ifndef _WIN32
bool tuntap_has_message = false;
#endif

#ifdef _WIN32
int total_events = 0;
HANDLE events[WSA_MAXIMUM_WAIT_EVENTS] = {0};
bool *event_message_map[WSA_MAXIMUM_WAIT_EVENTS] = {0};
events[total_events] = eee->stop_event_handle;
total_events += 1;
event_message_map[total_events] = &management_has_message;
if (!add_read_event_select(&total_events, events, eee->udp_mgmt_sock)) {
break;
}
if (eee->sock >= 0) {
event_message_map[total_events] = &sock_has_message;
if (!add_read_event_select(&total_events, events, eee->sock)) {
break;
}
}
#ifndef SKIP_MULTICAST_PEERS_DISCOVERY
if (eee->conf.allow_p2p && eee->conf.preferred_sock.family == AF_INVALID) {
event_message_map[total_events] = &multicast_has_message;
if (!add_read_event_select(&total_events, events, eee->udp_multicast_sock)) {
break;
}
}
#endif
DWORD wait_time_ms = (eee->sn_wait ? SOCKET_TIMEOUT_INTERVAL_SECS / 10 + 1 : SOCKET_TIMEOUT_INTERVAL_SECS) * 1000;
DWORD result = WSAWaitForMultipleEvents(total_events, events, false, wait_time_ms, false);
for (int i = 0; i < total_events; i++) {
HANDLE current_event = events[i];
if (current_event == NULL) {
break;
}
if (current_event != eee->stop_event_handle) {
if (!WSACloseEvent(current_event)) {
traceEvent(TRACE_ERROR, "can't close event, error code: %d", WSAGetLastError());
break;
}
}
}

traceEvent(TRACE_NORMAL, "wait for multiple events result: %d", result);
if (result == WSA_WAIT_FAILED) {
traceEvent(TRACE_ERROR, "can't wait for events, error code: %d", WSAGetLastError());
break;
}
if (result >= WSA_WAIT_EVENT_0 && result <= WSA_WAIT_EVENT_0 + total_events - 1) {
int index = result - WSA_WAIT_EVENT_0;
HANDLE signaled_event = events[index];
if (signaled_event == eee->stop_event_handle) {
traceEvent(TRACE_NORMAL, "exit signal received");
break;
}
*event_message_map[index] = true;
}
#else
int max_sock = 0;
fd_set socket_mask;
struct timeval wait_time;
time_t now;

FD_ZERO(&socket_mask);

Expand All @@ -2932,11 +3003,20 @@ int run_edge_loop (n2n_edge_t *eee) {
FD_SET(eee->device.fd, &socket_mask);
max_sock = max(max_sock, eee->device.fd);
#endif

struct timeval wait_time;
wait_time.tv_sec = (eee->sn_wait) ? (SOCKET_TIMEOUT_INTERVAL_SECS / 10 + 1) : (SOCKET_TIMEOUT_INTERVAL_SECS);
wait_time.tv_usec = 0;
rc = select(max_sock + 1, &socket_mask, NULL, NULL, &wait_time);
now = time(NULL);
traceEvent(TRACE_NORMAL, "start waiting for select");
int rc = select(max_sock + 1, &socket_mask, NULL, NULL, &wait_time);
traceEvent(TRACE_NORMAL, "finish waiting for select");

management_has_message = FD_ISSET(eee->udp_mgmt_sock, &socket_mask);
sock_has_message = FD_ISSET(eee->sock, &socket_mask);
multicast_has_message = FD_ISSET(eee->udp_multicast_sock, &socket_mask);
tuntap_has_message = FD_ISSET(eee->device.fd, &socket_mask);
#endif

time_t now = time(NULL);

// make sure ciphers are updated before the packet is treated
if((now - lastTransop) > TRANSOP_TICK_INTERVAL) {
Expand All @@ -2945,56 +3025,54 @@ int run_edge_loop (n2n_edge_t *eee) {
eee->transop.tick(&eee->transop, now);
}

if(rc > 0) {
// any or all of the FDs could have input; check them all
// any or all of the FDs could have input; check them all

// external
if((eee->sock >= 0) && FD_ISSET(eee->sock, &socket_mask)) {
if(0 != fetch_and_eventually_process_data(eee, eee->sock,
pktbuf, &expected, &position,
now)) {
*eee->keep_running = false;
break;
}
if(eee->conf.connect_tcp) {
if((expected >= N2N_PKT_BUF_SIZE) || (position >= N2N_PKT_BUF_SIZE)) {
// something went wrong, possibly even before
// e.g. connection failure/closure in the middle of transmission (between len & data)
supernode_disconnect(eee);
eee->sn_wait = 1;

expected = sizeof(uint16_t);
position = 0;
}
// external
if (sock_has_message) {
if(0 != fetch_and_eventually_process_data(eee, eee->sock,
pktbuf, &expected, &position,
now)) {
*eee->keep_running = false;
break;
}
if(eee->conf.connect_tcp) {
if((expected >= N2N_PKT_BUF_SIZE) || (position >= N2N_PKT_BUF_SIZE)) {
// something went wrong, possibly even before
// e.g. connection failure/closure in the middle of transmission (between len & data)
supernode_disconnect(eee);
eee->sn_wait = 1;

expected = sizeof(uint16_t);
position = 0;
}
}
}

#ifndef SKIP_MULTICAST_PEERS_DISCOVERY
if(FD_ISSET(eee->udp_multicast_sock, &socket_mask)) {
if(0 != fetch_and_eventually_process_data(eee, eee->udp_multicast_sock,
pktbuf, &expected, &position,
now)) {
*eee->keep_running = false;
break;
}
if (multicast_has_message) {
if(0 != fetch_and_eventually_process_data(eee, eee->udp_multicast_sock,
pktbuf, &expected, &position,
now)) {
*eee->keep_running = false;
break;
}
}
#endif

if(FD_ISSET(eee->udp_mgmt_sock, &socket_mask)) {
// read from the management port socket
readFromMgmtSocket(eee);
if (management_has_message) {
// read from the management port socket
readFromMgmtSocket(eee);

if(!(*eee->keep_running))
break;
}
if(!(*eee->keep_running))
break;
}

#ifndef _WIN32
if(FD_ISSET(eee->device.fd, &socket_mask)) {
// read an ethernet frame from the TAP socket; write on the IP socket
edge_read_from_tap(eee);
}
#endif
if (tuntap_has_message) {
// read an ethernet frame from the TAP socket; write on the IP socket
edge_read_from_tap(eee);
}
#endif

// finished processing select data
update_supernode_reg(eee, now);
Expand Down Expand Up @@ -3055,7 +3133,9 @@ int run_edge_loop (n2n_edge_t *eee) {
send_unregister_super(eee);

#ifdef _WIN32
traceEvent(TRACE_NORMAL, "start waiting for tun read thread");
WaitForSingleObject(tun_read_thread, INFINITE);
traceEvent(TRACE_NORMAL, "finish waiting for tun read thread");
#endif

supernode_disconnect(eee);
Expand Down
2 changes: 1 addition & 1 deletion tools/n2n-portfwd.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
#include "random_numbers.h" // for n2n_rand, n2n_seed, n2n_srand

#ifdef _WIN32
#include <winsock.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <netinet/in.h> // for sockaddr_in, htonl, htons, INADDR_LOOP...
Expand Down
2 changes: 1 addition & 1 deletion tools/n2n-route.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
#endif

#ifdef _WIN32
#include <winsock.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <arpa/inet.h> // for inet_pton
Expand Down
Loading