IterationResult SessionArray::select_iteration()

in src/tcp-proxy.cpp [385:475]


IterationResult SessionArray::select_iteration()
{
    fd_set set_r, set_w, set_e;
    struct timeval tv = { 0, 10 };
    int result = 0;
    IterationResult retVal = IR::IDLE;

    // KLUDGE:
    base().sock[HOST] = base().sock[CLIENT] = INVALID_SOCKET;

    // TODO: Do not add Sessions if there are too many
    // TODO: round-robin select if there are many sessions

    // Winsock fd_set is slow, maybe should iterate it myself later
    FD_ZERO(&set_r);
    

    SOCKET socketmax = listener;
    for (intptr iSession = 1, count = std::min(30, (int)size()); iSession < count; ++iSession) {
        Session &s = *operator[](iSession);
        SOCKET sock;
        forn (iSide, 2) {
            if (INVALID_SOCKET != (sock = s.sock[iSide])) {
                if (socketmax < sock) { 
                    socketmax = sock;
                }
                FD_SET(sock, &set_r);
            }
        }
        memset(s.chrwe, 0, sizeof(s.chrwe));
    }
    
    set_e = set_r;
    set_w = set_r;
    FD_SET(listener, &set_e);
    FD_SET(listener, &set_r);

    result = select((int)socketmax + 1, (fd_set *)&set_r, (fd_set *)&set_w, (fd_set *)&set_e, &tv);
    switch (result) {
    case 0:
        return IR::IDLE; // Timeout
    case -1:
        err("select(): returned with error");
        return IR::FAILURE;
    }
    if (FD_ISSET(listener, &set_e)) {
        err("select(): error on listening socket: %d", socket_last_error());
        return IR::FAILURE;
    }

    if (FD_ISSET(listener, &set_r)) {
        retVal = IR::SUCCESS;
        accept();
    }

    for (intptr iSession = 1, count = std::min(30, (int)size()); iSession < count; ++iSession) {
        Session &s = *operator[](iSession);
        SOCKET sock;
        forn (iSide, 2) {
            if (INVALID_SOCKET != (sock = s.sock[iSide])) {
                s.chrwe[0][3] = (
                    (s.chrwe[iSide][2] = FD_ISSET(sock, &set_e)) |
                    (s.chrwe[iSide][1] = FD_ISSET(sock, &set_w)) |
                    (s.chrwe[iSide][0] = FD_ISSET(sock, &set_r))
                );
            }
        }
    }

    for (intptr i = 1, count = std::min(30, (int)size()); i < count; ++i) {
        Session &s = *operator[](i);
        if (s.chrwe[0][3]) {
            IterationResult ir = s.process();
            if (ITERATION_FINISHED(ir)) {
                //iprintf("deleting %s\n", s.name.c_str());
                delete_at(i);
                --count;
                if (1 == size()) {
                    iprintf("All sessions finished\n\n");
                    nSessionsAccepted = 0;
                }
                retVal = IR::SUCCESS;
            }
            else if (IR::IDLE != ir) {
                retVal = IR::SUCCESS;
            }
        }
    }

    return retVal;
}