static apr_status_t create_socket_pipe()

in network_io/win32/socket_pipe.c [20:145]


static apr_status_t create_socket_pipe(SOCKET *rd, SOCKET *wr)
{
    FD_SET rs;
    SOCKET ls;
    struct timeval socktm;
    struct sockaddr_in pa;
    struct sockaddr_in la;
    struct sockaddr_in ca;
    int nrd;
    apr_status_t rv;
    int ll = sizeof(la);
    int lc = sizeof(ca);
    unsigned long bm = 1;
    char uid[8];
    char iid[8];

    *rd = INVALID_SOCKET;
    *wr = INVALID_SOCKET;

    /* Create the unique socket identifier
     * so that we know the connection originated
     * from us.
     */
    rv = apr_generate_random_bytes(uid, sizeof(uid));
    if (rv != APR_SUCCESS) {
        return rv;
    }

    if ((ls = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {
        return apr_get_netos_error();
    }

    pa.sin_family = AF_INET;
    pa.sin_port = 0;
    pa.sin_addr.s_addr = inet_addr("127.0.0.1");

    if (bind(ls, (SOCKADDR *)&pa, sizeof(pa)) == SOCKET_ERROR) {
        rv = apr_get_netos_error();
        goto cleanup;
    }
    if (getsockname(ls, (SOCKADDR *)&la, &ll) == SOCKET_ERROR) {
        rv = apr_get_netos_error();
        goto cleanup;
    }
    if (listen(ls, 1) == SOCKET_ERROR) {
        rv = apr_get_netos_error();
        goto cleanup;
    }
    if ((*wr = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {
        rv = apr_get_netos_error();
        goto cleanup;
    }
    if (connect(*wr, (SOCKADDR *)&la, sizeof(la)) == SOCKET_ERROR) {
        rv = apr_get_netos_error();
        goto cleanup;
    }
    if (send(*wr, uid, sizeof(uid), 0) != sizeof(uid)) {
        if ((rv = apr_get_netos_error()) == 0) {
            rv = APR_EINVAL;
        }
        goto cleanup;
    }
    if (ioctlsocket(ls, FIONBIO, &bm) == SOCKET_ERROR) {
        rv = apr_get_netos_error();
        goto cleanup;
    }
    for (;;) {
        int ns;
        int nc = 0;
        /* Listening socket is nonblocking by now.
         * The accept should create the socket
         * immediatelly because we are connected already.
         * However on buys systems this can take a while
         * until winsock gets a chance to handle the events.
         */
        FD_ZERO(&rs);
        FD_SET(ls, &rs);

        socktm.tv_sec = 1;
        socktm.tv_usec = 0;
        if ((ns = select(0, &rs, NULL, NULL, &socktm)) == SOCKET_ERROR) {
            /* Accept still not signaled */
            Sleep(100);
            continue;
        }
        if (ns == 0) {
            /* No connections in the last second */
            continue;
        }
        if ((*rd = accept(ls, (SOCKADDR *)&ca, &lc)) == INVALID_SOCKET) {
            rv = apr_get_netos_error();
            goto cleanup;
        }
        /* Verify the connection by reading/waiting for the identification */
        bm = 0;
        if (ioctlsocket(*rd, FIONBIO, &bm) == SOCKET_ERROR) {
            rv = apr_get_netos_error();
            goto cleanup;
        }
        nrd = recv(*rd, iid, sizeof(iid), 0);
        if (nrd == SOCKET_ERROR) {
            rv = apr_get_netos_error();
            goto cleanup;
        }
        if (nrd == (int)sizeof(uid) && memcmp(iid, uid, sizeof(uid)) == 0) {
            /* Got the right identifier, return. */
            break;
        }
        closesocket(*rd);
    }
    /* We don't need the listening socket any more */
    closesocket(ls);
    return 0;

cleanup:
    /* Don't leak resources */
    closesocket(ls);
    if (*rd != INVALID_SOCKET)
        closesocket(*rd);
    if (*wr != INVALID_SOCKET)
        closesocket(*wr);

    *rd = INVALID_SOCKET;
    *wr = INVALID_SOCKET;
    return rv;
}