-static void wait_data(int fd, bool write)
-{
- struct pollfd pfd = { .fd = fd };
-
- pfd.events = write ? POLLOUT : POLLIN;
- poll(&pfd, 1, 0);
-}
-
-static int writev_retry(int fd, struct iovec *iov, int iov_len)
-{
- int len = 0;
-
- do {
- int cur_len = writev(fd, iov, iov_len);
- if (cur_len < 0) {
- switch(errno) {
- case EAGAIN:
- wait_data(fd, true);
- break;
- case EINTR:
- break;
- default:
- return -1;
- }
- continue;
- }
- len += cur_len;
- while (cur_len >= iov->iov_len) {
- cur_len -= iov->iov_len;
- iov_len--;
- iov++;
- if (!cur_len || !iov_len)
- return len;
- }
- iov->iov_len -= cur_len;
- } while (1);
-}
-
-static int ubus_send_msg(struct ubus_context *ctx, uint32_t seq,
- struct blob_attr *msg, int cmd, uint32_t peer)
-{
- struct ubus_msghdr hdr;
- struct iovec iov[2] = {
- STATIC_IOV(hdr)
- };
-
- hdr.version = 0;
- hdr.type = cmd;
- hdr.seq = seq;
- hdr.peer = peer;
-
- if (!msg) {
- blob_buf_init(&b, 0);
- msg = b.head;
- }
-
- iov[1].iov_base = (char *) msg;
- iov[1].iov_len = blob_raw_len(msg);
-
- return writev_retry(ctx->sock.fd, iov, ARRAY_SIZE(iov));
-}
-
-static int ubus_start_request(struct ubus_context *ctx, struct ubus_request *req,
- struct blob_attr *msg, int cmd, uint32_t peer)
-{
- memset(req, 0, sizeof(*req));
-
- if (msg && blob_pad_len(msg) > UBUS_MAX_MSGLEN)
- return -1;
-
- INIT_LIST_HEAD(&req->list);
- INIT_LIST_HEAD(&req->pending);
- req->ctx = ctx;
- req->peer = peer;
- req->seq = ++ctx->request_seq;
- return ubus_send_msg(ctx, req->seq, msg, cmd, peer);
-}
-
-static bool recv_retry(int fd, struct iovec *iov, bool wait)
-{
- int bytes;
-
- while (iov->iov_len > 0) {
- if (wait)
- wait_data(fd, false);
-
- bytes = read(fd, iov->iov_base, iov->iov_len);
- if (bytes < 0) {
- bytes = 0;
- if (uloop_cancelled)
- return false;
- if (errno == EINTR)
- continue;
-
- if (errno != EAGAIN)
- return false;
- }
- if (!wait && !bytes)
- return false;
-
- wait = true;
- iov->iov_len -= bytes;
- iov->iov_base += bytes;
- }
-
- return true;
-}
-
-static bool ubus_validate_hdr(struct ubus_msghdr *hdr)
-{
- if (hdr->version != 0)
- return false;
-
- if (blob_raw_len(hdr->data) < sizeof(*hdr->data))
- return false;
-
- if (blob_pad_len(hdr->data) > UBUS_MAX_MSGLEN)
- return false;
-
- return true;
-}
-
-static bool get_next_msg(struct ubus_context *ctx)
-{
- struct iovec iov = STATIC_IOV(ctx->msgbuf.hdr);
-
- /* receive header + start attribute */
- iov.iov_len += sizeof(struct blob_attr);
- if (!recv_retry(ctx->sock.fd, &iov, false))
- return false;
-
- iov.iov_len = blob_len(ctx->msgbuf.hdr.data);
- if (iov.iov_len > 0 && !recv_retry(ctx->sock.fd, &iov, true))
- return false;
-
- return ubus_validate_hdr(&ctx->msgbuf.hdr);
-}
-
-static bool ubus_get_status(struct ubus_msghdr *hdr, int *ret)
-{
- ubus_parse_msg(hdr->data);
-
- if (!attrbuf[UBUS_ATTR_STATUS])
- return false;
-
- *ret = blob_get_u32(attrbuf[UBUS_ATTR_STATUS]);
- return true;
-}
-
-static void req_data_cb(struct ubus_request *req, int type, struct blob_attr *data)
-{
- struct blob_attr **attr;
-
- if (req->raw_data_cb)
- req->raw_data_cb(req, type, data);
-
- if (!req->data_cb)
- return;
-
- attr = ubus_parse_msg(data);
- req->data_cb(req, type, attr[UBUS_ATTR_DATA]);
-}
-
-static void ubus_process_req_data(struct ubus_request *req)
-{
- struct ubus_pending_data *data;
-
- while (!list_empty(&req->pending)) {
- data = list_first_entry(&req->pending,
- struct ubus_pending_data, list);
- list_del(&data->list);
- if (!req->cancelled)
- req_data_cb(req, data->type, data->data);
- free(data);
- }
-}
-
-static void ubus_req_complete_cb(struct ubus_request *req)
-{
- ubus_complete_handler_t cb = req->complete_cb;
-
- if (!cb)
- return;
-
- req->complete_cb = NULL;
- cb(req, req->status_code);
-}
-
-static int ubus_process_req_status(struct ubus_request *req, struct ubus_msghdr *hdr)
-{
- int ret = UBUS_STATUS_INVALID_ARGUMENT;
-
- if (!list_empty(&req->list))
- list_del(&req->list);
-
- ubus_get_status(hdr, &ret);
- req->peer = hdr->peer;
- req->status_msg = true;
- req->status_code = ret;
- if (!req->blocked)
- ubus_req_complete_cb(req);
-
- return ret;
-}
-
-static void ubus_req_data(struct ubus_request *req, struct ubus_msghdr *hdr)
-{
- struct ubus_pending_data *data;
- int len;
-
- if (!req->blocked) {
- req->blocked = true;
- req_data_cb(req, hdr->type, hdr->data);
- ubus_process_req_data(req);
- req->blocked = false;
-
- if (req->status_msg)
- ubus_req_complete_cb(req);
-
- return;
- }
-
- len = blob_raw_len(hdr->data);
- data = calloc(1, sizeof(*data) + len);
- if (!data)
- return;
-
- data->type = hdr->type;
- memcpy(data->data, hdr->data, len);
- list_add(&data->list, &req->pending);
-}
-
-static struct ubus_request *ubus_find_request(struct ubus_context *ctx, uint32_t seq, uint32_t peer)