/* Adds 'c' at the head of 'q', which must not be full. */ void byteq_put(struct byteq *q, uint8_t c) { ovs_assert(!byteq_is_full(q)); *byteq_head(q) = c; q->head++; }
int jsonrpc_recv(struct jsonrpc *rpc, struct jsonrpc_msg **msgp) { *msgp = NULL; if (rpc->status) { return rpc->status; } while (!rpc->received) { if (byteq_is_empty(&rpc->input)) { size_t chunk; int retval; chunk = byteq_headroom(&rpc->input); retval = stream_recv(rpc->stream, byteq_head(&rpc->input), chunk); if (retval < 0) { if (retval == -EAGAIN) { return EAGAIN; } else { VLOG_WARN_RL(&rl, "%s: receive error: %s", rpc->name, strerror(-retval)); jsonrpc_error(rpc, -retval); return rpc->status; } } else if (retval == 0) { jsonrpc_error(rpc, EOF); return EOF; } byteq_advance_head(&rpc->input, retval); } else { size_t n, used; if (!rpc->parser) { rpc->parser = json_parser_create(0); } n = byteq_tailroom(&rpc->input); used = json_parser_feed(rpc->parser, (char *) byteq_tail(&rpc->input), n); byteq_advance_tail(&rpc->input, used); if (json_parser_is_done(rpc->parser)) { jsonrpc_received(rpc); if (rpc->status) { const struct byteq *q = &rpc->input; if (q->head <= BYTEQ_SIZE) { stream_report_content(q->buffer, q->head, STREAM_JSONRPC, THIS_MODULE, rpc->name); } return rpc->status; } } } } *msgp = rpc->received; rpc->received = NULL; return 0; }
/* Adds the 'n' bytes in 'p' at the head of 'q', which must have at least 'n' * bytes of free space. */ void byteq_putn(struct byteq *q, const void *p_, size_t n) { const uint8_t *p = p_; ovs_assert(byteq_avail(q) >= n); while (n > 0) { size_t chunk = MIN(n, byteq_headroom(q)); memcpy(byteq_head(q), p, chunk); byteq_advance_head(q, chunk); p += chunk; n -= chunk; } }
/* Reads as much possible from 'fd' into 'q'. Returns 0 if 'q' is completely * filled up by the read, EOF if end-of-file was reached before 'q' was filled, * and otherwise a positive errno value (e.g. EAGAIN if a socket or tty buffer * was drained). */ int byteq_read(struct byteq *q, int fd) { while (!byteq_is_full(q)) { ssize_t n = read(fd, byteq_head(q), byteq_headroom(q)); if (n > 0) { byteq_advance_head(q, n); } else { return !n ? EOF : errno; } } return 0; }
void async_append_write(struct async_append *ap, const void *data_, size_t size) { const uint8_t *data = data_; while (size > 0) { struct aiocb *aiocb; size_t chunk_size; void *chunk; while (async_append_is_full(ap)) { async_append_wait(ap); } chunk = byteq_head(&ap->byteq); chunk_size = byteq_headroom(&ap->byteq); if (chunk_size > size) { chunk_size = size; } memcpy(chunk, data, chunk_size); aiocb = &ap->aiocbs[ap->aiocb_head & (MAX_CBS - 1)]; memset(aiocb, 0, sizeof *aiocb); aiocb->aio_fildes = ap->fd; aiocb->aio_offset = 0; aiocb->aio_buf = chunk; aiocb->aio_nbytes = chunk_size; aiocb->aio_sigevent.sigev_notify = SIGEV_NONE; if (aio_write(aiocb) == -1) { async_append_flush(ap); ignore(write(ap->fd, data, size)); return; } data += chunk_size; size -= chunk_size; byteq_advance_head(&ap->byteq, chunk_size); ap->aiocb_head++; } }
/* Attempts to receive a message from 'rpc'. * * If successful, stores the received message in '*msgp' and returns 0. The * caller takes ownership of '*msgp' and must eventually destroy it with * jsonrpc_msg_destroy(). * * Otherwise, stores NULL in '*msgp' and returns one of the following: * * - EAGAIN: No message has been received. * * - EOF: The remote end closed the connection gracefully. * * - Otherwise an errno value that represents a JSON-RPC protocol violation * or another error fatal to the connection. 'rpc' will not send or * receive any more messages. */ int jsonrpc_recv(struct jsonrpc *rpc, struct jsonrpc_msg **msgp) { int i; *msgp = NULL; if (rpc->status) { return rpc->status; } for (i = 0; i < 50; i++) { size_t n, used; /* Fill our input buffer if it's empty. */ if (byteq_is_empty(&rpc->input)) { size_t chunk; int retval; chunk = byteq_headroom(&rpc->input); retval = stream_recv(rpc->stream, byteq_head(&rpc->input), chunk); if (retval < 0) { if (retval == -EAGAIN) { return EAGAIN; } else { VLOG_WARN_RL(&rl, "%s: receive error: %s", rpc->name, ovs_strerror(-retval)); jsonrpc_error(rpc, -retval); return rpc->status; } } else if (retval == 0) { jsonrpc_error(rpc, EOF); return EOF; } byteq_advance_head(&rpc->input, retval); } /* We have some input. Feed it into the JSON parser. */ if (!rpc->parser) { rpc->parser = json_parser_create(0); } n = byteq_tailroom(&rpc->input); used = json_parser_feed(rpc->parser, (char *) byteq_tail(&rpc->input), n); byteq_advance_tail(&rpc->input, used); /* If we have complete JSON, attempt to parse it as JSON-RPC. */ if (json_parser_is_done(rpc->parser)) { *msgp = jsonrpc_parse_received_message(rpc); if (*msgp) { return 0; } if (rpc->status) { const struct byteq *q = &rpc->input; if (q->head <= q->size) { stream_report_content(q->buffer, q->head, STREAM_JSONRPC, THIS_MODULE, rpc->name); } return rpc->status; } } } return EAGAIN; }