// Serial to UDP Converter: listen int serial2udp_listen(int port, int *server_socket) { int rc = -1; struct addrinfo testing_addr; // remote_addr used inside getaddrinfo() memset((char *) &testing_addr, 0, sizeof(testing_addr)); struct sockaddr_in6 server_addr; memset((char *) &server_addr, 0, sizeof(server_addr)); // Opening sock *server_socket = socket(AF_INET6, SOCK_DGRAM, 0); if (*server_socket < 0) { rc = 1; UNLLog(LLERROR, "Error while listening for serial2udp wrapper. ERR: %s (%i).\n", strerror(errno), rc); return rc; } // Setting options server_addr.sin6_family = AF_INET6; server_addr.sin6_addr = in6addr_any; server_addr.sin6_port = htons(port); // Binding (checking if address is already in use) if (bind(*server_socket, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0) { rc = 2; UNLLog(LLERROR, "Error while binding for serial2udp wrapper. ERR: %s (%i).\n", strerror(errno), rc); return rc; } return 0; }
// Handling Signals void signal_handler(int signal) { int i = 0; // Find out which signal we're handling switch (signal) { case SIGHUP: // Signal 1 UNLLog(LLINFO, "Caught SIGHUP, closing clients.\n"); for (i = tsclients_socket[0]; i > 0; i++) { UNLLog(LLINFO, "Closing client (%i).\n", tsclients_socket[i]); close(tsclients_socket[i]); } break; case SIGINT: // Signal 2 UNLLog(LLINFO, "Caught SIGINT, killing child.\n"); break; case SIGTERM: // Signal 15 UNLLog(LLINFO, "Caught SIGTERM, killing child.\n"); break; default: UNLLog(LLWARNING, "Caught wrong signal (%d).\n", signal); break; } }
// Serial to UDP Converter: receive int serial2udp_receive(void *c, int server_socket, int bytesToRead) { int length = 0; //memset(c, 0, sizeof(*c)); // useless memset if ((length = read(server_socket, c, bytesToRead)) <= 0) { // Read error UNLLog(LLERROR, "Failed to receive data from UDP (s=%i, l=%i). ERR: %s (%i).\n", server_socket, length, strerror(errno), length); return length; } UNLLog(LLVERBOSE, "Received data from UDP (s=%i, l=%i).\n", server_socket, length); return length; }
// AF_UNIX socket: receive int afsocket_receive(void *c, int server_socket, int bytesToRead) { int length = 0; //memset(c, 0, sizeof(*c)); what's that for??? if ((length = read(server_socket, c, bytesToRead)) <= 0) { // Read error UNLLog(LLERROR, "Failed to receive data from local AF_UNIX (s=%i, l=%i): %s (%i)\n", server_socket, length, strerror(errno), length); return length; } UNLLog(LLVERBOSE, "Received data from local AF_UNIX (s=%i, l=%i).\n", server_socket, length); return length; }
// TAP interface: receive int tap_receive(void *c, int server_socket, int bytesToRead) { int length = 0; //memset(c, 0, sizeof(*c)); if ((length = read(server_socket, c, bytesToRead)) <= 0) { // Read error UNLLog(LLERROR, "Failed to receive data from TAP (s=%i, l=%i). ERR: %s (%i).\n", server_socket, length, strerror(errno), length); return length; } if ( sLogLevel >= LLVERBOSE ) { // In order to avoid excessive hash calculation UNLLog(LLVERBOSE, "Received data from TAP (s=%i, l=%i) Hash = %i\n", server_socket, length, hash((const char*)c, length)); } return length; }
// CMD: add a single command to the CMD line void cmd_add(char **cmd_line, const char *cmd) { if ((int) strnlen(*cmd_line, sizeof(*cmd_line)) + (int) strnlen(cmd, sizeof(*cmd)) + 1 > sysconf(_SC_ARG_MAX)) { // String too long UNLLog(LLERROR, "Cannot add command '%s' (string too long).\n", cmd); exit(1); } strncat(*cmd_line, cmd, strlen(cmd)); }
// AF_UNIX socket: listen int afsocket_listen(char *server_socketfile, char *remote_socketfile, int *server_socket, int *remote_socket) { int rc = -1; struct sockaddr_un remote_addr; memset(&remote_addr, 0, sizeof(remote_addr)); struct sockaddr_un server_addr; memset(&server_addr, 0, sizeof(server_addr)); // Setting AF_UNIX remote (sending) socket *remote_socket = socket(AF_UNIX, SOCK_DGRAM, 0); if (*remote_socket < 0) { rc = 1; UNLLog(LLERROR, "Error while setting remote AF_UNIX: %s (%i)\n",strerror(errno), rc); return rc; } remote_addr.sun_family = AF_UNIX; strncpy(remote_addr.sun_path, remote_socketfile, sizeof(remote_addr.sun_path) - 1); while (connect(*remote_socket, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr_un)) < 0) { rc = 2; UNLLog(LLERROR, "Error while connecting local AF_UNIX: %s (%i)\n",strerror(errno), rc); return rc; } // Setting AF_UNIX local (receiving) socket *server_socket = socket(AF_UNIX, SOCK_DGRAM, 0); if (*server_socket < 0) { rc = 3; UNLLog(LLERROR, "Error while setting local AF_UNIX: %s (%i)\n",strerror(errno), rc); return rc; } server_addr.sun_family = AF_UNIX; strncpy(server_addr.sun_path, server_socketfile, sizeof(server_addr.sun_path) -1 ); if (bind(*server_socket, (struct sockaddr *)&server_addr, sizeof(struct sockaddr_un))) { rc = 4; UNLLog(LLERROR, "Error while binding local AF_UNIX: %s (%i)\n", strerror(errno), rc); return rc; } UNLLog(LLINFO, "Local (%i) and remote (%i) AF_UNIX are configured.\n", *server_socket, *remote_socket); return 0; }
// TAP interface: listen int tap_listen(char *tap_name, int *tap_fd) { char tmp[200]; char *tun_dev = "/dev/net/tun"; int rc = -1; int tap_socket = -1; struct ifreq ifr; memset(&ifr,0,sizeof(ifr)); ifr.ifr_flags = IFF_TAP; // We want TAP interface (not TUN) ifr.ifr_flags |= IFF_NO_PI; // Do not add 4 bytes preamble (we want to send RAW packets) strncpy(ifr.ifr_name, tap_name, IFNAMSIZ); // Setting device name // Checking TAP interface sprintf(tmp, "/sys/class/net/%s/dev_id", tap_name); if (is_file(tmp) != 0) { rc = 1; UNLLog(LLVERBOSE, "Skipping non existent TAP interface (%s).\n", tap_name); return rc; } // Open the clone device if ((*tap_fd = open(tun_dev, O_RDWR)) < 0) { rc = 2; UNLLog(LLERROR, "Error while calling open TUN (%s). ERR: %s (%i)\n", tap_name, strerror(errno), rc); return rc; } // Creating TAP interface if (ioctl(*tap_fd, TUNSETIFF, (void *)&ifr) < 0) { rc = 3; UNLLog(LLINFO, "Skipping TAP (%s), maybe it's not used (%s).\n", tap_name, strerror(errno)); return rc; } // Activate interface if ((tap_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { rc = 4; UNLLog(LLERROR, "Error while activating TAP interface (%s). ERR: %s (%i).\n", tap_name, strerror(errno), rc); return rc; } // Put the inteface "up" ifr.ifr_flags |= IFF_UP; if (ioctl(tap_socket, SIOCSIFFLAGS, &ifr) < 0) { rc = 5; UNLLog(LLVERBOSE, "Error while putting TAP interface up (%s). ERR: %s (%i). Is interface already up?\n", tap_name, strerror(errno), rc); // unl_wrapper will bring the interface in up state //return rc; } UNLLog(LLINFO, "TAP interface configured (s=%i, n=%s).\n", *tap_fd, tap_name); return 0; }
// Serial to UDP Converter: add end-point int serial2udp_add(int *remote_socket, int *remote_id, int *remote_if, char *serial2udp_map) { int i = 0; char tmp_srcif[10]; memset((char *) &tmp_srcif, 0, sizeof(tmp_srcif)); char tmp_dst[100]; memset((char *) &tmp_dst, 0, sizeof(tmp_dst)); char tmp_dstid[100]; memset((char *) &tmp_dstid, 0, sizeof(tmp_dstid)); char tmp_dstif[10]; memset((char *) &tmp_dstif, 0, sizeof(tmp_dstif)); char tmp_dstport[10]; int rc = -1; struct addrinfo *result_addr; // remote_addr saved as output of getaddrinfo() memset((char *) &result_addr, 0, sizeof(result_addr)); struct addrinfo *remote_addr; // remote_addr after getaddrinfo() memset((char *) &remote_addr, 0, sizeof(remote_addr)); struct addrinfo testing_addr; // remote_addr used inside getaddrinfo() memset((char *) &testing_addr, 0, sizeof(testing_addr)); // Setting options testing_addr.ai_family = AF_UNSPEC; // Allow IPv4 or IPv6 testing_addr.ai_socktype = SOCK_DGRAM; // Looking for source interface for (; serial2udp_map[i] != ':'; i++) { if (serial2udp_map[i] == '\0') { rc = 3; UNLLog(LLERROR, "Invalid map (%s).\n", serial2udp_map); return 3; } strncat(tmp_srcif, &serial2udp_map[i], 1); } // Looking for detination hostname for (++i; serial2udp_map[i] != ':'; i++) { if (serial2udp_map[i] == '\0') { rc = 3; UNLLog(LLERROR, "Invalid map (%s).\n", serial2udp_map); return 3; } strncat(tmp_dst, &serial2udp_map[i], 1); } // Looking for destination ID for (++i; serial2udp_map[i] != ':'; i++) { if (serial2udp_map[i] == '\0') { rc = 3; UNLLog(LLERROR, "Invalid map (%s).\n", serial2udp_map); return 3; } strncat(tmp_dstid, &serial2udp_map[i], 1); } // Looking for destination interface for (++i; serial2udp_map[i] != ',' && serial2udp_map[i] != 0; i++) { if (serial2udp_map[i] == ':') { rc = 3; UNLLog(LLERROR, "Invalid map (%s).\n", serial2udp_map); return 3; } strncat(tmp_dstif, &serial2udp_map[i], 1); } // Setting the destination UDP port sprintf(tmp_dstport, "%i", 32768 + 128 * tenant_id + atoi(tmp_dstid)); UNLLog(LLINFO, "Creating UDP MAP (src: %i:%s, dst: %s:%s, dst_id %s:%s).\n", device_id, tmp_srcif, tmp_dst, tmp_dstport, tmp_dstid, tmp_dstif); // Looking for an IPv4 or IPv6 address if ((rc = getaddrinfo(tmp_dst, tmp_dstport, &testing_addr, &result_addr)) != 0) { // Failed to get address rc = 4; UNLLog(LLERROR, "Failed to create UDP map (getaddrinfo). ERR: %s (%i).\n", strerror(errno), rc); return rc; } for (remote_addr = result_addr; remote_addr != NULL; remote_addr = remote_addr -> ai_next) { remote_socket[atoi(tmp_srcif)] = socket(remote_addr -> ai_family, remote_addr -> ai_socktype, remote_addr -> ai_protocol); if (remote_socket[atoi(tmp_srcif)] == -1) { // Wrong address/AF_FAMILY continue; } if (connect(remote_socket[atoi(tmp_srcif)], remote_addr -> ai_addr, remote_addr -> ai_addrlen) != -1) { // Working address/AF_FAMILY -> Exiting break; } close(remote_socket[atoi(tmp_srcif)]); } if (remote_addr == NULL) { // Failed to get address rc = 5; UNLLog(LLERROR, "Failed to create UDP map (cannot find a working address). ERR: %s (%i).\n", strerror(errno), rc); return rc; } // We need to store remote device ID and remote interface ID also remote_id[atoi(tmp_srcif)] = atoi(tmp_dstid); remote_if[atoi(tmp_srcif)] = atoi(tmp_dstif); freeaddrinfo(result_addr); // Nod needed anymore UNLLog(LLINFO, "Configured serial2udp wrapper (s=%i, int=%i, remote_id=%i, remote_if=%i.\n", remote_socket[atoi(tmp_srcif)], atoi(tmp_srcif), remote_id[atoi(tmp_srcif)], remote_if[atoi(tmp_srcif)]); return 0; }
int main (int argc, char *argv[]) { setpgrp(); // Become the leader of its group. // Child's CMD line int m = sysconf(_SC_ARG_MAX); // Maximum CMD line length char *cmd; // Store child's CMD line cmd = (char *) calloc(m, sizeof(char)); // Child's parameters int *child_delay = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); *child_delay = 0; // Delay before starting (shared between parent and child) int child_pid = -1; // PID after the fork() int child_status = -1; // Used during waitpid() char *child_file = NULL; // Binary file // Telnet server int ts_port = -1; // TCP (console) and UDP (serial converter) port char *xtitle = "Terminal Server"; // Title for telnet clients // Select parameters int *infd = calloc(2, sizeof(int)); // Array of integers [0] is for reading, [1] is for writing int *outfd = calloc(2, sizeof(int)); // Array of integers [0] is for reading, [1] is for writing fd_set active_fd_set; // Contains active FD using in select() FD_ZERO(&active_fd_set); fd_set read_fd_set; // Contains FD selected in current loop FD_ZERO(&read_fd_set); // Other parameters int i = -1; // Counter int j = -1; // Counter int opt = NULL; // Store CMD options int rc = -1; // Generic return code char *tmp = NULL; // Generic char string struct sigaction sa; // Manage signals (SIGHUP, SIGTERM...) // Wrapper parameters int child_afsocket[100]; // Store AF_UNIX child sockets memset(&child_afsocket, 0, sizeof(child_afsocket)); int ser_remoteid[64]; // Store Remote Device ID (used for UDP communication) memset(&ser_remoteid, 0, sizeof(ser_remoteid)); int ser_remoteif[64]; // Store Remote Interface ID (used for UDP communication) memset(&ser_remoteif, 0, sizeof(ser_remoteif)); int udpserver_socket = -1; // UDP socket for serial communications int wrapper_afsocket[100]; // Store AF_UNIX wrapper sockets memset(&wrapper_afsocket, 0, sizeof(wrapper_afsocket)); // Parsing options while ((opt = getopt(argc, argv, ":vT:D:d:t:F:x")) != -1) { switch (opt) { default: usage(argv[0]); exit(1); // Begin standard parameters case 'v': printf("%s\n", VERSION); exit(0); case 'T': // Mandatory: Tenant ID tenant_id = atoi(optarg); if (tenant_id < 0) { UNLLog(LLERROR,"Tenant_id must be integer.\n"); exit(1); } UNLLog(LLINFO, "Tennant_id = %i\n", tenant_id); break; case 'D': // Mandatory: Device ID device_id = atoi(optarg); if (tenant_id < 0) { UNLLog(LLERROR,"Device_id must be integer.\n"); exit(1); } UNLLog(LLINFO, "Device_id = %i\n", device_id); break; case 'F': // Mandatory: IOS child_file = optarg; if (is_file(child_file) != 0) { UNLLog(LLERROR,"File '%s' does not exist.\n", child_file); exit(1); } break; case 'd': // Optional: child's startup delay (default 0) *child_delay = atoi(optarg); if (*child_delay < 0) { UNLLog(LLERROR,"Delay must be integer.\n"); exit(1); } break; case 't': // Optional: telnet window title (default "Terminal Server") xtitle = optarg; break; } } // Checking if tenant_id is set if (tenant_id < 0) { UNLLog(LLERROR,"Tenant ID not set.\n"); exit(1); } // Checking if device_id is set if (device_id < 0) { UNLLog(LLERROR,"Device ID not set.\n"); exit(1); } // Checking if child_file is set if (child_file == NULL) { UNLLog(LLERROR,"Subprocess executable not set.\n"); exit(1); } // Building the CMD line ts_port = 32768 + 128 * tenant_id + device_id; tmp = (char *) malloc(m * sizeof(char)); sprintf(tmp, "/usr/bin/dynamips -N '%s' -T %i", xtitle, ts_port); cmd_add(&cmd, tmp); free(tmp); // Adding parameters after "--" j = 0; for (i = 1; i < argc; i++) { if (j == 1) { // Adding parameter given after "--" cmd_add(&cmd, " "); cmd_add(&cmd, argv[i]); } if (strcmp(argv[i], "--") == 0) { // Found "--" j = 1; } } // Adding the IOS filename cmd_add(&cmd, " "); cmd_add(&cmd, child_file); // Creating PIPEs for select() if ((pipe(infd)) < 0 || pipe(outfd) < 0) { UNLLog(LLERROR, "Failed to create PIPEs (%s).\n", strerror(errno)); exit(1); } // Forking if ((rc = fork()) == 0) { // Child: stating subprocess UNLLog(LLINFO, "Starting child (%s).\n", cmd); if (*child_delay > 0) { // Delay is set, waiting for (; *child_delay > 0;) { rc = write(outfd[1], ".", 1); *child_delay = *child_delay - 1; sleep(1); } rc = write(outfd[1], "\n", 1); } close(STDIN_FILENO); // Closing child's stdin close(STDOUT_FILENO); // Closing child's stdout dup2(infd[0], STDIN_FILENO); // Linking stdin to PIPE dup2(outfd[1], STDOUT_FILENO); // Linking stdout to PIPE dup2(outfd[1], STDERR_FILENO); // Redirect child's stderr to child's stdout close(infd[0]); close(infd[1]); close(outfd[0]); close(outfd[1]); // Start process rc = cmd_start(cmd); // Subprocess terminated, killing the parent UNLLog(LLERROR,"Child terminated (%i).\n", rc); } else if (rc > 0) { // Parent close(infd[0]); // Used by the child close(outfd[1]); // Used by the child // Handling Signals signal(SIGPIPE,SIG_IGN); // Ignoring SIGPIPE when a client terminates sa.sa_handler = &signal_handler; // Setup the sighub handler sa.sa_flags = SA_RESTART; // Restart the system call, if at all possible sigemptyset(&sa.sa_mask); // Signals blocked during the execution of the handler sigaddset(&sa.sa_mask, SIGHUP); // Signal 1 sigaddset(&sa.sa_mask, SIGINT); // Signal 2 sigaddset(&sa.sa_mask, SIGTERM); // Signal 15 sigfillset(&sa.sa_mask); // Intercept SIGHUP, SIGINT, SIGUSR1 and SIGTERM if (sigaction(SIGHUP, &sa, NULL) == -1) { UNLLog(LLERROR, "Cannot handle SIGHUP (%s).\n", strerror(errno)); } if (sigaction(SIGINT, &sa, NULL) == -1) { UNLLog(LLERROR, "Cannot handle SIGINT (%s).\n", strerror(errno)); } if (sigaction(SIGTERM, &sa, NULL) == -1) { UNLLog(LLERROR, "Cannot handle SIGTERM (%s).\n", strerror(errno)); } // Preparing select() FD_ZERO(&active_fd_set); FD_ZERO(&read_fd_set); if (udpserver_socket > 0) { FD_SET(udpserver_socket, &active_fd_set); // Adding UDP socket } // While subprocess is running, check IO from subprocess, telnet clients, socket and network waitpid(child_pid, &child_status, 0); // Child is no more running UNLLog(LLERROR, "Child is no more running.\n"); } else { UNLLog(LLERROR, "Failed to fork (%s).\n", strerror(errno)); exit(1); } exit(0); }
int main (int argc, char *argv[]) { setpgrp(); // Become the leader of its group. // Child's CMD line int m = sysconf(_SC_ARG_MAX); // Maximum CMD line length char *cmd; // Store child's CMD line cmd = (char *) calloc(m, sizeof(char)); // Child's parameters char *child_file = NULL; // Binary file int child_pid = -1; // PID after the fork() int child_status = -1; // Used during waitpid() // Telnet server int ts_socket = -1; // Telnet server socket int ts_port = -1; // TCP (console) and UDP (serial converter) port char child_output = '\0'; // Store single char from child unsigned char client_input = '\0'; // Store single char from client char *xtitle = "Terminal Server"; // Title for telnet clients // Select parameters int *infd = calloc(2, sizeof(int)); // Array of integers [0] is for reading, [1] is for writing int *outfd = calloc(2, sizeof(int)); // Array of integers [0] is for reading, [1] is for writing fd_set active_fd_set; // Contains active FD using in select() FD_ZERO(&active_fd_set); fd_set read_fd_set; // Contains FD selected in current loop FD_ZERO(&read_fd_set); // Other parameters int i = -1; // Counter int j = -1; // Counter int opt = NULL; // Store CMD options int rc = -1; // Generic return code struct sigaction sa; // Manage signals (SIGHUP, SIGTERM...) // Parsing options while ((opt = getopt(argc, argv, ":vT:D:t:F:")) != -1) { switch (opt) { default: usage(argv[0]); exit(1); // Begin standard parameters case 'v': printf("%s\n", VERSION); exit(0); case 'T': // Mandatory: Tenant ID tenant_id = atoi(optarg); if (tenant_id < 0) { UNLLog(LLERROR,"Tenant_id must be integer.\n"); exit(1); } UNLLog(LLINFO, "Tennant_id = %i\n", tenant_id); break; case 'D': // Mandatory: Device ID device_id = atoi(optarg); if (device_id < 0) { UNLLog(LLERROR,"Device_id must be integer.\n"); exit(1); } UNLLog(LLINFO, "Device_id = %i\n", device_id); break; case 'F': // Mandatory: subprocess executable child_file = optarg; if (is_file(child_file) != 0) { UNLLog(LLERROR,"File '%s' does not exist.\n", child_file); exit(1); } break; case 't': // Optional: telnet window title (default "Terminal Server") xtitle = optarg; break; } } // Checking if tenant_id is set if (tenant_id < 0) { UNLLog(LLERROR, "Tenant ID not set.\n"); exit(1); } // Checking if device_id is set if (device_id < 0) { UNLLog(LLERROR, "Device ID not set.\n"); exit(1); } // Checking if child_file is set if (child_file == NULL) { UNLLog(LLERROR, "Subprocess executable not set.\n"); exit(1); } // Building the CMD line cmd_add(&cmd, child_file); // Adding parameters after "--" j = 0; for (i = 1; i < argc; i++) { if (j == 1) { // Adding parameter given after "--" cmd_add(&cmd, " "); cmd_add(&cmd, argv[i]); } if (strcmp(argv[i], "--") == 0) { // Found "--" j = 1; } } // Creating PIPEs for select() if ((pipe(infd)) < 0 || pipe(outfd) < 0) { UNLLog(LLERROR, "Failed to create PIPEs (%s).\n", strerror(errno)); exit(1); } // Telnet listen ts_port = 32768 + 128 * tenant_id + device_id; tsclients_socket[0] = 0; if ((rc = ts_listen(ts_port, &ts_socket)) != 0) { UNLLog(LLERROR, "Failed to open TCP socket (%i).\n", rc); exit(1); } // Forking if ((rc = fork()) == 0) { // Child: stating subprocess UNLLog(LLINFO, "Starting child (%s).\n", cmd); close(STDIN_FILENO); // Closing child's stdin close(STDOUT_FILENO); // Closing child's stdout dup2(infd[0], STDIN_FILENO); // Linking stdin to PIPE dup2(outfd[1], STDOUT_FILENO); // Linking stdout to PIPE dup2(outfd[1], STDERR_FILENO); // Redirect child's stderr to child's stdout close(infd[0]); close(infd[1]); close(outfd[0]); close(outfd[1]); // Start process while (rc == -1 || rc == 0) { // Start console until it fail rc = cmd_start(cmd); } // Subprocess terminated, killing the parent UNLLog(LLERROR, "Child terminated (%i).\n", rc); } else if (rc > 0) { // Parent close(infd[0]); // Used by the child close(outfd[1]); // Used by the child // Handling Signals signal(SIGPIPE,SIG_IGN); // Ignoring SIGPIPE when a client terminates sa.sa_handler = &signal_handler; // Setup the sighub handler sa.sa_flags = SA_RESTART; // Restart the system call, if at all possible sigemptyset(&sa.sa_mask); // Signals blocked during the execution of the handler sigaddset(&sa.sa_mask, SIGHUP); // Signal 1 sigaddset(&sa.sa_mask, SIGINT); // Signal 2 sigaddset(&sa.sa_mask, SIGTERM); // Signal 15 sigfillset(&sa.sa_mask); // Intercept SIGHUP, SIGINT, SIGUSR1 and SIGTERM if (sigaction(SIGHUP, &sa, NULL) == -1) { UNLLog(LLERROR, "Cannot handle SIGHUP (%s).\n", strerror(errno)); } if (sigaction(SIGINT, &sa, NULL) == -1) { UNLLog(LLERROR, "Cannot handle SIGINT (%s).\n", strerror(errno)); } if (sigaction(SIGTERM, &sa, NULL) == -1) { UNLLog(LLERROR, "Cannot handle SIGTERM (%s).\n", strerror(errno)); } // Preparing select() FD_ZERO(&active_fd_set); FD_ZERO(&read_fd_set); FD_SET(outfd[0], &active_fd_set); // Adding subprocess stdout FD_SET(ts_socket, &active_fd_set); // Adding telnet socket // While subprocess is running, check IO from subprocess, telnet clients, socket and network while (waitpid(child_pid, &child_status, WNOHANG|WUNTRACED) == 0) { // Check if select() is valid read_fd_set = active_fd_set; if (select(FD_SETSIZE, &read_fd_set, NULL, NULL, NULL) <= 0) { UNLLog(LLERROR, "Failed to select().\n"); kill(0, SIGTERM); break; } // Check if output from child if (FD_ISSET(outfd[0], &read_fd_set)) { if (read(outfd[0], &child_output, 1) <= 0) { UNLLog(LLERROR, "Error while reading data from the subprocess, killing it.\n"); kill(0, SIGTERM); break; } // Writing to all telnet clients ts_broadcast(child_output, &active_fd_set, tsclients_socket); } // Check if new client is coming if (FD_ISSET(ts_socket, &read_fd_set)) { if ((rc = ts_accept(&active_fd_set, ts_socket, xtitle, tsclients_socket,1)) != 0) { UNLLog(LLERROR, "Failed to accept a new client (%i).\n", rc); } } // Check for output from all telnet clients if (ts_receive(&client_input, &read_fd_set, &active_fd_set, tsclients_socket) == 0) { // Write to child rc = write(infd[1], &client_input, 1); if (rc < 0) { UNLLog(LLERROR, "Error writing to the subprocess, closing.\n"); kill(0, SIGTERM); break; } } } } else { UNLLog(LLERROR, "Failed to fork.\n" ); exit(1); } close(ts_socket); exit(0); }