void listeners_reload(struct Listener_head *existing_listeners, struct Listener_head *new_listeners, const struct Table_head *tables, struct ev_loop *loop) { struct Listener *iter_existing = SLIST_FIRST(existing_listeners); struct Listener *iter_new = SLIST_FIRST(new_listeners); while (iter_existing != NULL || iter_new != NULL) { int compare_result; char address[ADDRESS_BUFFER_SIZE]; if (iter_existing == NULL) compare_result = 1; else if (iter_new == NULL) compare_result = -1; else compare_result = address_compare(iter_existing->address, iter_new->address); if (compare_result > 0) { struct Listener *new_listener = iter_new; iter_new = SLIST_NEXT(iter_new, entries); notice("Listener %s added.", display_address(new_listener->address, address, sizeof(address))); SLIST_REMOVE(new_listeners, new_listener, Listener, entries); add_listener(existing_listeners, new_listener); init_listener(new_listener, tables, loop); /* -1 for removing from new_listeners */ listener_ref_put(new_listener); } else if (compare_result == 0) { notice ("Listener %s updated.", display_address(iter_existing->address, address, sizeof(address))); listener_update(iter_existing, iter_new, tables); iter_existing = SLIST_NEXT(iter_existing, entries); iter_new = SLIST_NEXT(iter_new, entries); } else { struct Listener *removed_listener = iter_existing; iter_existing = SLIST_NEXT(iter_existing, entries); notice("Listener %s removed.", display_address(removed_listener->address, address, sizeof(address))); SLIST_REMOVE(existing_listeners, removed_listener, Listener, entries); close_listener(loop, removed_listener); /* -1 for removing from existing_listeners */ listener_ref_put(removed_listener); } } }
int main ( int argc, char **argv ) { struct hijack_options options; struct hijack_listener listener; struct sigaction sa; /* Parse command-line options */ if ( parse_options ( argc, argv, &options ) < 0 ) exit ( 1 ); /* Set up syslog connection */ openlog ( basename ( argv[0] ), LOG_PID, LOG_DAEMON ); /* Set up listening socket */ if ( open_listener ( options.interface, &listener ) < 0 ) exit ( 1 ); /* Daemonise on demand */ if ( options.daemonise ) { if ( daemonise ( options.interface ) < 0 ) exit ( 1 ); } /* Avoid creating zombies */ memset ( &sa, 0, sizeof ( sa ) ); sa.sa_handler = SIG_IGN; sa.sa_flags = SA_RESTART | SA_NOCLDWAIT; if ( sigaction ( SIGCHLD, &sa, NULL ) < 0 ) { logmsg ( LOG_ERR, "Could not set SIGCHLD handler: %s", strerror ( errno ) ); exit ( 1 ); } /* Set 'signalled' flag on SIGINT or SIGHUP */ sa.sa_handler = flag_signalled; sa.sa_flags = SA_RESTART | SA_RESETHAND; if ( sigaction ( SIGINT, &sa, NULL ) < 0 ) { logmsg ( LOG_ERR, "Could not set SIGINT handler: %s", strerror ( errno ) ); exit ( 1 ); } if ( sigaction ( SIGHUP, &sa, NULL ) < 0 ) { logmsg ( LOG_ERR, "Could not set SIGHUP handler: %s", strerror ( errno ) ); exit ( 1 ); } /* Listen for hijackers */ if ( listen_for_hijackers ( &listener, options.interface ) < 0 ) exit ( 1 ); close_listener ( &listener ); return 0; }
/* * close_listeners - close and free all listeners that are not being used */ void close_listeners() { struct Listener *listener; struct Listener *listener_next = 0; /* * close all 'extra' listening ports we have */ for (listener = ListenerPollList; listener; listener = listener_next) { listener_next = listener->next; close_listener(listener); } }
/* * close_listeners - close and free all listeners that are not being used */ void close_listeners() { struct Listener* listener; struct Listener* listener_next = 0; /* * close all 'extra' listening ports we have */ for (listener = ListenerPollList; listener; listener = listener_next) { listener_next = listener->next; if (0 == listener->active && 0 == listener->ref_count) close_listener(listener); } }
bool CHttpServer::init() { RAWTRACE("Open listening socket..."); close_listener(); m_listener = socket(AF_INET, SOCK_STREAM, 0); if (m_listener == INVALID_SOCKET) { RAWLOG_ERROR1("Can not create listener: %d", RHO_NET_ERROR_CODE); return false; } int enable = 1; if (setsockopt(m_listener, SOL_SOCKET, SO_REUSEADDR, (const char *)&enable, sizeof(enable)) == SOCKET_ERROR) { RAWLOG_ERROR1("Can not set socket option (SO_REUSEADDR): %d", RHO_NET_ERROR_CODE); close_listener(); return false; } struct sockaddr_in sa; memset(&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; sa.sin_port = htons((uint16_t)m_port); sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK); if (bind(m_listener, (const sockaddr *)&sa, sizeof(sa)) == SOCKET_ERROR) { RAWLOG_ERROR2("Can not bind to port %d: %d", m_port, RHO_NET_ERROR_CODE); close_listener(); return false; } if (listen(m_listener, 128) == SOCKET_ERROR) { RAWLOG_ERROR1("Can not listen on socket: %d", RHO_NET_ERROR_CODE); close_listener(); return false; } RAWLOG_INFO1("Listen for connections on port %d", m_port); return true; }
void terminate(int signal) { // Block SIGINT sigset_t set; sigemptyset(&set); sigaddset (&set, SIGINT); sigprocmask(SIG_BLOCK, &set, NULL); #ifdef DEBUG fprintf(printf_file, "Terminating...\n"); fflush(printf_file); #endif close_listener(); exit(0); }
/* * add_listener- create a new listener * port - the port number to listen on * vhost_ip - if non-null must contain a valid IP address string in * the format "255.255.255.255" */ void add_listener(int port, const char *vhost_ip, int family, int ssl) { struct Listener *listener; struct rb_sockaddr_storage vaddr; /* * if no port in conf line, don't bother */ if(port == 0) return; memset(&vaddr, 0, sizeof(vaddr)); vaddr.ss_family = family; if(vhost_ip != NULL) { if(family == AF_INET) { if(rb_inet_pton(family, vhost_ip, &((struct sockaddr_in *)&vaddr)->sin_addr) <= 0) return; } #ifdef RB_IPV6 else { if(rb_inet_pton(family, vhost_ip, &((struct sockaddr_in6 *)&vaddr)->sin6_addr) <= 0) return; } #endif } else { switch(family) { case AF_INET: ((struct sockaddr_in *)&vaddr)->sin_addr.s_addr = INADDR_ANY; break; #ifdef RB_IPV6 case AF_INET6: memcpy(&((struct sockaddr_in6 *)&vaddr)->sin6_addr, &in6addr_any, sizeof(struct in6_addr)); break; default: return; #endif } } switch(family) { case AF_INET: SET_SS_LEN(&vaddr, sizeof(struct sockaddr_in)); ((struct sockaddr_in *)&vaddr)->sin_port = htons(port); break; #ifdef RB_IPV6 case AF_INET6: SET_SS_LEN(&vaddr, sizeof(struct sockaddr_in6)); ((struct sockaddr_in6 *)&vaddr)->sin6_port = htons(port); break; #endif default: break; } if((listener = find_listener(&vaddr))) { if(listener->F != NULL) return; } else { listener = make_listener(&vaddr); listener->next = ListenerPollList; ListenerPollList = listener; } listener->F = NULL; listener->ssl = ssl; if(inetport(listener)) listener->active = 1; else close_listener(listener); }
bool CHttpServer::init() { if (verbose) RAWTRACE("Open listening socket..."); close_listener(); //m_listener = socket(AF_INET, SOCK_STREAM, 0); m_listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (m_listener == INVALID_SOCKET) { if (verbose) RAWLOG_ERROR1("Can not create listener: %d", RHO_NET_ERROR_CODE); return false; } int enable = 1; if (setsockopt(m_listener, SOL_SOCKET, SO_REUSEADDR, (const char *)&enable, sizeof(enable)) == SOCKET_ERROR) { if (verbose) RAWLOG_ERROR1("Can not set socket option (SO_REUSEADDR): %d", RHO_NET_ERROR_CODE); close_listener(); return false; } struct sockaddr_in sa; memset(&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; sa.sin_port = htons((uint16_t)m_port); if (m_enable_external_access) { sa.sin_addr.s_addr = htonl(INADDR_ANY); } else { sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK); } if (bind(m_listener, (const sockaddr *)&sa, sizeof(sa)) == SOCKET_ERROR) { if (verbose) RAWLOG_ERROR2("Can not bind to port %d: %d", m_port, RHO_NET_ERROR_CODE); close_listener(); return false; } if (listen(m_listener, 128) == SOCKET_ERROR) { if (verbose) RAWLOG_ERROR1("Can not listen on socket: %d", RHO_NET_ERROR_CODE); close_listener(); return false; } // detect local IP adress struct sockaddr_in sin; memset(&sin, 0, sizeof(sin)); //sin.sin_len = sizeof(sin); sin.sin_family = AF_INET; // or AF_INET6 (address family) socklen_t len = sizeof(sin); if (getsockname(m_listener, (struct sockaddr *)&sin, &len) < 0) { // Handle error here if (verbose) RAWLOG_ERROR("Can not detect local IP adress"); } else { m_IP_adress = inet_ntoa(sin.sin_addr); } if (verbose) RAWLOG_INFO1("Listen for connections on port %d", m_port); return true; }
/** Main loop for redundant processes */ void redundancy_main(uint64_t process_type, uint64_t process_type_version, int port, uint64_t input_process_type, void (*process_input)(char *, int), void (*vote_and_process)(), void (*flush_inputs)(), int flags, int argc, char ** argv) { // Get pid pid = getpid(); // Open debug file #ifdef DEBUG_FILE char fn[64]; sprintf(fn, "redundancy_%llu.log", pid); debug_file = fopen(fn, "a"); printf_file = (debug_file != NULL) ? debug_file : stdin; #else printf_file = stdin; #endif // Store process type ptype = process_type; ptype_version = process_type_version; // Get start time struct timeval tv; gettimeofday(&tv, NULL); timestamp = (tv.tv_sec * 100 + (tv.tv_usec / 10000)) & 0x00000000ffffffffLLU; // In 100ths of seconds // Set up signal handling signal(SIGABRT, terminate); signal(SIGTERM, terminate); signal(SIGINT, terminate); // There are no last inputs processed memset(&last_inputs_processes, 0, sizeof last_inputs_processes); // Check number of args if (argc != 2) { fprintf(printf_file, "Usage: %s <host_num>\n", argv[0]); fflush(printf_file); exit(1); } // Get host number sscanf (argv[1], "%llu", &host_num); // Register address pthread_mutex_lock(&sisis_addr_mutex); if (sisis_register(sisis_addr, process_type, process_type_version, host_num, pid, timestamp) != 0) { fprintf(printf_file, "Failed to register SIS-IS address.\n"); fflush(printf_file); exit(1); } pthread_mutex_unlock(&sisis_addr_mutex); gettimeofday(×tamp_sisis_registered, NULL); // Status fprintf(printf_file, "Opening socket at %s on port %i.\n", sisis_addr, port); fflush(printf_file); // Set up socket address info struct addrinfo hints, *addr; memset(&hints, 0, sizeof hints); hints.ai_family = AF_INET6; // IPv6 hints.ai_socktype = SOCK_DGRAM; char port_str[8]; sprintf(port_str, "%u", port); getaddrinfo(sisis_addr, port_str, &hints, &addr); // Create socket if ((sockfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol)) == -1) { fprintf(printf_file, "Failed to open socket.\n"); fflush(printf_file); exit(1); } // Bind to port if (bind(sockfd, addr->ai_addr, addr->ai_addrlen) == -1) { fprintf(printf_file, "Failed to bind socket to port.\n"); fflush(printf_file); close_listener(); exit(2); } // Are we checking redundancy? if (!(flags & REDUNDANCY_MAIN_FLAG_SKIP_REDUNDANCY)) { // Open socket to stop redundancy sprintf(port_str, "%u", STOP_REDUNDANCY_PORT); stop_redundancy_socket = make_socket(port_str); } // Short sleep while address propagates usleep(50000); // 50ms // Status message inet_ntop(AF_INET6, &((struct sockaddr_in6 *)(addr->ai_addr))->sin6_addr, sisis_addr, INET6_ADDRSTRLEN); fprintf(printf_file, "Socket opened at %s on port %u.\n", sisis_addr, ntohs(((struct sockaddr_in *)(addr->ai_addr))->sin_port)); fflush(printf_file); // Info to subscribe to RIB changes struct subscribe_to_rib_changes_info info; // Are we checking redundancy? if (!(flags & REDUNDANCY_MAIN_FLAG_SKIP_REDUNDANCY)) { // Set up signal handling for alarm signal(SIGALRM, recheck_redundance_alarm_handler); // Check redundancy check_redundancy(); // Subscribe to RIB changes memset(&info, 0, sizeof info); info.rib_add_ipv6_route = rib_monitor_add_ipv6_route; info.rib_remove_ipv6_route = rib_monitor_remove_ipv6_route; subscribe_to_rib_changes(&info); } // Set of sockets for select call when waiting for other inputs fd_set socks; // Timeout information for select call struct timeval select_timeout; struct timeval start_time, cur_time, tmp1, tmp2; // Number of input processes int num_input_processes; int num_input = 0; // Wait for message struct sockaddr_in6 remote_addr; int buflen; char buf[RECV_BUFFER_SIZE]; socklen_t addr_size = sizeof remote_addr; while (1) { // Set of sockets for main select call int main_socks_max_fd; fd_set main_socks; FD_ZERO(&main_socks); FD_SET(sockfd, &main_socks); // Are we checking redundancy? if (!(flags & REDUNDANCY_MAIN_FLAG_SKIP_REDUNDANCY)) { FD_SET(stop_redundancy_socket, &main_socks); main_socks_max_fd = MAX(stop_redundancy_socket, sockfd)+1; } else main_socks_max_fd = sockfd+1; // Wait for message on either socket if (select(main_socks_max_fd, &main_socks, NULL, NULL, NULL) > 0) { // Stop redundancy socket if (FD_ISSET(stop_redundancy_socket, &main_socks)) { if ((buflen = recvfrom(stop_redundancy_socket, buf, RECV_BUFFER_SIZE, 0, NULL, NULL)) != -1) { // Very primative security if (buflen == strlen(PASSWORD) && memcmp(buf, PASSWORD, buflen) == 0) { #ifdef DEBUG fprintf(printf_file, "Stopping Redundancy.\n"); fflush(printf_file); #endif // Unsubscribe to RIB changes subscribe_to_rib_changes(&info); redundancy_flag = 0; } } } // Input socket else if (FD_ISSET(sockfd, &main_socks)) { do { // Read from socket if ((buflen = recvfrom(sockfd, buf, RECV_BUFFER_SIZE, 0, (struct sockaddr *)&remote_addr, &addr_size)) != -1) { #ifdef DEBUG gettimeofday(&cur_time, NULL); char addr[INET6_ADDRSTRLEN]; if (inet_ntop(AF_INET6, &(remote_addr.sin6_addr), addr, INET6_ADDRSTRLEN) != NULL) fprintf(printf_file, "[%llu.%06llu] Input from %*s.\n", (uint64_t)cur_time.tv_sec, (uint64_t)cur_time.tv_usec, INET6_ADDRSTRLEN, addr); fflush(printf_file); #endif // Setup input if (num_input == 0) { // Set socket select timeout select_timeout.tv_sec = GATHER_RESULTS_TIMEOUT_USEC / 1000000; select_timeout.tv_usec = GATHER_RESULTS_TIMEOUT_USEC % 1000000; // Get start time gettimeofday(&start_time, NULL); } else { // Determine new socket select timeout gettimeofday(&cur_time, NULL); timersub(&cur_time, &start_time, &tmp1); timersub(&select_timeout, &tmp1, &tmp2); select_timeout.tv_sec = tmp2.tv_sec; select_timeout.tv_usec = tmp2.tv_usec; } // Record input num_input++; // Process the input process_input(buf, buflen); // Check how many input processes there are if (!(flags & REDUNDANCY_MAIN_FLAG_SINGLE_INPUT)) { num_input_processes = get_process_type_count(input_process_type); #ifdef DEBUG fprintf(printf_file, "# inputs: %d\n", num_input); fprintf(printf_file, "# input processes: %d\n", num_input_processes); fprintf(printf_file, "Waiting %ld.%06ld seconds for more results.\n", (long)(select_timeout.tv_sec), (long)(select_timeout.tv_usec)); fflush(printf_file); #endif } } // Set of sockets for select call when waiting for other inputs FD_ZERO(&socks); FD_SET(sockfd, &socks); } while(!(flags & REDUNDANCY_MAIN_FLAG_SINGLE_INPUT) && num_input < num_input_processes && select(sockfd+1, &socks, NULL, NULL, &select_timeout) > 0); // Check that at least 1/2 of the processes sent inputs if (!(flags & REDUNDANCY_MAIN_FLAG_SINGLE_INPUT) && num_input <= num_input_processes/2) { // Check how late these are for the last set of inputs gettimeofday(&cur_time, NULL); timersub(&cur_time, &last_inputs_processes, &tmp1); //if ((tmp1.tv_sec * 1000000 + tmp1.tv_usec) < GATHER_RESULTS_TIMEOUT_USEC * 1.25) fprintf(printf_file, "Late by %llu.%06llu seconds.\n", (uint64_t)tmp1.tv_sec, (uint64_t)tmp1.tv_usec); fflush(printf_file); // Flush inputs flush_inputs(); #ifdef DEBUG fprintf(printf_file, "Not enough inputs for a vote.\n"); fflush(printf_file); #endif } else { #ifdef DEBUG fprintf(printf_file, "Voting...\n"); fflush(printf_file); #endif // Record time gettimeofday(&last_inputs_processes, NULL); // Vote and process results vote_and_process(); } // Reset num_input = 0; } } } // Close socket close_listener(); }
void remove_listener(struct Listener_head *listeners, struct Listener *listener) { SLIST_REMOVE(listeners, listener, Listener, entries); close_listener(EV_DEFAULT, listener); free_listener(listener); }
static int inetport(struct Listener* listener) { struct irc_sockaddr lsin; int fd; int opt = 1; /* * At first, open a new socket */ fd = comm_open(DEF_FAM, SOCK_STREAM, 0, "Listener socket"); #ifdef IPV6 if (!IN6_ARE_ADDR_EQUAL((struct in6_addr *)&listener->addr, &in6addr_any)) { #else if (INADDR_ANY != listener->addr.sins.sin.s_addr) { #endif inetntop(DEF_FAM, &IN_ADDR(listener->addr), listener->vhost, HOSTLEN); listener->name = listener->vhost; } if (fd == -1) { report_error(L_ALL, "opening listener socket %s:%s", get_listener_name(listener), errno); return 0; } else if ((HARD_FDLIMIT - 10) < fd) { report_error(L_ALL, "no more connections left for listener %s:%s", get_listener_name(listener), errno); fd_close(fd); return 0; } /* * XXX - we don't want to do all this crap for a listener * set_sock_opts(listener); */ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*) &opt, sizeof(opt))) { report_error(L_ALL, "setting SO_REUSEADDR for listener %s:%s", get_listener_name(listener), errno); fd_close(fd); return 0; } /* * Bind a port to listen for new connections if port is non-null, * else assume it is already open and try get something from it. */ memset(&lsin, 0, sizeof(struct irc_sockaddr)); S_FAM(lsin) = DEF_FAM; copy_s_addr(S_ADDR(lsin), IN_ADDR(listener->addr)); S_PORT(lsin) = htons(listener->port); if (bind(fd, (struct sockaddr*) &SOCKADDR(lsin), sizeof(struct irc_sockaddr))) { report_error(L_ALL, "binding listener socket %s:%s", get_listener_name(listener), errno); fd_close(fd); return 0; } if (listen(fd, HYBRID_SOMAXCONN)) { report_error(L_ALL, "listen failed for %s:%s", get_listener_name(listener), errno); fd_close(fd); return 0; } /* * XXX - this should always work, performance will suck if it doesn't */ if (!set_non_blocking(fd)) report_error(L_ALL, NONB_ERROR_MSG, get_listener_name(listener), errno); listener->fd = fd; /* Listen completion events are READ events .. */ accept_connection(fd, listener); return 1; } static struct Listener* find_listener(int port, struct irc_inaddr *addr) { struct Listener* listener = NULL; struct Listener* last_closed = NULL; for (listener = ListenerPollList; listener; listener = listener->next) { if ( (port == listener->port) && (!memcmp(&PIN_ADDR(addr), &IN_ADDR(listener->addr), sizeof(struct irc_inaddr)))) { /* Try to return an open listener, otherwise reuse a closed one */ if (listener->fd == -1) last_closed = listener; else return listener; } } return last_closed; } /* * add_listener- create a new listener * port - the port number to listen on * vhost_ip - if non-null must contain a valid IP address string in * the format "255.255.255.255" */ void add_listener(int port, const char* vhost_ip) { struct Listener* listener; struct irc_inaddr vaddr; /* * if no port in conf line, don't bother */ if (port == 0) return; #ifdef IPV6 copy_s_addr(IN_ADDR(vaddr), &in6addr_any); #else copy_s_addr(IN_ADDR(vaddr), INADDR_ANY); #endif if (vhost_ip) { if(inetpton(DEF_FAM, vhost_ip, &IN_ADDR(vaddr)) <= 0) return; } if ((listener = find_listener(port, &vaddr))) { if (listener->fd > -1) return; } else { listener = make_listener(port, &vaddr); listener->next = ListenerPollList; ListenerPollList = listener; } listener->fd = -1; if (inetport(listener)) listener->active = 1; else close_listener(listener); } /* * close_listener - close a single listener */ void close_listener(struct Listener* listener) { assert(listener != NULL); if(listener == NULL) return; if (listener->fd >= 0) { fd_close(listener->fd); listener->fd = -1; } listener->active = 0; if (listener->ref_count) return; free_listener(listener); }
int main(int argc, char *argv[]) { if (argc < 1) { dprintf(STDERR_FILENO, "wrun called without argument\n"); terminate_nocore(); } shift(&argc, &argv); if (argc > 1 && !strcmp(argv[0], "--tool_name")) { shift(&argc, &argv); tool_name = shift(&argc, &argv); } fill_std_fd_info_identity(STDIN_FILENO); fill_std_fd_info_identity(STDOUT_FILENO); fill_std_fd_info_identity(STDERR_FILENO); bool force_redirects = false; bool silent_breakaway = false; int port; bool terminate = !get_outbash_infos(&port, &force_redirects); struct string outbash_command = string_create(""); if (argc && !strcmp(argv[0], ":")) { shift(&argc, &argv); string_append(&outbash_command, "cd:~\n"); } else { char* cwd = agetcwd(); if (is_absolute_drive_fs_path(cwd)) { char* cwd_win32 = convert_drive_fs_path_to_win32(cwd); string_append(&outbash_command, "cd:"); string_append(&outbash_command, cwd_win32); string_append(&outbash_command, "\n"); free(cwd_win32); } free(cwd); } while (argc && !strncmp(argv[0], "--", 2)) { if (!strcmp(argv[0], "--")) { shift(&argc, &argv); break; } if (!strcmp(argv[0], "--env")) { shift(&argc, &argv); while (argc && strncmp(argv[0], "--", 2) != 0 && *argv[0] != '\0' && strchr(argv[0] + 1, '=')) { string_append(&outbash_command, "env:"); string_append(&outbash_command, argv[0]); string_append(&outbash_command, "\n"); shift(&argc, &argv); } } else if (!strcmp(argv[0], "--force-redirects")) { force_redirects = true; shift(&argc, &argv); } else if (!strcmp(argv[0], "--silent-breakaway")) { silent_breakaway = true; shift(&argc, &argv); } else if (!strcmp(argv[0], "--help")) { print_help(); exit(1); } else { dprintf(STDERR_FILENO, "%s: unknown command line option: %s\n", tool_name, argv[0]); dprintf(STDERR_FILENO, "type %s --help for more information.\n", tool_name); terminate_nocore(); } } if (terminate) terminate_nocore(); check_argc(argc); decide_will_redirect(STDIN_FILENO, force_redirects); decide_will_redirect(STDOUT_FILENO, force_redirects); decide_will_redirect(STDERR_FILENO, force_redirects); int sock_ctrl = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sock_ctrl < 0) { dprintf(STDERR_FILENO, "%s: socket() failed: %s\n", tool_name, my_strerror(errno)); terminate_nocore(); } #define STDIN_NEEDS_SOCKET_REDIRECT 1 #define STDOUT_NEEDS_SOCKET_REDIRECT 2 #define STDERR_NEEDS_SOCKET_REDIRECT 4 #define STDERR_SOCKREDIR_TO_STDOUT 8 int redirects = (needs_socket_redirect(STDIN_FILENO) ? STDIN_NEEDS_SOCKET_REDIRECT : 0) | (needs_socket_redirect(STDOUT_FILENO) ? STDOUT_NEEDS_SOCKET_REDIRECT : 0); if (needs_socket_redirect(STDERR_FILENO)) { if ((redirects & STDOUT_NEEDS_SOCKET_REDIRECT) && are_stdfd_to_same_thing(STDOUT_FILENO, STDERR_FILENO)) redirects |= STDERR_SOCKREDIR_TO_STDOUT; else redirects |= STDERR_NEEDS_SOCKET_REDIRECT; } struct listening_socket lsock_in = NO_LISTENING_SOCKET; struct listening_socket lsock_out = NO_LISTENING_SOCKET; struct listening_socket lsock_err = NO_LISTENING_SOCKET; if (redirects & STDIN_NEEDS_SOCKET_REDIRECT) lsock_in = socket_listen_one_loopback(); if (redirects & STDOUT_NEEDS_SOCKET_REDIRECT) lsock_out = socket_listen_one_loopback(); if (redirects & STDERR_NEEDS_SOCKET_REDIRECT) lsock_err = socket_listen_one_loopback(); ask_redirect(&outbash_command, "stdin:", STDIN_FILENO, lsock_in.port); ask_redirect(&outbash_command, "stdout:", STDOUT_FILENO, lsock_out.port); ask_redirect(&outbash_command, "stderr:", STDERR_FILENO, (redirects & STDERR_NEEDS_SOCKET_REDIRECT) ? lsock_err.port : lsock_out.port); if (silent_breakaway) string_append(&outbash_command, "silent_breakaway:1\n"); char* win32_module; if (is_absolute_drive_fs_path(argv[0])) { win32_module = convert_drive_fs_path_to_win32(argv[0]); string_append(&outbash_command, "module:"); string_append(&outbash_command, win32_module); string_append(&outbash_command, "\n"); } else { win32_module = convert_slash_to_backslash(argv[0]); } const bool module_need_quotes = (NULL != strpbrk(win32_module, " \t")); string_append(&outbash_command, "run:"); if (module_need_quotes) string_append(&outbash_command, "\""); string_append(&outbash_command, win32_module); if (module_need_quotes) string_append(&outbash_command, "\""); free(win32_module); for (int i = 1; i < argc; i++) { string_append(&outbash_command, " "); string_append(&outbash_command, argv[i]); } string_append(&outbash_command, "\n\n"); //dprintf(STDOUT_FILENO, "%s", outbash_command.str); //return EXIT_FAILURE; signal(SIGPIPE, SIG_IGN); sigset_t signal_set, orig_mask; //////////////////////////// unblock SIGUSR1 sigemptyset(&signal_set); sigaddset(&signal_set, SIGUSR1); pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL); //////////////////////////// block SIGTSTP sigemptyset(&signal_set); sigaddset(&signal_set, SIGTSTP); pthread_sigmask(SIG_BLOCK, &signal_set, &orig_mask); //////////////////////////// install custom SIGTSTP handler if signal was not ignored struct sigaction sa; sigaction(SIGTSTP, NULL, &sa); const bool ignore_sigtstp = (sa.sa_handler == SIG_IGN); if (!ignore_sigtstp) { sa.sa_handler = tstop_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sigaction(SIGTSTP, &sa, NULL); } //////////////////////////// install custom SIGUSR1 handler to wake-up blocked IO forwarding threads // NOTE: the handler itself do nothing, but any blocked syscall will return with EINTR error sa.sa_handler = noop_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sigaction(SIGUSR1, &sa, NULL); struct sockaddr_in serv_addr; memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); serv_addr.sin_port = htons(port); if (connect(sock_ctrl, (const struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) { // NOTE: I'm not sure that WSL does what Linux does concerning // http://www.madore.org/~david/computers/connect-intr.html // for now we do not expect to recover after an interruption here. dprintf(STDERR_FILENO, "%s: connect() failed: %s\n", tool_name, my_strerror(errno)); terminate_nocore(); } if (send_all(sock_ctrl, outbash_command.str, outbash_command.length, 0) < 0) { dprintf(STDERR_FILENO, "%s: send_all() failed: %s\n", tool_name, my_strerror(errno)); terminate_nocore(); } string_destroy(&outbash_command); static struct forward_state fs[3]; fs_init_accept_as_needed(&fs[STDIN_FILENO], &lsock_in, redirects & STDIN_NEEDS_SOCKET_REDIRECT, STDIN_FILENO, "stdin"); fs_init_accept_as_needed(&fs[STDOUT_FILENO], &lsock_out, redirects & STDOUT_NEEDS_SOCKET_REDIRECT, STDOUT_FILENO, "stdout"); fs_init_accept_as_needed(&fs[STDERR_FILENO], &lsock_err, redirects & STDERR_NEEDS_SOCKET_REDIRECT, STDERR_FILENO, "stderr"); char *line = ctrl_readln(sock_ctrl, NULL); if (!line || strcmp(line, "connected")) { dprintf(STDERR_FILENO, "%s: did not receive connection validation from outbash.exe\n", tool_name); terminate_nocore(); } close_listener(&lsock_in); close_listener(&lsock_out); close_listener(&lsock_err); enum state_e state = RUNNING; int program_return_code = 255; pthread_t forward_threads[3]; bool active_threads[3] = {0}; for (int i = 0; i < 3; i++) { if ((!fs[i].dead_in) || (!fs[i].dead_out)) { int err = pthread_create(&forward_threads[i], NULL, forward_one_stream, &fs[i]); if (err != 0) { dprintf(STDERR_FILENO, "%s: pthread_create() failed: %s\n", tool_name, my_strerror(err)); terminate_nocore(); } active_threads[i] = true; } } int nfds = sock_ctrl + 1; while (state != TERMINATED) { fd_set rfds; FD_ZERO(&rfds); if (sock_ctrl < 0 || sock_ctrl >= FD_SETSIZE) { dprintf(STDERR_FILENO, "%s: sock_ctrl=%d out of range\n", tool_name, sock_ctrl); abort(); } FD_SET(sock_ctrl, &rfds); int pselect_res = pselect(nfds, &rfds, NULL, NULL, NULL, &orig_mask); // tstop_handler can run here int pselect_errno = errno; if (tstop_req && state == RUNNING) { int r = send_all(sock_ctrl, "suspend\n", strlen("suspend\n"), 0); if (r < 0 && err_is_connection_broken(errno)) { // We will never be able to ask outbash to suspend the // Windows process, the expected reason is that it actually // has already terminated and we don't know yet about that, // so stop the suspend forwarding mechanism and suspend // ourselves immediately. shutdown(sock_ctrl, SHUT_WR); // also we can't send anything anymore // XXX to comment for WSL bug workaround? proba low here... signal(SIGTSTP, SIG_DFL); state = DYING; raise(SIGTSTP); pthread_sigmask(SIG_SETMASK, &orig_mask, NULL); } else if (r < 0) { // other errors dprintf(STDERR_FILENO, "%s: send_all(\"suspend\\n\") failed: %s\n", tool_name, my_strerror(errno)); abort(); } else { // OK // It's up to outbash now, just wait for its "suspend_ok" // answer after it has suspended the Windows process. state = SUSPEND_PENDING; } } if (pselect_res < 0 && pselect_errno == EINTR) { // "On error, -1 is returned, and errno is set appropriately; // the sets and timeout become undefined, so do not rely on // their contents after an error." continue; } if (pselect_res < 0) { dprintf(STDERR_FILENO, "%s: pselect() failed: %s\n", tool_name, my_strerror(pselect_errno)); abort(); } if (FD_ISSET(sock_ctrl, &rfds)) { while (1) { int nonblock_marker; line = ctrl_readln(sock_ctrl, &nonblock_marker); if (!line && nonblock_marker) break; if (line && !strcmp(line, "suspend_ok")) { if (state == SUSPEND_PENDING) { signal(SIGTSTP, SIG_DFL); raise(SIGTSTP); sigset_t previous_mask; pthread_sigmask(SIG_SETMASK, &orig_mask, &previous_mask); // >>> Process will Stop here, until SIGCONT <<< pthread_sigmask(SIG_SETMASK, &previous_mask, NULL); tstop_req = 0; int r = send_all(sock_ctrl, "resume\n", strlen("resume\n"), 0); if (r < 0 && err_is_connection_broken(errno)) { // killed when suspended (if this is possible?) // or maybe just before an attempt? shutdown(sock_ctrl, SHUT_WR); // XXX to comment for WSL bug workaround? proba low here... state = DYING; pthread_sigmask(SIG_SETMASK, &orig_mask, NULL); } else if (r < 0) { dprintf(STDERR_FILENO, "%s: send_all(\"resume\\n\") failed: %s\n", tool_name, my_strerror(errno)); abort(); } else { state = RUNNING; sa.sa_handler = tstop_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sigaction(SIGTSTP, &sa, NULL); } } else { dprintf(STDERR_FILENO, "%s: spurious \"suspend_ok\" received\n", tool_name); } } else { // not "suspend_ok" => for now only other cases are exit conditions program_return_code = get_return_code(line); shutdown(sock_ctrl, SHUT_RDWR); signal(SIGTSTP, ignore_sigtstp ? SIG_IGN : SIG_DFL); if ((tstop_req && state == RUNNING) || state == SUSPEND_PENDING) { // We expect to stop soon, but not without flushing the OS TCP // buffers and our owns, and other WSL processes in a pipe might // already be suspended, so we better honor suspend requests ASAP. raise(SIGTSTP); } pthread_sigmask(SIG_SETMASK, &orig_mask, NULL); tstop_req = 0; state = TERMINATED; break; } } } } // XXX: this is not ideal if the Win32 side managed to maintain the // redirection socket beyond the lifetime of the launched process, // however things seem to already be not reliable for Windows reasons // in this case if (active_threads[0]) { __sync_fetch_and_add(&fs[0].ask_terminate, 1); useconds_t usec_sleep = 1000; while (!__sync_fetch_and_add(&fs[0].finished, 0)) { pthread_kill(forward_threads[0], SIGUSR1); usleep(usec_sleep); usec_sleep *= 2; if (usec_sleep > 60000000) usec_sleep = 60000000; } } for (int i = 0; i < 3; i++) if (active_threads[i]) pthread_join(forward_threads[i], NULL); return program_return_code; }
void remove_listener(struct Listener_head *listeners, struct Listener *listener, struct ev_loop *loop) { SLIST_REMOVE(listeners, listener, Listener, entries); close_listener(loop, listener); listener_ref_put(listener); }
void terminate(int signal) { printf("Terminating...\n"); close_listener(); exit(0); }