diff --git a/include/n2n_typedefs.h b/include/n2n_typedefs.h index f28ab6584..89032ae4f 100644 --- a/include/n2n_typedefs.h +++ b/include/n2n_typedefs.h @@ -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. */ diff --git a/src/edge.c b/src/edge.c index f8b7bdc0f..8d5083e25 100644 --- a/src/edge.c +++ b/src/edge.c @@ -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 @@ -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: @@ -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; diff --git a/src/edge_utils.c b/src/edge_utils.c index 4afdb64fa..5688f42d5 100644 --- a/src/edge_utils.c +++ b/src/edge_utils.c @@ -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) { @@ -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 @@ -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); @@ -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) { @@ -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); @@ -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); diff --git a/tools/n2n-portfwd.c b/tools/n2n-portfwd.c index dce283a16..e522ebcb2 100644 --- a/tools/n2n-portfwd.c +++ b/tools/n2n-portfwd.c @@ -34,7 +34,7 @@ #include "random_numbers.h" // for n2n_rand, n2n_seed, n2n_srand #ifdef _WIN32 -#include +#include #include #else #include // for sockaddr_in, htonl, htons, INADDR_LOOP... diff --git a/tools/n2n-route.c b/tools/n2n-route.c index 8ff14b58c..1c0d36bd0 100644 --- a/tools/n2n-route.c +++ b/tools/n2n-route.c @@ -39,7 +39,7 @@ #endif #ifdef _WIN32 -#include +#include #include #else #include // for inet_pton