Beispiel #1
0
int
call_putflush(struct call *cc, const char *s, unsigned int len)
{
	if (call_put(cc, s, len) == -1) return -1;
        if (call_flush(cc) == -1) return -1;
	return 0;
}
Beispiel #2
0
rstatus_t
call_recv(struct context *ctx, struct call *call)
{
    rstatus_t status;
    struct conn *conn = call->conn;
    ssize_t n;
    size_t rcvd;

    if (call->rsp.rsize == 0) {
        size_t chunk_size;

        ASSERT(call->rsp.rcurr > call->rsp.pcurr);

        /*
         * Make space in the read buffer by moving the unparsed chunk
         * at the tail end to the head.
         */
        chunk_size = (size_t)(call->rsp.rcurr - call->rsp.pcurr);
        mcp_memmove(conn->buf, call->rsp.pcurr, chunk_size);
        call->rsp.pcurr = conn->buf;
        call->rsp.rcurr = conn->buf + chunk_size;
        call->rsp.rsize = sizeof(conn->buf) - chunk_size;
    }

    if (call->rsp.rcvd == 0) {
        ecb_signal(ctx, EVENT_CALL_RECV_START, call);
    }

    n = conn_recv(conn, call->rsp.rcurr, call->rsp.rsize);

    rcvd = n > 0 ? (size_t)n : 0;

    call->rsp.rcvd += rcvd;
    call->rsp.rcurr += rcvd;
    call->rsp.rsize -= rcvd;

    if (n <= 0) {
        if (n == 0 || n == MCP_EAGAIN) {
            return MCP_OK;
        }
        return MCP_ERROR;
    }

    do {
        struct call *next_call; /* next call in recv q */

        status = call_parse_rsp(ctx, call);
        if (status != MCP_OK) {
            if (status == MCP_EAGAIN) {
                /* incomplete response; parse again when more data arrives */
                return MCP_OK;
            }
            return status;
        }

        next_call = NULL;
        /*
         * Spill over unparsed response onto the next call and update
         * the current call appropriately
         */
        if (call->rsp.rcurr != call->rsp.pcurr) {
            next_call = STAILQ_NEXT(call, call_tqe);
            if (next_call == NULL) {
                log_debug(LOG_ERR, "stray response type %d on c %"PRIu64"",
                          call->rsp.type, conn->id);
                conn->err = EINVAL;
                return MCP_ERROR;
            }

            ecb_signal(ctx, EVENT_CALL_RECV_START, next_call);

            next_call->rsp.rcurr = call->rsp.rcurr;
            next_call->rsp.rsize = call->rsp.rsize;
            next_call->rsp.pcurr = call->rsp.pcurr;

            /*
             * Calculate the exact bytes received on this call and accumulate
             * the remaining bytes onto the next call
             */
            ASSERT(call->rsp.rcurr > call->rsp.pcurr);
            next_call->rsp.rcvd = (size_t)(call->rsp.rcurr - call->rsp.pcurr);
            call->rsp.rcvd -= next_call->rsp.rcvd;
        }

        conn->ncall_recvq--;
        STAILQ_REMOVE(&conn->call_recvq, call, call, call_tqe);

        call_reset_timer(ctx, call);

        ecb_signal(ctx, EVENT_CALL_RECV_STOP, call);
        ecb_signal(ctx, EVENT_CALL_DESTROYED, call);

        call_put(call);

        call = next_call;
    } while (call != NULL);

    return MCP_OK;
}
Beispiel #3
0
rstatus_t
call_send(struct context *ctx, struct call *call)
{
    struct conn *conn = call->conn;
    size_t sent;
    ssize_t n;
    uint32_t i;

    ASSERT(call->req.send != 0);

    if (!call->req.sending) {
        /*
         * We might need multiple write events to send a call completely.
         * Signal the first time we start sending a given call.
         */
        ecb_signal(ctx, EVENT_CALL_SEND_START, call);
        call->req.sending = 1;
    }

    n = conn_sendv(conn, call->req.iov, REQ_IOV_LEN, call->req.send);

    sent = n > 0 ? (size_t)n : 0;

    log_debug(LOG_VERB, "send call %"PRIu64" on c %"PRIu64" sd %d %zu of %zu "
              "bytes", call->id, conn->id, conn->sd, sent, call->req.send);

    call->req.send -= sent;
    call->req.sent += sent;

    for (i = 0; i < REQ_IOV_LEN; i++) {
        struct iovec *iov = &call->req.iov[i];

        if (sent == 0) {
            break;
        }

        if (sent < iov->iov_len) {
            /* iov element was sent partially; send remaining bytes later */
            iov->iov_base = (char *)iov->iov_base + sent;
            iov->iov_len -= sent;
            sent = 0;
            break;
        }

        /* iov element was sent completely; mark it empty */
        sent -= iov->iov_len;
        iov->iov_base = NULL;
        iov->iov_len = 0;
    }

    if (call->req.send == 0) {
        ecb_signal(ctx, EVENT_CALL_SEND_STOP, call);

        /*
         * Call has been sent completely; move the call from sendq
         * to recvq unless it has been marked as noreply.
         */
        conn->ncall_sendq--;
        STAILQ_REMOVE(&conn->call_sendq, call, call, call_tqe);

        if (call->req.noreply) {
            ecb_signal(ctx, EVENT_CALL_DESTROYED, call);
            call_put(call);
        } else {
            STAILQ_INSERT_TAIL(&conn->call_recvq, call, call_tqe);
            conn->ncall_recvq++;
            call_start_timer(ctx, call);
        }
    }

    if (n > 0) {
        return MCP_OK;
    }

    return (n == MCP_EAGAIN) ? MCP_OK : MCP_ERROR;
}