Пример #1
0
/* Broadcast a message to all the descriptors in fds. Returns -1 if any of the
   sends failed. */
int ncat_broadcast(fd_set *fds, const fd_list_t *fdlist, const char *msg, size_t size)
{
    struct fdinfo *fdn;
    int i, ret;

    if (o.recvonly)
        return size;

    ret = 0;
    for (i = 0; i <= fdlist->fdmax; i++) {
        if (!FD_ISSET(i, fds))
            continue;

        fdn = get_fdinfo(fdlist, i);
        ncat_assert(fdn != NULL);
        if (blocking_fdinfo_send(fdn, msg, size) <= 0) {
            if (o.debug > 1)
                logdebug("Error sending to fd %d: %s.\n", i, socket_strerror(socket_errno()));
            ret = -1;
        }
    }

    ncat_log_send(msg, size);

    return ret;
}
Пример #2
0
static void shutdown_sockets(int how)
{
    struct fdinfo *fdn;
    int i;

    for (i = 0; i <= broadcast_fdlist.fdmax; i++) {
        if (!FD_ISSET(i, &master_broadcastfds))
            continue;

        fdn = get_fdinfo(&broadcast_fdlist, i);
        ncat_assert(fdn != NULL);
        shutdown(fdn->fd, how);
    }
}
Пример #3
0
/* Read from a client socket and write to stdout. Return the number of bytes
   read from the socket, or -1 on error. */
int read_socket(int recv_fd)
{
    char buf[DEFAULT_TCP_BUF_LEN];
    struct fdinfo *fdn;
    int nbytes, pending;

    fdn = get_fdinfo(&client_fdlist, recv_fd);
    ncat_assert(fdn != NULL);

    nbytes = 0;
    do {
        int n;

        n = ncat_recv(fdn, buf, sizeof(buf), &pending);
        if (n <= 0) {
            if (o.debug)
                logdebug("Closing connection.\n");
#ifdef HAVE_OPENSSL
            if (o.ssl && fdn->ssl) {
                if (nbytes == 0)
                    SSL_shutdown(fdn->ssl);
                SSL_free(fdn->ssl);
            }
#endif
            close(recv_fd);
            FD_CLR(recv_fd, &master_readfds);
            rm_fd(&client_fdlist, recv_fd);
            FD_CLR(recv_fd, &master_broadcastfds);
            rm_fd(&broadcast_fdlist, recv_fd);

            conn_inc--;
            if (get_conn_count() == 0)
                FD_CLR(STDIN_FILENO, &master_readfds);

            return n;
        }

        Write(STDOUT_FILENO, buf, n);
        nbytes += n;
    } while (pending);

    return nbytes;
}
Пример #4
0
int monitor_processes(int *nb_pid)
{
int pid_count, fd_count, result_count;
int i,j;
pidinfo_t pidinfo_list[MAX_PIDS];
fdinfo_t fdinfo;
fdinfo_t biggest_fd;
int fdnum_list[MAX_FD_PER_PID];
off_t max_size;
char fsize[64];
char fpos[64];
char ftroughput[64];
float perc;
result_t results[MAX_RESULTS];
signed char still_there;
signed char search_all = 1;

pid_count = 0;

if (proc_specifiq_name_cnt) {
    for (i = 0; i < proc_specifiq_name_cnt; ++i)
        pid_count += find_pids_by_binary_name(proc_specifiq_name[i],
                                              pidinfo_list + pid_count,
                                              MAX_PIDS - pid_count);
    search_all = 0;
}

if (proc_specifiq_pid) {
    pid_count += find_pid_by_id(proc_specifiq_pid,
                                  pidinfo_list + pid_count);
    search_all = 0;
}

if (search_all) {
    for (i = 0 ; proc_names[i] ; i++) {
        pid_count += find_pids_by_binary_name(proc_names[i],
                                              pidinfo_list + pid_count,
                                              MAX_PIDS - pid_count);
        if(pid_count >= MAX_PIDS) {
            nfprintf(stderr, "Found too much procs (max = %d)\n",MAX_PIDS);
            break;
        }
    }
}

*nb_pid = pid_count;

if (!pid_count) {
    if (flag_quiet)
        return 0;
    if (flag_monitor || flag_monitor_continous) {
        clear();
	refresh();
    }
    nfprintf(stderr,"No command currently running: ");
    for (i = 0 ; proc_names[i] ; i++) {
        nfprintf(stderr,"%s, ", proc_names[i]);
    }
    nfprintf(stderr,"exiting.\n");
    return 0;
}

result_count = 0;

for (i = 0 ; i < pid_count ; i++) {
    fd_count = find_fd_for_pid(pidinfo_list[i].pid, fdnum_list, MAX_FD_PER_PID);

    max_size = 0;

    // let's find the biggest opened file
    for (j = 0 ; j < fd_count ; j++) {
        get_fdinfo(pidinfo_list[i].pid, fdnum_list[j], &fdinfo);

        if (fdinfo.size > max_size) {
            biggest_fd = fdinfo;
            max_size = fdinfo.size;
        }
    }

    if (!max_size) { // nothing found
        nprintf("[%5d] %s inactive/flushing/streaming/...\n",
                pidinfo_list[i].pid,
                pidinfo_list[i].name);
        continue;
    }

    // We've our biggest_fd now, let's store the result
    results[result_count].pid = pidinfo_list[i];
    results[result_count].fd = biggest_fd;
    results[result_count].hbegin = NULL;
    results[result_count].hend = NULL;
    results[result_count].hsize = 0;

    result_count++;
}

// wait a bit, so we can estimate the throughput
if (flag_throughput)
    usleep(1000000 * throughput_wait_secs);
if (flag_monitor || flag_monitor_continous) {
    clear();
    refresh();
}
copy_and_clean_results(results, result_count, 1);
for (i = 0 ; i < result_count ; i++) {

    if (flag_throughput) {
        still_there = get_fdinfo(results[i].pid.pid, results[i].fd.num, &fdinfo);
        if (still_there && strcmp(results[i].fd.name, fdinfo.name))
            still_there = 0; // still there, but it's not the same file !
    } else
        still_there = 0;

    if (!still_there) {
        // pid is no more here (or no throughput was asked), use initial info
        format_size(results[i].fd.pos, fpos);
        format_size(results[i].fd.size, fsize);
        perc = ((double)100 / (double)results[i].fd.size) * (double)results[i].fd.pos;
    } else {
        // use the newest info
        format_size(fdinfo.pos, fpos);
        format_size(fdinfo.size, fsize);
        perc = ((double)100 / (double)fdinfo.size) * (double)fdinfo.pos;

    }

    nprintf("[%5d] %s %s %.1f%% (%s / %s)",
        results[i].pid.pid,
        results[i].pid.name,
        results[i].fd.name,
        perc,
        fpos,
        fsize);

    if (flag_throughput && still_there) {
        // results[i] vs fdinfo
        long long usec_diff;
        off_t byte_diff;
        off_t bytes_per_sec;

        usec_diff =   (fdinfo.tv.tv_sec  - results[i].fd.tv.tv_sec) * 1000000L
                    + (fdinfo.tv.tv_usec - results[i].fd.tv.tv_usec);
        byte_diff = fdinfo.pos - results[i].fd.pos;
        results[i].hsize += add_to_hlist(&results[i].hbegin, &results[i].hend, results[i].hsize, byte_diff / (usec_diff / 1000000.0));
        bytes_per_sec = get_hlist_average(results[i].hbegin, results[i].hsize);

        format_size(bytes_per_sec, ftroughput);
        nprintf(" %s/s", ftroughput);
        if (bytes_per_sec && fdinfo.size - fdinfo.pos > 0) {
            print_eta((fdinfo.size - fdinfo.pos) / bytes_per_sec);
        }
    }


    nprintf("\n");

    // Need to work on window width when using screen/watch/...
    //~ printf("    [");
    //~ print_bar(perc, ws.ws_col-6);
    //~ printf("]\n");
}
copy_and_clean_results(results, result_count, 0);
return 0;
}
Пример #5
0
int main(int argc, char *argv[])
{
int pid_count, fd_count, result_count;
int i,j;
pidinfo_t pidinfo_list[MAX_PIDS];
fdinfo_t fdinfo;
fdinfo_t biggest_fd;
int fdnum_list[MAX_FD_PER_PID];
off_t max_size;
char fsize[64];
char fpos[64];
char ftroughput[64];
struct winsize ws;
float perc;
result_t results[MAX_RESULTS];
signed char still_there;

parse_options(argc,argv);

// ws.ws_row, ws.ws_col
ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws);

pid_count = 0;

if(!proc_specifiq) {
    for(i = 0 ; proc_names[i] ; i++) {
        pid_count += find_pids_by_binary_name(proc_names[i],
                                              pidinfo_list + pid_count,
                                              MAX_PIDS - pid_count);
        if(pid_count >= MAX_PIDS) {
            fprintf(stderr, "Found too much procs (max = %d)\n",MAX_PIDS);
            break;
        }
    }
} else {
    pid_count += find_pids_by_binary_name(proc_specifiq,
                                          pidinfo_list + pid_count,
                                          MAX_PIDS - pid_count);
}


if(!pid_count) {
    if(flag_quiet)
        return 0;

    fprintf(stderr,"No command currently running: ");
    for(i = 0 ; proc_names[i] ; i++) {
        fprintf(stderr,"%s, ", proc_names[i]);
    }
    fprintf(stderr,"exiting.\n");
    return 0;
}

result_count = 0;

for(i = 0 ; i < pid_count ; i++) {
    fd_count = find_fd_for_pid(pidinfo_list[i].pid, fdnum_list, MAX_FD_PER_PID);

    max_size = 0;

    // let's find the biggest opened file
    for(j = 0 ; j < fd_count ; j++) {
        get_fdinfo(pidinfo_list[i].pid, fdnum_list[j], &fdinfo);

        if(fdinfo.size > max_size) {
            biggest_fd = fdinfo;
            max_size = fdinfo.size;
        }
    }

    if(!max_size) { // nothing found
        printf("[%5d] %s inactive/flushing/streaming/...\n",
                pidinfo_list[i].pid,
                pidinfo_list[i].name);
        continue;
    }

    // We've our biggest_fd now, let's store the result
    results[result_count].pid = pidinfo_list[i];
    results[result_count].fd = biggest_fd;

    result_count++;
}

// wait a bit, so we can estimate the throughput
if (flag_throughput)
    usleep(1000000 * throughput_wait_secs);

for (i = 0 ; i < result_count ; i++) {

    if (flag_throughput) {
        still_there = get_fdinfo(results[i].pid.pid, results[i].fd.num, &fdinfo);
        if (still_there && strcmp(results[i].fd.name, fdinfo.name))
            still_there = 0; // still there, but it's not the same file !
    } else
        still_there = 0;

    if (!still_there) {
        // pid is no more here (or no throughput was asked), use initial info
        format_size(results[i].fd.pos, fpos);
        format_size(results[i].fd.size, fsize);
        perc = ((double)100 / (double)results[i].fd.size) * (double)results[i].fd.pos;
    } else {
        // use the newest info
        format_size(fdinfo.pos, fpos);
        format_size(fdinfo.size, fsize);
        perc = ((double)100 / (double)fdinfo.size) * (double)fdinfo.pos;

    }

    printf("[%5d] %s %s %.1f%% (%s / %s)",
        results[i].pid.pid,
        results[i].pid.name,
        results[i].fd.name,
        perc,
        fpos,
        fsize);

    if (flag_throughput && still_there) {
        // results[i] vs fdinfo
        long long usec_diff;
        off_t byte_diff;
        off_t bytes_per_sec;

        usec_diff =   (fdinfo.tv.tv_sec  - results[i].fd.tv.tv_sec) * 1000000L
                    + (fdinfo.tv.tv_usec - results[i].fd.tv.tv_usec);
        byte_diff = fdinfo.pos - results[i].fd.pos;
        bytes_per_sec = byte_diff / (usec_diff / 1000000.0);

        format_size(bytes_per_sec, ftroughput);
        printf(" %s/s", ftroughput);
        if (bytes_per_sec && fdinfo.size - fdinfo.pos > 0) {
            print_eta((fdinfo.size - fdinfo.pos) / bytes_per_sec);
        }
    }


    printf("\n");

    // Need to work on window width when using screen/watch/...
    //~ printf("    [");
    //~ print_bar(perc, ws.ws_col-6);
    //~ printf("]\n");

}

return 0;
}
Пример #6
0
/* Read from recv_fd and broadcast whatever is read to all other descriptors in
   read_fds, with the exception of stdin, listen_socket, and recv_fd itself.
   Handles EOL translation and chat mode. On read error or end of stream,
   closes the socket and removes it from the read_fds list. */
static void read_and_broadcast(int recv_fd)
{
    struct fdinfo *fdn;
    int pending;

    fdn = get_fdinfo(&client_fdlist, recv_fd);
    ncat_assert(fdn != NULL);

    /* Loop while ncat_recv indicates data is pending. */
    do {
        char buf[DEFAULT_TCP_BUF_LEN];
        char *chatbuf, *outbuf;
        char *tempbuf = NULL;
        fd_set broadcastfds;
        int n;

        /* Behavior differs depending on whether this is stdin or a socket. */
        if (recv_fd == STDIN_FILENO) {
            n = read(recv_fd, buf, sizeof(buf));
            if (n <= 0) {
                if (n < 0 && o.verbose)
                    logdebug("Error reading from stdin: %s\n", strerror(errno));
                if (n == 0 && o.debug)
                    logdebug("EOF on stdin\n");

                /* Don't close the file because that allows a socket to be
                   fd 0. */
                FD_CLR(recv_fd, &master_readfds);
                /* But mark that we've seen EOF so it doesn't get re-added to
                   the select list. */
                stdin_eof = 1;

                return;
            }

            if (o.crlf)
                fix_line_endings((char *) buf, &n, &tempbuf, &crlf_state);

            pending = 0;
        } else {
            /* From a connected socket, not stdin. */
            n = ncat_recv(fdn, buf, sizeof(buf), &pending);

            if (n <= 0) {
                if (o.debug)
                    logdebug("Closing connection.\n");
#ifdef HAVE_OPENSSL
                if (o.ssl && fdn->ssl) {
                    if (n == 0)
                        SSL_shutdown(fdn->ssl);
                    SSL_free(fdn->ssl);
                }
#endif
                close(recv_fd);
                FD_CLR(recv_fd, &master_readfds);
                rm_fd(&client_fdlist, recv_fd);
                FD_CLR(recv_fd, &master_broadcastfds);
                rm_fd(&broadcast_fdlist, recv_fd);

                conn_inc--;
                if (conn_inc == 0)
                    FD_CLR(STDIN_FILENO, &master_readfds);

                if (o.chat)
                    chat_announce_disconnect(recv_fd);

                return;
            }
        }

        if (o.debug > 1)
            logdebug("Handling data from client %d.\n", recv_fd);

        chatbuf = NULL;
        /* tempbuf is in use if we read from STDIN and fixed EOL */
        if (tempbuf == NULL)
            outbuf = buf;
        else
            outbuf = tempbuf;

        if (o.chat) {
            chatbuf = chat_filter(outbuf, n, recv_fd, &n);
            if (chatbuf == NULL) {
                if (o.verbose)
                    logdebug("Error formatting chat message from fd %d\n", recv_fd);
            } else {
                outbuf = chatbuf;
            }
        }

        /* Send to everyone except the one who sent this message. */
        broadcastfds = master_broadcastfds;
        FD_CLR(recv_fd, &broadcastfds);
        ncat_broadcast(&broadcastfds, &broadcast_fdlist, outbuf, n);

        free(chatbuf);
        free(tempbuf);
        tempbuf = NULL;
    } while (pending);
}
Пример #7
0
static int ncat_listen_stream(int proto)
{
    int rc, i, fds_ready;
    fd_set listen_fds;
    struct timeval tv;
    struct timeval *tvp = NULL;
    unsigned int num_sockets;

    /* clear out structs */
    FD_ZERO(&master_readfds);
    FD_ZERO(&master_writefds);
    FD_ZERO(&master_broadcastfds);
    FD_ZERO(&listen_fds);
#ifdef HAVE_OPENSSL
    FD_ZERO(&sslpending_fds);
#endif
    zmem(&client_fdlist, sizeof(client_fdlist));
    zmem(&broadcast_fdlist, sizeof(broadcast_fdlist));

#ifdef WIN32
    set_pseudo_sigchld_handler(decrease_conn_count);
#else
    /* Reap on SIGCHLD */
    Signal(SIGCHLD, sigchld_handler);
    /* Ignore the SIGPIPE that occurs when a client disconnects suddenly and we
       send data to it before noticing. */
    Signal(SIGPIPE, SIG_IGN);
#endif

#ifdef HAVE_OPENSSL
    if (o.ssl)
        setup_ssl_listen();
#endif

/* Not sure if this problem exists on Windows, but fcntl and /dev/null don't */
#ifndef WIN32
    /* Check whether stdin is closed. Because we treat this fd specially, we
     * can't risk it being reopened for an incoming connection, so we'll hold
     * it open instead. */
    if (fcntl(STDIN_FILENO, F_GETFD) == -1 && errno == EBADF) {
      logdebug("stdin is closed, attempting to reserve STDIN_FILENO\n");
      rc = open("/dev/null", O_RDONLY);
      if (rc >= 0 && rc != STDIN_FILENO) {
        /* Oh well, we tried */
        logdebug("Couldn't reserve STDIN_FILENO\n");
        close(rc);
      }
    }
#endif

    /* We need a list of fds to keep current fdmax. The second parameter is a
       number added to the supplied connection limit, that will compensate
       maxfds for the added by default listen and stdin sockets. */
    init_fdlist(&client_fdlist, sadd(o.conn_limit, num_listenaddrs + 1));

    for (i = 0; i < NUM_LISTEN_ADDRS; i++)
        listen_socket[i] = -1;

    num_sockets = 0;
    for (i = 0; i < num_listenaddrs; i++) {
        /* setup the main listening socket */
        listen_socket[num_sockets] = do_listen(SOCK_STREAM, proto, &listenaddrs[i]);
        if (listen_socket[num_sockets] == -1) {
            if (o.debug > 0)
                logdebug("do_listen(\"%s\"): %s\n", inet_ntop_ez(&listenaddrs[i].storage, sizeof(listenaddrs[i].storage)), socket_strerror(socket_errno()));
            continue;
        }

        /* Make our listening socket non-blocking because there are timing issues
         * which could cause us to block on accept() even though select() says it's
         * readable.  See UNPv1 2nd ed, p422 for more.
         */
        unblock_socket(listen_socket[num_sockets]);

        /* setup select sets and max fd */
        FD_SET(listen_socket[num_sockets], &master_readfds);
        add_fd(&client_fdlist, listen_socket[num_sockets]);

        FD_SET(listen_socket[num_sockets], &listen_fds);

        num_sockets++;
    }
    if (num_sockets == 0) {
        if (num_listenaddrs == 1)
            bye("Unable to open listening socket on %s: %s", inet_ntop_ez(&listenaddrs[0].storage, sizeof(listenaddrs[0].storage)), socket_strerror(socket_errno()));
        else
            bye("Unable to open any listening sockets.");
    }

    add_fd(&client_fdlist, STDIN_FILENO);

    init_fdlist(&broadcast_fdlist, o.conn_limit);

    if (o.idletimeout > 0)
        tvp = &tv;

    while (1) {
        /* We pass these temporary descriptor sets to fselect, since fselect
           modifies the sets it receives. */
        fd_set readfds = master_readfds, writefds = master_writefds;
        struct fdinfo *fdi = NULL;

        if (o.debug > 1)
            logdebug("selecting, fdmax %d\n", client_fdlist.fdmax);

        if (o.debug > 1 && o.broker)
            logdebug("Broker connection count is %d\n", get_conn_count());

        if (o.idletimeout > 0)
            ms_to_timeval(tvp, o.idletimeout);

        fds_ready = fselect(client_fdlist.fdmax + 1, &readfds, &writefds, NULL, tvp);

        if (o.debug > 1)
            logdebug("select returned %d fds ready\n", fds_ready);

        if (fds_ready == 0)
            bye("Idle timeout expired (%d ms).", o.idletimeout);

        /*
         * FIXME: optimize this loop to look only at the fds in the fd list,
         * doing it this way means that if you have one descriptor that is very
         * large, say 500, and none close to it, that you'll loop many times for
         * nothing.
         */
        for (i = 0; i <= client_fdlist.fdmax && fds_ready > 0; i++) {
            /* Loop through descriptors until there's something to read */
            if (!FD_ISSET(i, &readfds) && !FD_ISSET(i, &writefds))
                continue;

            if (o.debug > 1)
                logdebug("fd %d is ready\n", i);

#ifdef HAVE_OPENSSL
            /* Is this an ssl socket pending a handshake? If so handle it. */
            if (o.ssl && FD_ISSET(i, &sslpending_fds)) {
                FD_CLR(i, &master_readfds);
                FD_CLR(i, &master_writefds);
                fdi = get_fdinfo(&client_fdlist, i);
                ncat_assert(fdi != NULL);
                switch (ssl_handshake(fdi)) {
                case NCAT_SSL_HANDSHAKE_COMPLETED:
                    /* Clear from sslpending_fds once ssl is established */
                    FD_CLR(i, &sslpending_fds);
                    post_handle_connection(*fdi);
                    break;
                case NCAT_SSL_HANDSHAKE_PENDING_WRITE:
                    FD_SET(i, &master_writefds);
                    break;
                case NCAT_SSL_HANDSHAKE_PENDING_READ:
                    FD_SET(i, &master_readfds);
                    break;
                case NCAT_SSL_HANDSHAKE_FAILED:
                default:
                    SSL_free(fdi->ssl);
                    Close(fdi->fd);
                    FD_CLR(i, &sslpending_fds);
                    FD_CLR(i, &master_readfds);
                    rm_fd(&client_fdlist, i);
                    /* Are we in single listening mode(without -k)? If so
                       then we should quit also. */
                    if (!o.keepopen && !o.broker)
                        return 1;
                    --conn_inc;
                    break;
                }
            } else
#endif
            if (FD_ISSET(i, &listen_fds)) {
                /* we have a new connection request */
                handle_connection(i);
            } else if (i == STDIN_FILENO) {
                if (o.broker) {
                    read_and_broadcast(i);
                } else {
                    /* Read from stdin and write to all clients. */
                    rc = read_stdin();
                    if (rc == 0) {
                        if (o.proto != IPPROTO_TCP || (o.proto == IPPROTO_TCP && o.sendonly)) {
                            /* There will be nothing more to send. If we're not
                               receiving anything, we can quit here. */
                            return 0;
                        }
                        if (!o.noshutdown) shutdown_sockets(SHUT_WR);
                    }
                    if (rc < 0)
                        return 1;
                }
            } else if (!o.sendonly) {
                if (o.broker) {
                    read_and_broadcast(i);
                } else {
                    /* Read from a client and write to stdout. */
                    rc = read_socket(i);
                    if (rc <= 0 && !o.keepopen)
                        return rc == 0 ? 0 : 1;
                }
            }

            fds_ready--;
        }
    }

    return 0;
}
Пример #8
0
static int ncat_listen_stream(int proto)
{
    int rc, i, fds_ready;
    fd_set listen_fds;

    /* clear out structs */
    FD_ZERO(&master_readfds);
    FD_ZERO(&master_writefds);
    FD_ZERO(&master_broadcastfds);
    FD_ZERO(&listen_fds);
#ifdef HAVE_OPENSSL
    FD_ZERO(&sslpending_fds);
#endif
    zmem(&client_fdlist, sizeof(client_fdlist));
    zmem(&broadcast_fdlist, sizeof(broadcast_fdlist));

#ifdef WIN32
    set_pseudo_sigchld_handler(decrease_conn_count);
#else
    /* Reap on SIGCHLD */
    Signal(SIGCHLD, sigchld_handler);
    /* Ignore the SIGPIPE that occurs when a client disconnects suddenly and we
       send data to it before noticing. */
    Signal(SIGPIPE, SIG_IGN);
#endif

#ifdef HAVE_OPENSSL
    if (o.ssl)
        setup_ssl_listen();
#endif

    /* We need a list of fds to keep current fdmax. The second parameter is a
       number added to the supplied connection limit, that will compensate
       maxfds for the added by default listen and stdin sockets. */
    init_fdlist(&client_fdlist, sadd(o.conn_limit, num_listenaddrs + 1));

    for (i = 0; i < NUM_LISTEN_ADDRS; i++)
        listen_socket[i] = -1;

    for (i = 0; i < num_listenaddrs; i++) {
        /* setup the main listening socket */
        listen_socket[i] = do_listen(SOCK_STREAM, proto, &listenaddrs[i]);

        /* Make our listening socket non-blocking because there are timing issues
         * which could cause us to block on accept() even though select() says it's
         * readable.  See UNPv1 2nd ed, p422 for more.
         */
        unblock_socket(listen_socket[i]);

        /* setup select sets and max fd */
        FD_SET(listen_socket[i], &master_readfds);
        add_fd(&client_fdlist, listen_socket[i]);

        FD_SET(listen_socket[i], &listen_fds);
    }
    add_fd(&client_fdlist, STDIN_FILENO);

    init_fdlist(&broadcast_fdlist, o.conn_limit);

    while (1) {
        /* We pass these temporary descriptor sets to fselect, since fselect
           modifies the sets it receives. */
        fd_set readfds = master_readfds, writefds = master_writefds;
        struct fdinfo *fdi = NULL;

        if (o.debug > 1)
            logdebug("selecting, fdmax %d\n", client_fdlist.fdmax);

        if (o.debug > 1 && o.broker)
            logdebug("Broker connection count is %d\n", get_conn_count());

        fds_ready = fselect(client_fdlist.fdmax + 1, &readfds, &writefds, NULL, NULL);

        if (o.debug > 1)
            logdebug("select returned %d fds ready\n", fds_ready);

        /*
         * FIXME: optimize this loop to look only at the fds in the fd list,
         * doing it this way means that if you have one descriptor that is very
         * large, say 500, and none close to it, that you'll loop many times for
         * nothing.
         */
        for (i = 0; i <= client_fdlist.fdmax && fds_ready > 0; i++) {
            /* Loop through descriptors until there's something to read */
            if (!FD_ISSET(i, &readfds) && !FD_ISSET(i, &writefds))
                continue;

            if (o.debug > 1)
                logdebug("fd %d is ready\n", i);

#ifdef HAVE_OPENSSL
            /* Is this an ssl socket pending a handshake? If so handle it. */
            if (o.ssl && FD_ISSET(i, &sslpending_fds)) {
                FD_CLR(i, &master_readfds);
                FD_CLR(i, &master_writefds);
                fdi = get_fdinfo(&client_fdlist, i);
                switch(ssl_handshake(fdi)){
                case NCAT_SSL_HANDSHAKE_COMPLETED:
                    /* Clear from sslpending_fds once ssl is established */
                    FD_CLR(i, &sslpending_fds);
                    rm_fd(&client_fdlist, i);
                    post_handle_connection(*fdi);
                    break;
                case NCAT_SSL_HANDSHAKE_PENDING_WRITE:
                    FD_SET(i, &master_writefds);
                    break;
                case NCAT_SSL_HANDSHAKE_PENDING_READ:
                    FD_SET(i, &master_readfds);
                    break;
                case NCAT_SSL_HANDSHAKE_FAILED:
                default:
                    SSL_free(fdi->ssl);
                    Close(fdi->fd);
                    FD_CLR(i, &sslpending_fds);
                    FD_CLR(i, &master_readfds);
                    rm_fd(&client_fdlist, i);
                    /* Are we in single listening mode(without -k)? If so
                       then we should quit also. */
                    if (!o.keepopen && !o.broker)
                        return 1;
                    --conn_inc;
                    break;
                }
            } else
#endif
            if (FD_ISSET(i, &listen_fds)) {
                /* we have a new connection request */
                handle_connection(i);
            } else if (i == STDIN_FILENO) {
                if(o.broker) {
                    read_and_broadcast(i);
                }else {
                    /* Read from stdin and write to all clients. */
                    rc = read_stdin();
                    if (rc == 0 && o.sendonly)
                        /* There will be nothing more to send. If we're not
                           receiving anything, we can quit here. */
                        return 0;
                    if (rc < 0)
                        return 1;
                }
            } else if (!o.sendonly) {
                if(o.broker) {
                    read_and_broadcast(i);
                }else {
                    /* Read from a client and write to stdout. */
                    rc = read_socket(i);
                    if (rc <= 0 && !o.keepopen)
                        return rc == 0 ? 0 : 1;
                }
            }

            fds_ready--;
        }
    }

    return 0;
}