示例#1
0
int virNetClientGetFD(virNetClientPtr client)
{
    int fd;
    virNetClientLock(client);
    fd = virNetSocketGetFD(client->sock);
    virNetClientUnlock(client);
    return fd;
}
示例#2
0
int virNetServerClientGetFD(virNetServerClientPtr client)
{
    int fd = -1;
    virNetServerClientLock(client);
    if (client->sock)
        fd = virNetSocketGetFD(client->sock);
    virNetServerClientUnlock(client);
    return fd;
}
示例#3
0
/*
 * Process all calls pending dispatch/receive until we
 * get a reply to our own call. Then quit and pass the buck
 * to someone else.
 */
static int virNetClientIOEventLoop(virNetClientPtr client,
                                   virNetClientCallPtr thiscall)
{
    struct pollfd fds[2];
    int ret;

    fds[0].fd = virNetSocketGetFD(client->sock);
    fds[1].fd = client->wakeupReadFD;

    for (;;) {
        virNetClientCallPtr tmp = client->waitDispatch;
        virNetClientCallPtr prev;
        char ignore;
        sigset_t oldmask, blockedsigs;
        int timeout = -1;

        /* If we have existing SASL decoded data we
         * don't want to sleep in the poll(), just
         * check if any other FDs are also ready
         */
        if (virNetSocketHasCachedData(client->sock))
            timeout = 0;

        fds[0].events = fds[0].revents = 0;
        fds[1].events = fds[1].revents = 0;

        fds[1].events = POLLIN;
        while (tmp) {
            if (tmp->mode == VIR_NET_CLIENT_MODE_WAIT_RX)
                fds[0].events |= POLLIN;
            if (tmp->mode == VIR_NET_CLIENT_MODE_WAIT_TX)
                fds[0].events |= POLLOUT;

            tmp = tmp->next;
        }

        /* We have to be prepared to receive stream data
         * regardless of whether any of the calls waiting
         * for dispatch are for streams.
         */
        if (client->nstreams)
            fds[0].events |= POLLIN;

        /* Release lock while poll'ing so other threads
         * can stuff themselves on the queue */
        virNetClientUnlock(client);

        /* Block SIGWINCH from interrupting poll in curses programs,
         * then restore the original signal mask again immediately
         * after the call (RHBZ#567931).  Same for SIGCHLD and SIGPIPE
         * at the suggestion of Paolo Bonzini and Daniel Berrange.
         */
        sigemptyset (&blockedsigs);
#ifdef SIGWINCH
        sigaddset (&blockedsigs, SIGWINCH);
#endif
#ifdef SIGCHLD
        sigaddset (&blockedsigs, SIGCHLD);
#endif
        sigaddset (&blockedsigs, SIGPIPE);
        ignore_value(pthread_sigmask(SIG_BLOCK, &blockedsigs, &oldmask));

    repoll:
        ret = poll(fds, ARRAY_CARDINALITY(fds), timeout);
        if (ret < 0 && errno == EAGAIN)
            goto repoll;

        ignore_value(pthread_sigmask(SIG_SETMASK, &oldmask, NULL));

        virNetClientLock(client);

        /* If we have existing SASL decoded data, pretend
         * the socket became readable so we consume it
         */
        if (virNetSocketHasCachedData(client->sock))
            fds[0].revents |= POLLIN;

        if (fds[1].revents) {
            VIR_DEBUG("Woken up from poll by other thread");
            if (saferead(client->wakeupReadFD, &ignore, sizeof(ignore)) != sizeof(ignore)) {
                virReportSystemError(errno, "%s",
                                     _("read on wakeup fd failed"));
                goto error;
            }
        }

        if (ret < 0) {
            if (errno == EWOULDBLOCK)
                continue;
            virReportSystemError(errno,
                                 "%s", _("poll on socket failed"));
            goto error;
        }

        if (fds[0].revents & POLLOUT) {
            if (virNetClientIOHandleOutput(client) < 0)
                goto error;
        }

        if (fds[0].revents & POLLIN) {
            if (virNetClientIOHandleInput(client) < 0)
                goto error;
        }

        /* Iterate through waiting threads and if
         * any are complete then tell 'em to wakeup
         */
        tmp = client->waitDispatch;
        prev = NULL;
        while (tmp) {
            if (tmp != thiscall &&
                tmp->mode == VIR_NET_CLIENT_MODE_COMPLETE) {
                /* Take them out of the list */
                if (prev)
                    prev->next = tmp->next;
                else
                    client->waitDispatch = tmp->next;

                /* And wake them up....
                 * ...they won't actually wakeup until
                 * we release our mutex a short while
                 * later...
                 */
                VIR_DEBUG("Waking up sleep %p %p", tmp, client->waitDispatch);
                virCondSignal(&tmp->cond);
            } else {
                prev = tmp;
            }
            tmp = tmp->next;
        }

        /* Now see if *we* are done */
        if (thiscall->mode == VIR_NET_CLIENT_MODE_COMPLETE) {
            /* We're at head of the list already, so
             * remove us
             */
            client->waitDispatch = thiscall->next;
            VIR_DEBUG("Giving up the buck %p %p", thiscall, client->waitDispatch);
            /* See if someone else is still waiting
             * and if so, then pass the buck ! */
            if (client->waitDispatch) {
                VIR_DEBUG("Passing the buck to %p", client->waitDispatch);
                virCondSignal(&client->waitDispatch->cond);
            }
            return 0;
        }


        if (fds[0].revents & (POLLHUP | POLLERR)) {
            virNetError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("received hangup / error event on socket"));
            goto error;
        }
    }


error:
    client->waitDispatch = thiscall->next;
    VIR_DEBUG("Giving up the buck due to I/O error %p %p", thiscall, client->waitDispatch);
    /* See if someone else is still waiting
     * and if so, then pass the buck ! */
    if (client->waitDispatch) {
        VIR_DEBUG("Passing the buck to %p", client->waitDispatch);
        virCondSignal(&client->waitDispatch->cond);
    }
    return -1;
}
示例#4
0
int virNetClientSetTLSSession(virNetClientPtr client,
                              virNetTLSContextPtr tls)
{
    int ret;
    char buf[1];
    int len;
    struct pollfd fds[1];
    sigset_t oldmask, blockedsigs;

    sigemptyset (&blockedsigs);
#ifdef SIGWINCH
    sigaddset (&blockedsigs, SIGWINCH);
#endif
#ifdef SIGCHLD
    sigaddset (&blockedsigs, SIGCHLD);
#endif
    sigaddset (&blockedsigs, SIGPIPE);

    virNetClientLock(client);

    if (!(client->tls = virNetTLSSessionNew(tls,
                                            client->hostname)))
        goto error;

    virNetSocketSetTLSSession(client->sock, client->tls);

    for (;;) {
        ret = virNetTLSSessionHandshake(client->tls);

        if (ret < 0)
            goto error;
        if (ret == 0)
            break;

        fds[0].fd = virNetSocketGetFD(client->sock);
        fds[0].revents = 0;
        if (virNetTLSSessionGetHandshakeStatus(client->tls) ==
            VIR_NET_TLS_HANDSHAKE_RECVING)
            fds[0].events = POLLIN;
        else
            fds[0].events = POLLOUT;

        /* Block SIGWINCH from interrupting poll in curses programs,
         * then restore the original signal mask again immediately
         * after the call (RHBZ#567931).  Same for SIGCHLD and SIGPIPE
         * at the suggestion of Paolo Bonzini and Daniel Berrange.
         */
        ignore_value(pthread_sigmask(SIG_BLOCK, &blockedsigs, &oldmask));

    repoll:
        ret = poll(fds, ARRAY_CARDINALITY(fds), -1);
        if (ret < 0 && errno == EAGAIN)
            goto repoll;

        ignore_value(pthread_sigmask(SIG_BLOCK, &oldmask, NULL));
    }

    ret = virNetTLSContextCheckCertificate(tls, client->tls);

    if (ret < 0)
        goto error;

    /* At this point, the server is verifying _our_ certificate, IP address,
     * etc.  If we make the grade, it will send us a '\1' byte.
     */

    fds[0].fd = virNetSocketGetFD(client->sock);
    fds[0].revents = 0;
    fds[0].events = POLLIN;

    /* Block SIGWINCH from interrupting poll in curses programs */
    ignore_value(pthread_sigmask(SIG_BLOCK, &blockedsigs, &oldmask));

    repoll2:
    ret = poll(fds, ARRAY_CARDINALITY(fds), -1);
    if (ret < 0 && errno == EAGAIN)
        goto repoll2;

    ignore_value(pthread_sigmask(SIG_BLOCK, &oldmask, NULL));

    len = virNetTLSSessionRead(client->tls, buf, 1);
    if (len < 0 && errno != ENOMSG) {
        virReportSystemError(errno, "%s",
                             _("Unable to read TLS confirmation"));
        goto error;
    }
    if (len != 1 || buf[0] != '\1') {
        virNetError(VIR_ERR_RPC, "%s",
                    _("server verification (of our certificate or IP "
                      "address) failed"));
        goto error;
    }

    virNetClientUnlock(client);
    return 0;

error:
    virNetTLSSessionFree(client->tls);
    client->tls = NULL;
    virNetClientUnlock(client);
    return -1;
}