+/*
+ * Copyright (C) 2011 Felix Fietkau <nbd@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <unistd.h>
+#include <poll.h>
#include <libubox/blob.h>
#include <libubox/blobmsg.h>
[UBUS_STATUS_NO_DATA] = "No response",
[UBUS_STATUS_PERMISSION_DENIED] = "Permission denied",
[UBUS_STATUS_TIMEOUT] = "Request timed out",
+ [UBUS_STATUS_NOT_SUPPORTED] = "Operation not supported",
+ [UBUS_STATUS_UNKNOWN_ERROR] = "Unknown error",
};
static struct blob_buf b;
return err;
}
+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;
if (cur_len < 0) {
switch(errno) {
case EAGAIN:
- /* turn off non-blocking mode */
- fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) &
- ~O_NONBLOCK);
+ wait_data(fd, true);
break;
case EINTR:
break;
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;
int ret = UBUS_STATUS_INVALID_ARGUMENT;
if (!list_empty(&req->list))
- list_del(&req->list);
+ list_del_init(&req->list);
ubus_get_status(hdr, &ret);
req->peer = hdr->peer;
int method;
int ret = 0;
+ req.peer = hdr->peer;
+ req.seq = hdr->seq;
ubus_parse_msg(hdr->data);
if (!attrbuf[UBUS_ATTR_OBJID])
found:
req.object = objid;
- req.peer = hdr->peer;
- req.seq = hdr->seq;
ret = obj->methods[method].handler(ctx, obj, &req,
blob_data(attrbuf[UBUS_ATTR_METHOD]),
attrbuf[UBUS_ATTR_DATA]);
blob_buf_init(&b, 0);
blob_put_int32(&b, UBUS_ATTR_STATUS, ret);
blob_put_int32(&b, UBUS_ATTR_OBJID, objid);
- ubus_send_msg(ctx, hdr->seq, b.head, UBUS_MSG_STATUS, hdr->peer);
+ ubus_send_msg(ctx, req.seq, b.head, UBUS_MSG_STATUS, req.peer);
}
static void ubus_process_msg(struct ubus_context *ctx, struct ubus_msghdr *hdr)
req->cancelled = true;
ubus_process_req_data(req);
- list_del(&req->list);
+ list_del_init(&req->list);
}
void ubus_complete_request_async(struct ubus_context *ctx, struct ubus_request *req)
struct ubus_sync_req_cb cb;
ubus_complete_handler_t complete_cb = req->complete_cb;
bool registered = ctx->sock.registered;
- bool cancelled = uloop_cancelled;
int status = UBUS_STATUS_NO_DATA;
if (!registered) {
ubus_complete_request_async(ctx, req);
req->complete_cb = ubus_sync_req_cb;
- uloop_run();
+ while (!req->status_msg) {
+ bool cancelled = uloop_cancelled;
+ uloop_cancelled = false;
+ uloop_run();
+ uloop_cancelled = cancelled;
+ }
if (timeout)
uloop_timeout_cancel(&cb.timeout);
if (req->complete_cb)
req->complete_cb(req, status);
- uloop_cancelled = cancelled;
if (!registered)
uloop_fd_delete(&ctx->sock);
if (!ctx->local_id)
goto error_close;
+ fcntl(ctx->sock.fd, F_SETFL, fcntl(ctx->sock.fd, F_GETFL) | O_NONBLOCK);
+
return ctx;
error_free_buf: