For a project I'm building a "super-server" like inetd. It is supposed to read a set of ports and commands from a config file, and for each port spin up a listener socket. It should then use select() to determine when one or more of these sockets is ready to read from. When select finds a socket, it should use accept() to connect to this socket, and then fork() a child process in which the command will be executed. Unfortunately, select is always either timing out or failing when I try to call "nc -l localhost 12345" to test it (with '12345 echo "hello world"' in the config.txt file).
Can you spot anything I might be doing wrong? Thanks in advance! I've been going crazy trying to figure this out!
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/select.h>
#include <iostream>
#include <sstream>
#include <fstream>
#include <map>
using namespace std;
map<int,string> parse_config_file() {
    string line;
    ifstream file;
    stringstream ss;
    int port;
    string command;
    map<int,string> port_to_command;
    file.open("config.txt");
    while (getline(file,line)) {
        ss = stringstream(line);
        ss >> port;
        getline(ss,command);
        port_to_command[port] = command;
    }
    file.close();
    return port_to_command;
}
void handle_client(int socket, string command) {
    dup2(socket, STDIN_FILENO);
    dup2(socket, STDOUT_FILENO);
    execl("/bin/sh", "/bin/sh", "-c", command.c_str(), NULL);
}
int main(int argc, const char * argv[]) {
    int rc;
    int readyfd;
    int peerfd;
    int maxfd = 0;
    int port;
    pid_t child_pid;
    fd_set readfds;
    struct timeval tv;
    tv.tv_sec = 10;
    tv.tv_usec = 0;
    struct sockaddr* server_address;
    socklen_t server_address_length = sizeof(server_address);
    struct sockaddr client_address;
    socklen_t client_address_length = sizeof(client_address);
    map<int,string> port_to_command = parse_config_file();
    map<int,string>::iterator pcitr;
    map<int,int> socket_to_port;
    map<int,int>::iterator spitr;
    // Create, bind, and listen on the sockets:
    for (pcitr = port_to_command.begin(); pcitr != port_to_command.end(); pcitr++) {
        int sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (sockfd < 0) {
            cerr << "ERROR opening socket";
            exit(EXIT_FAILURE);
        }
        port = pcitr->first;
        struct sockaddr_in server_address_internet;
        bzero((char *) &server_address_internet, sizeof(server_address_internet));
        server_address_internet.sin_family = AF_INET;
        server_address_internet.sin_addr.s_addr = INADDR_ANY;
        server_address_internet.sin_port = htons(port);
        server_address = (struct sockaddr *)&server_address_internet;
        bind(sockfd, server_address, server_address_length);
        rc = listen(sockfd, 10);
        if (rc < 0) {
            cerr << "listen() failed";
            exit(EXIT_FAILURE);
        }
        socket_to_port[sockfd] = pcitr->first;
        if (sockfd > maxfd) {
            maxfd = sockfd;
        }
    }
    // Server Loop
    while (true) {
        // Rebuild the FD set:
        FD_ZERO(&readfds);
        for (spitr = socket_to_port.begin(); spitr != socket_to_port.end(); spitr++) {
            FD_SET(spitr->first, &readfds);
        }
        // Select
        rc = select(maxfd + 1, &readfds, NULL, NULL, &tv);
        if (rc == 0) {
            // Timeout
            continue;
        } else if (rc < 0) {
            cerr << "select failed" << endl;
            exit(EXIT_FAILURE);
        }
        // Find the socket that is ready to be read:
        readyfd = -1;
        for (spitr = socket_to_port.begin(); spitr != socket_to_port.end(); spitr++) {
            if (FD_ISSET(spitr->first, &readfds)) {
                readyfd = spitr->first;
                break;
            }
        }
        // Accept
        peerfd = accept(readyfd, &client_address, &client_address_length);
        if (peerfd < 0) {
            cerr << "accept failed" << endl;
            exit(EXIT_FAILURE);
        }
        // Fork to handle request:
        child_pid = fork();
        if (child_pid == 0) {
            port = ((struct sockaddr_in*)&client_address)->sin_port;
            handle_client(peerfd, port_to_command[port]);
            close(peerfd);
            exit(EXIT_SUCCESS);
        } else {
            close(peerfd);
        }
    }
    return 0;
}
 
     
     
    