/* Schedules 'msg' to be sent on 'rpc' and returns 'rpc''s status (as with * jsonrpc_get_status()). * * If 'msg' cannot be sent immediately, it is appended to a buffer. The caller * is responsible for ensuring that the amount of buffered data is somehow * limited. (jsonrpc_get_backlog() returns the amount of data currently * buffered in 'rpc'.) * * Always takes ownership of 'msg', regardless of success. */ int jsonrpc_send(struct jsonrpc *rpc, struct jsonrpc_msg *msg) { struct ofpbuf *buf; struct json *json; size_t length; char *s; if (rpc->status) { jsonrpc_msg_destroy(msg); return rpc->status; } jsonrpc_log_msg(rpc, "send", msg); json = jsonrpc_msg_to_json(msg); s = json_to_string(json, 0); length = strlen(s); json_destroy(json); buf = xmalloc(sizeof *buf); ofpbuf_use(buf, s, length); ofpbuf_set_size(buf, length); list_push_back(&rpc->output, &buf->list_node); rpc->backlog += length; if (rpc->backlog == length) { jsonrpc_run(rpc); } return rpc->status; }
/* Prefixes 'size' bytes to the head end of 'b', reallocating and copying its * data if necessary. Returns a pointer to the first byte of the data's * location in the ofpbuf. The new data is left uninitialized. */ void * ofpbuf_push_uninit(struct ofpbuf *b, size_t size) { ofpbuf_prealloc_headroom(b, size); ofpbuf_set_data(b, (char*)ofpbuf_data(b) - size); ofpbuf_set_size(b, ofpbuf_size(b) + size); return ofpbuf_data(b); }
/* Appends 'size' bytes of data to the tail end of 'b', reallocating and * copying its data if necessary. Returns a pointer to the first byte of the * new data, which is left uninitialized. */ void * ofpbuf_put_uninit(struct ofpbuf *b, size_t size) { void *p; ofpbuf_prealloc_tailroom(b, size); p = ofpbuf_tail(b); ofpbuf_set_size(b, ofpbuf_size(b) + size); return p; }
static void ofpbuf_use__(struct ofpbuf *b, void *base, size_t allocated, enum ofpbuf_source source) { ofpbuf_set_base(b, base); ofpbuf_set_data(b, base); ofpbuf_set_size(b, 0); ofpbuf_init__(b, allocated, source); }
/* Schedules 'msg' to be sent on 'rpc' and returns 'rpc''s status (as with * jsonrpc_get_status()). * * If 'msg' cannot be sent immediately, it is appended to a buffer. The caller * is responsible for ensuring that the amount of buffered data is somehow * limited. (jsonrpc_get_backlog() returns the amount of data currently * buffered in 'rpc'.) * * Always takes ownership of 'msg', regardless of success. */ int jsonrpc_send(struct jsonrpc *rpc, struct jsonrpc_msg *msg) { struct ofpbuf *buf; struct json *json; size_t length; char *s; if (rpc->status) { jsonrpc_msg_destroy(msg); return rpc->status; } jsonrpc_log_msg(rpc, "send", msg); json = jsonrpc_msg_to_json(msg); s = json_to_string(json, 0); length = strlen(s); json_destroy(json); buf = xmalloc(sizeof *buf); ofpbuf_use(buf, s, length); ofpbuf_set_size(buf, length); list_push_back(&rpc->output, &buf->list_node); rpc->output_count++; rpc->backlog += length; if (rpc->output_count >= 50) { VLOG_INFO_RL(&rl, "excessive sending backlog, jsonrpc: %s, num of" " msgs: %"PRIuSIZE", backlog: %"PRIuSIZE".", rpc->name, rpc->output_count, rpc->backlog); } if (rpc->backlog == length) { jsonrpc_run(rpc); } return rpc->status; }
/* Initializes 'b' as an ofpbuf whose data starts at 'data' and continues for * 'size' bytes. This is appropriate for an ofpbuf that will be used to * inspect existing data, without moving it around or reallocating it, and * generally without modifying it at all. * * An ofpbuf operation that requires reallocating data will assert-fail if this * function was used to initialize it. */ void ofpbuf_use_const(struct ofpbuf *b, const void *data, size_t size) { ofpbuf_use__(b, CONST_CAST(void *, data), size, OFPBUF_STACK); ofpbuf_set_size(b, size); }
static int nl_sock_recv__(struct nl_sock *sock, struct ofpbuf *buf, bool wait) { /* We can't accurately predict the size of the data to be received. The * caller is supposed to have allocated enough space in 'buf' to handle the * "typical" case. To handle exceptions, we make available enough space in * 'tail' to allow Netlink messages to be up to 64 kB long (a reasonable * figure since that's the maximum length of a Netlink attribute). */ struct nlmsghdr *nlmsghdr; #ifdef _WIN32 #define MAX_STACK_LENGTH 81920 uint8_t tail[MAX_STACK_LENGTH]; #else uint8_t tail[65536]; #endif struct iovec iov[2]; struct msghdr msg; ssize_t retval; int error; ovs_assert(buf->allocated >= sizeof *nlmsghdr); ofpbuf_clear(buf); iov[0].iov_base = ofpbuf_base(buf); iov[0].iov_len = buf->allocated; iov[1].iov_base = tail; iov[1].iov_len = sizeof tail; memset(&msg, 0, sizeof msg); msg.msg_iov = iov; msg.msg_iovlen = 2; /* Receive a Netlink message from the kernel. * * This works around a kernel bug in which the kernel returns an error code * as if it were the number of bytes read. It doesn't actually modify * anything in the receive buffer in that case, so we can initialize the * Netlink header with an impossible message length and then, upon success, * check whether it changed. */ nlmsghdr = ofpbuf_base(buf); do { nlmsghdr->nlmsg_len = UINT32_MAX; #ifdef _WIN32 boolean result = false; DWORD last_error = 0; result = ReadFile(sock->handle, tail, MAX_STACK_LENGTH, &retval, NULL); last_error = GetLastError(); if (last_error != ERROR_SUCCESS && !result) { retval = -1; errno = EAGAIN; } else { ofpbuf_put(buf, tail, retval); } #else retval = recvmsg(sock->fd, &msg, wait ? 0 : MSG_DONTWAIT); #endif error = (retval < 0 ? errno : retval == 0 ? ECONNRESET /* not possible? */ : nlmsghdr->nlmsg_len != UINT32_MAX ? 0 : retval); } while (error == EINTR); if (error) { if (error == ENOBUFS) { /* Socket receive buffer overflow dropped one or more messages that * the kernel tried to send to us. */ COVERAGE_INC(netlink_overflow); } return error; } if (msg.msg_flags & MSG_TRUNC) { VLOG_ERR_RL(&rl, "truncated message (longer than %"PRIuSIZE" bytes)", sizeof tail); return E2BIG; } if (retval < sizeof *nlmsghdr || nlmsghdr->nlmsg_len < sizeof *nlmsghdr || nlmsghdr->nlmsg_len > retval) { VLOG_ERR_RL(&rl, "received invalid nlmsg (%"PRIuSIZE" bytes < %"PRIuSIZE")", retval, sizeof *nlmsghdr); return EPROTO; } #ifndef _WIN32 ofpbuf_set_size(buf, MIN(retval, buf->allocated)); if (retval > buf->allocated) { COVERAGE_INC(netlink_recv_jumbo); ofpbuf_put(buf, tail, retval - buf->allocated); } #endif log_nlmsg(__func__, 0, ofpbuf_data(buf), ofpbuf_size(buf), sock->protocol); COVERAGE_INC(netlink_received); return 0; }