2OF1 · the depletionmode zineLinkedIn · X
← back to the issue

08 June 2010

accept()ing multiple tcp connections

Originally published on the old depletionmode / 2of1 blog (archived copy).

The best way I've found of handling multiple tcp connections on the same socket is to use a poll file device with the listen()ing socket itself as the first pfd. The example below is based on a i5/OS example available from IBM at http://publib.boulder.ibm.com/infocenter/iseries/v6r1m0/index.jsp?topic=/rzab6/example.htm. I've made some minor changes to how flags are set to allow the example below to work on Linux/Win/BSD. (Please note the lack of error checking in the code below. You should obviously have some in your application.) #include ... #include #include int listen_sd, cli_len, npfds = 1, port = 12345, max_connections = 5, one = 1; struct sockaddr_in srv; struct pollfd pfds[100]; memset(pfds, 0, sizeof(pfds)); memset(&srv, 0, sizeof(srv); listen_sd = socket(AF_INET, SOCK_STREAM, 0); // set up socket setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); // allow for port reuse srv.sin_family = AF_INET; srv.sin_addr.s_addr = INADDR_ANY; srv.sin_port

The best way I’ve found of handling multiple tcp connections on the same socket is to use a poll file device with the listen()ing socket itself as the first pfd.

The example below is based on a i5/OS example available from IBM at http://publib.boulder.ibm.com/infocenter/iseries/v6r1m0/index.jsp?topic=/rzab6/example.htm.
I’ve made some minor changes to how flags are set to allow the example below to work on Linux/Win/BSD.

(Please note the lack of error checking in the code below. You should obviously have some in your application.)

listing text
#include ...
#include <poll.h>
#include <fcntl.h>
 
int listen_sd, cli_len, npfds = 1, port = 12345, max_connections = 5, one = 1;
struct sockaddr_in srv;
struct pollfd pfds[100];
 
memset(pfds, 0, sizeof(pfds));
memset(&srv, 0, sizeof(srv);
 
listen_sd = socket(AF_INET, SOCK_STREAM, 0);    // set up socket
setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));  // allow for port reuse
 
srv.sin_family = AF_INET;
srv.sin_addr.s_addr = INADDR_ANY;
srv.sin_port = htons(port);
 
fcntl(listen_sd, FSETFL, O_NONBLOCK);    // make sure socket doesn't block
 
bind(listen_sd, (struct sockaddr *)&srv, sizeof(srv));    // bind
listen(listen_sd, max_connections);     // listens for a max of 5 connections
 
pfds[0].fd = listen_fd;        // set up the first pfd to be the listen()ing socket
pfds[0].events = POLLIN;  // trigger when POLLIN event
 
while (1) {
    if (poll(pfds, npfds, -1) > 0) {    // there's an event waiting
    int i, j = npfds;
    for(i = 0; i < j; i++) {    // process each fd
        if (pfds[i].revents == 0) continue;    // this fd has nothing to process, so move to next
 
        if (pfds[i].fd == listen_sd) {    // event has been received on the listening socket
            int fd;
            do {
                int flags;
                fd = accept(listen_sd, NULL, NULL);
 
                flags = fcntl(fd, F_GETFL, NULL) | ~O_NONBLOCK;
                fcntl(fd, F_SETFL, flags);    // make sure fd doesn't block
 
                // set up the new pfd
                pfds[npfds].fd = fd;
                pfds[npfds].events = POLLIN;
                npfds++;
            } while (fd != -1);
        } else {   // there is input waiting on the current connection fd
            unsigned char buf[1000];
            if (recv(pfds[i].fd, buf, 1000) > 0) {
                // process data
            } else {    // connection has been closed
                close(pfds[i].fd);
                remove_pfd_from_array(pfds, &npfds, i);    // make sure pfd is no longer polled
            }
        }
    }
}

The remove_pfd_from_array() removes the disconnected fd from the array. There are better ways of doing this, but a dirty implementation looks something like this:

listing text
void remove_pfd_from_array(struct pollfd *pfds, int *npfds, int fd)
{
    int i;
    for (i = 0; i < *npfds - 1; i++)
        pfds[i] = pfds[i + 1];
    memset(pfds + i, 0, sizeof(struct pollfd));
    (*npfds)--;
}

→ end of entry

2/1
@depletionmode
security research & systems engineering