struct blob_attr data[];
};
+static int ubus_cmp_id(const void *k1, const void *k2, void *ptr)
+{
+ const uint32_t *id1 = k1, *id2 = k2;
+
+ if (*id1 < *id2)
+ return -1;
+ else
+ return *id1 > *id2;
+}
+
struct blob_attr **ubus_parse_msg(struct blob_attr *msg)
{
blob_parse(msg, attrbuf, ubus_policy, UBUS_ATTR_MAX);
return err;
}
-int ubus_start_request(struct ubus_context *ctx, struct ubus_request *req,
- struct blob_attr *msg, int cmd, uint32_t peer)
+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)
};
- memset(req, 0, sizeof(*req));
hdr.version = 0;
hdr.type = cmd;
- hdr.seq = ++ctx->request_seq;
+ hdr.seq = seq;
hdr.peer = peer;
- req->peer = hdr.peer;
- req->seq = hdr.seq;
-
if (!msg) {
blob_buf_init(&b, 0);
msg = b.head;
iov[1].iov_base = (char *) msg;
iov[1].iov_len = blob_raw_len(msg);
- INIT_LIST_HEAD(&req->list);
- INIT_LIST_HEAD(&req->pending);
return writev(ctx->sock.fd, iov, 2);
}
+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));
+
+ 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;
data = list_first_entry(&req->pending,
struct ubus_pending_data, list);
list_del(&data->list);
- req->data_cb(req, data->type, data->data);
+ if (!req->cancelled)
+ req->data_cb(req, data->type, data->data);
free(data);
}
}
list_add(&data->list, &req->pending);
}
-static void ubus_process_msg(struct ubus_context *ctx, struct ubus_msghdr *hdr)
+static struct ubus_request *ubus_find_request(struct ubus_context *ctx, uint32_t seq, uint32_t peer)
{
struct ubus_request *req;
list_for_each_entry(req, &ctx->requests, list) {
- if (hdr->seq != req->seq || hdr->peer != req->peer)
+ if (seq != req->seq || peer != req->peer)
continue;
- switch(hdr->type) {
- case UBUS_MSG_STATUS:
- ubus_process_req_status(req, hdr);
- return;
- case UBUS_MSG_DATA:
- if (req->data_cb)
- ubus_req_data(req, hdr);
- break;
- default:
- DPRINTF("unknown message type: %d\n", hdr->type);
+ return req;
+ }
+ return NULL;
+}
+
+static void ubus_process_invoke(struct ubus_context *ctx, struct ubus_msghdr *hdr)
+{
+ uint32_t objid = 0;
+ int ret = 0;
+
+ ubus_parse_msg(hdr->data);
+
+ if (attrbuf[UBUS_ATTR_OBJID])
+ objid = blob_get_int32(attrbuf[UBUS_ATTR_OBJID]);
+
+ 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);
+}
+
+static void ubus_process_msg(struct ubus_context *ctx, struct ubus_msghdr *hdr)
+{
+ struct ubus_request *req;
+
+ switch(hdr->type) {
+ case UBUS_MSG_STATUS:
+ req = ubus_find_request(ctx, hdr->seq, hdr->peer);
+ if (!req)
break;
- }
+
+ ubus_process_req_status(req, hdr);
+ break;
+
+ case UBUS_MSG_DATA:
+ req = ubus_find_request(ctx, hdr->seq, hdr->peer);
+ if (req && req->data_cb)
+ ubus_req_data(req, hdr);
+ break;
+
+ case UBUS_MSG_INVOKE:
+ ubus_process_invoke(ctx, hdr);
+ break;
+ default:
+ DPRINTF("unknown message type: %d\n", hdr->type);
+ break;
}
}
if (!list_empty(&req->list))
return;
+ req->cancelled = true;
+ ubus_process_req_data(req);
list_del(&req->list);
}
if (req->status_msg)
return req->status_code;
+ if (req->cancelled)
+ return UBUS_STATUS_NO_DATA;
+
if (!get_next_msg(ctx, true))
return UBUS_STATUS_NO_DATA;
ubus_req_data(req, hdr);
continue;
default:
- DPRINTF("unknown message type: %d\n", hdr->type);
- continue;
+ goto skip;
}
skip:
if (attrbuf[UBUS_ATTR_OBJTYPE])
obj->type->id = blob_get_int32(attrbuf[UBUS_ATTR_OBJTYPE]);
+
+ obj->avl.key = &obj->id;
+ avl_insert(&req->ctx->objects, &obj->avl);
}
static bool ubus_push_table_data(const struct ubus_signature **sig, int *rem, bool array)
blob_buf_init(&b, 0);
blob_put_string(&b, UBUS_ATTR_OBJPATH, obj->name);
- if (obj->parent)
- blob_put_int32(&b, UBUS_ATTR_OBJID, obj->parent->id);
if (obj->type->id)
blob_put_int32(&b, UBUS_ATTR_OBJTYPE, obj->type->id);
ctx->local_id = hdr.hdr.peer;
free(buf);
+ INIT_LIST_HEAD(&ctx->requests);
+ avl_init(&ctx->objects, ubus_cmp_id, false, NULL);
+
if (!ctx->local_id) {
DPRINTF("Failed to get local peer id\n");
goto error_close;