Esempio n. 1
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);
}
Esempio n. 2
0
int main (int argc, char *argv[]) {
    // 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
    int ts_socket = -1;                     // Telnet server socket
    char child_output = '\0';               // Store single char from child
    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
    int active_fd = -1;                     // Contains current active FD
    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);

    // Wrapper parameters
    int child_afsocket = -1;                // Store AF_UNIX child socket
    int *eth_socket = calloc(64, sizeof(int));  // Store FD of ethernet intefaces
    int *ser_remoteid = calloc(64, sizeof(int));// Store Remote Device ID (used for UDP communication)
    int *ser_remoteif = calloc(64, sizeof(int));// Store Remote Interface ID (used for UDP communication)
    int *ser_socket = calloc(64, sizeof(int));  // Store FD of serial intefaces
    int udpserver_socket = -1;              // UDP socket for serial communications
    int wrapper_afsocket = -1;              // Store AF_UNIX wrapper socket

    // Other parameters
    int af_ready = 0;                       // 1 = AF_UNIX files are configured (needed if IOL is delayed)
    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...)

    setpgrp();

    // Check for iourc file
    tmp = (char *) malloc(m * sizeof(char));
    sprintf(tmp, "iourc");
    if (is_file(tmp) != 0) {
        printf("ERR: file '%s' does not exist.\n", tmp);
        exit(1);
    }
    free(tmp);

    // Adding options to child's CMD line
    while ((opt = getopt(argc, argv, ":vT:D:d:t:F:e:s:l:")) != -1) {
        switch (opt) {
            default:
                usage(argv[0]);
                exit(1);
            // Begin standard parameters
            case 'v':
                version();
                exit(0);
            case 'T':
                // Mandatory: Tenant ID
                tenant_id = atoi(optarg);
                if (tenant_id < 0) {
                    printf("ERR: tenant_id must be integer.\n");
                    exit(1);
                }
                break;
            case 'D':
                // Mandatory: Device ID
                device_id = atoi(optarg);
                if (tenant_id < 0) {
                    printf("ERR: device_id must be integer.\n");
                    exit(1);
                }
                break;
            case 'F':
                child_file = optarg;
                if (is_file(child_file) != 0) {
                    printf("ERR: 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) {
                    printf("ERR: delay must be integer.\n");
                    exit(1);
                }
                break;
            case 't':
                // Optional: telnet window title (default "Terminal Server")
                xtitle = optarg;
                break;
            // End standard parameters
            // Optional: number of Ethernet progroups (default: 2)
            case 'e':
                child_eth = atoi(optarg);
                if (child_eth < 0) {
                    printf("ERR: Ethernet portgroup must be integer.\n");
                    exit(1);
                }
                break;
            // Optional: number of Serial progroups (default: 2)
            case 's':
                child_ser = atoi(optarg);
                if (child_ser < 0) {
                    printf("ERR: Serial portgroup must be numeric.\n");
                    exit(1);
                }
                break;
            // Optional: Serial link end-point (no default)
            case 'l':
                if (udpserver_socket == -1 && tenant_id != -1 && device_id != -1) {
                    // First Serial2UDP definition, must listen()
                    if ((rc = serial2udp_listen(32768 + 128 * tenant_id + device_id, &udpserver_socket)) != 0) {
                        printf("%u:%u ERR: failed to open UDP socket (%i).\n", tenant_id, device_id, rc);
                        exit(1);
                    }
                    // Now add serial end-point
                    if ((rc = serial2udp_add(ser_socket, ser_remoteid, ser_remoteif, optarg)) != 0) {
                        printf("%u:%u ERR: failed to add serial end-point (%i).\n", tenant_id, device_id, rc);
                        exit(1);
                    }
                } else if (udpserver_socket > 0) {
                    // Serial2UDP wrapper already started, add serial end-point
                    if ((rc = serial2udp_add(ser_socket, ser_remoteid, ser_remoteif, optarg)) != 0) {
                        printf("%u:%u ERR: failed to add serial end-point (%i).\n", tenant_id, device_id, rc);
                        exit(1);
                    }
                } else {
                    printf("ERR: flag '-l' must be after '-T' and '-D'.\n");
                    exit(1);
                }
                break;
        }
    }

    // Checking if tenant_id is set
    if (tenant_id < 0) {
        printf("ERR: tenant ID not set.\n");
        exit(1);
    }

    // Checking if device_id is set
    if (device_id < 0) {
        printf("ERR: device ID not set.\n");
        exit(1);
    }

    // Checking if child_file is set
    if (child_file == NULL) {
        printf("%u:%u ERR: subprocess executable not set.\n", tenant_id, device_id);
        exit(1);
    }

    // Checking total interfaces
    if (child_eth + child_ser > 16) {
        printf("%u:%u ERR: Ethernet + Serial portgroups must lower equal than 16.\n", tenant_id, device_id);
        exit(1);
    }

    // Building the CMD line
    cmd_add(&cmd, "LD_LIBRARY_PATH=/opt/unetlab/addons/iol/lib ");
    cmd_add(&cmd, child_file);

    // Adding interfaces
    tmp = (char *) malloc(m * sizeof(char));
    sprintf(tmp, " -e %i -s %i", child_eth, child_ser);
    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 device_id as last
    tmp = (char *) malloc(m * sizeof(char));
    sprintf(tmp, "%i", device_id);
    cmd_add(&cmd, " ");
    cmd_add(&cmd, tmp);
    free(tmp);

    // Creating NETMAP
    if ((rc = mk_netmap()) != 0) {
        printf("%u:%u ERR: failed to create NETMAP file (%i).\n", tenant_id, device_id, rc);
        exit(1);
    }

    // Creating PIPEs for select()
    if ((pipe(infd)) < 0 || pipe(outfd) < 0) {
         printf("%u:%u ERR: failed to create PIPEs (%s).\n", tenant_id, device_id, 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) {
        printf("%u:%u ERR: failed to open TCP socket (%i).\n", tenant_id, device_id, rc);
        exit(1);
    }

    // Creating TAP interfaces
    if ((rc = mk_tap(child_eth, eth_socket)) != 0) {
        printf("%u:%u ERR: failed to create TAP interfaces (%i).\n", tenant_id, device_id, rc);
        kill(0, SIGTERM);
        exit(1);
    }

    // Forking
    if ((rc = fork()) == 0) {
        // Child: starting subprocess
        if (DEBUG > 0) printf("DEBUG: 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
        printf("%u:%u ERR: child terminated (%i).\n", tenant_id, device_id, 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) {
            printf("%u:%u ERR: cannot handle SIGHUP (%s).\n", tenant_id, device_id, strerror(errno));
        }
        if (sigaction(SIGINT, &sa, NULL) == -1) {
            printf("%u:%u ERR: cannot handle SIGINT (%s).\n", tenant_id, device_id, strerror(errno));
        }
        if (sigaction(SIGTERM, &sa, NULL) == -1) {
            printf("%u:%u ERR: cannot handle SIGTERM (%s).\n", tenant_id, device_id, strerror(errno));
        }

        // Preparing select()
        FD_ZERO(&active_fd_set);
        FD_ZERO(&read_fd_set);
        if (DEBUG > 0) printf("DEBUG: adding subprocess stdout descriptor (%i).\n", outfd[0]);
        FD_SET(outfd[0], &active_fd_set);         // Adding subprocess stdout
        if (DEBUG > 0) printf("DEBUG: adding telnet socket descriptor (%i).\n", ts_socket);
        FD_SET(ts_socket, &active_fd_set);        // Adding telnet socket
        if (udpserver_socket > 0) {
            if (DEBUG > 0) printf("DEBUG: adding UDP socket descriptor (%i).\n", udpserver_socket);
            FD_SET(udpserver_socket, &active_fd_set); // Adding UDP socket
        }

        // Adding TAP interfaces for select()
        for (i = 0; i <= 63; i++) {
            if (eth_socket[i] > 0) {
                if (DEBUG > 0) printf("DEBUG: adding TAP interface descriptor (%i).\n", eth_socket[i]);
                FD_SET(eth_socket[i], &active_fd_set);
            }
        }

        // While subprocess is running, check IO from subprocess, telnet clients, socket and network
        while (waitpid(child_pid, &child_status, WNOHANG|WUNTRACED) == 0) {
            // Creating AF communication from child
            if (af_ready == 0 && *child_delay == 0) {
                // wait 3 seconds for AF_UNIX
                sleep(3);
                if ((rc = mk_afsocket(&wrapper_afsocket, &child_afsocket)) != 0) {;
                    printf("%u:%u ERR: failed to create AF_UNIX socket file (%i).\n", tenant_id, device_id, rc);
                    kill(0, SIGTERM);
                    break;
                }
                af_ready = 1;
                if (DEBUG > 0) printf("DEBUG: adding wrapper socket descriptor (%i).\n", wrapper_afsocket);
                FD_SET(wrapper_afsocket, &active_fd_set);   // Adding subprocess AF_UNIX socket
            }

            // Check if select() is valid
            read_fd_set = active_fd_set;
            if ((active_fd = select(FD_SETSIZE, &read_fd_set, NULL, NULL, NULL)) <= 0) {
                printf("%u:%u ERR: failed to select().\n", tenant_id, device_id);
                kill(0, SIGTERM);
                break;
            }
            if (DEBUG > 2) printf("DEBUG: data from select descriptor (%i).\n", active_fd);

            // Check if output from child
            if (FD_ISSET(outfd[0], &read_fd_set)) {
                if (read(outfd[0], &child_output, 1) <= 0) {
                    printf("%u:%u ERR: error while reading data from the subprocess, killing it.\n", tenant_id, device_id);
                    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) {
                    printf("%u:%u ERR: failed to accept a new client (%i).\n", tenant_id, device_id, 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) {
                    printf("%u:%u ERR: error writing to the subprocess, closing.\n", tenant_id, device_id);
                    kill(0, SIGTERM);
                    break;
                }
            }

            // If AF, UDP and TAP sockets are configured, check for packets
            if (af_ready == 1) {
                // Check for packets from subprocess
                if (FD_ISSET(wrapper_afsocket, &read_fd_set)) {
                    if ((rc = packet_af(wrapper_afsocket, eth_socket, ser_socket, ser_remoteid, ser_remoteif)) != 0) {
                        printf("%u:%u ERR: error forwarding packet from AF_UNIX socket to TAP/UDP (%i).\n", tenant_id, device_id, rc);
                        kill(0, SIGTERM);
                        break;
                    }
                }

                // Check for packets from TAP interfaces
                for (i = 0; i <= 63; i++) {
                    if (eth_socket[i] > 0 && FD_ISSET(eth_socket[i], &read_fd_set)) {
                        if ((rc = packet_tap(eth_socket[i], child_afsocket, i)) != 0) {
                            if (rc == 3) {
                              af_ready = 0;
                              printf("Failed to forward TAP => AF_UNIX. Will try to recreate it later...\n");
                            } else {
                              printf("%u:%u ERR: error forwarding packet from TAP to AF_UNIX socket (%i).\n", tenant_id, device_id, rc);
                              kill(0, SIGTERM);
                              break;
                            }
                        }
                    }
                }

                // Check for incoming serial (UDP) packets
                if (udpserver_socket > 0) {
                    if (FD_ISSET(udpserver_socket, &read_fd_set)) {
                        if ((rc = packet_udp(udpserver_socket, child_afsocket)) != 0) {
                            if (rc == 3) {
                                af_ready = 0;
                                printf("Failed to forward UDP => AF_UNIX. Will try to recreate it later...\n");
                            } else {
                                printf("%u:%u ERR: error forwarding packet from UDP to AF_UNIX (%i).\n", tenant_id, device_id, rc);
                                kill(0, SIGTERM);
                                break;
                            }
                        }
                    }
                }
            }

            // We should not have other active dscriptor
        }

        // Child is no more running
        printf("%u:%u ERR: child is no more running.\n", tenant_id, device_id);
    } else {
        printf("%u:%u ERR: failed to fork.\n", tenant_id, device_id);
        exit(1);
    }
    close(ts_socket);
    close(wrapper_afsocket);
    exit(0);
}