Пример #1
0
// 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;
}
Пример #2
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;
    }
}
Пример #3
0
// 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;
}
Пример #4
0
// 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;
}
Пример #5
0
// 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;
}
Пример #6
0
// 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));
}
Пример #7
0
// 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;
}
Пример #8
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;
}
Пример #9
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;
}
Пример #10
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);
}
Пример #11
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);
}