X-Git-Url: http://git.openwrt.org/?a=blobdiff_plain;f=ubusd_proto.c;h=48de9b96141c8011061ac9ae7d9885d5a0eb6b12;hb=HEAD;hp=b20f91c793982159515d8afe8bae92e101223dda;hpb=4becbd67de5867ec32a53cb15566a6ef505f4619;p=project%2Fubus.git diff --git a/ubusd_proto.c b/ubusd_proto.c index b20f91c..48de9b9 100644 --- a/ubusd_proto.c +++ b/ubusd_proto.c @@ -186,16 +186,56 @@ static void ubusd_send_obj(struct ubus_client *cl, struct ubus_msg_buf *ub, stru ubus_proto_send_msg_from_blob(cl, ub, UBUS_MSG_DATA); } -static int ubusd_handle_lookup(struct ubus_client *cl, struct ubus_msg_buf *ub, struct blob_attr **attr) +static int ubus_client_cmd_queue_add(struct ubus_client *cl, + struct ubus_msg_buf *msg, + struct ubus_object *obj) { - struct ubus_object *obj; + struct ubus_client_cmd *cmd = malloc(sizeof(*cmd)); + + if (cmd) { + cmd->msg = msg; + cmd->obj = obj; + list_add_tail(&cmd->list, &cl->cmd_queue); + return -2; + } + return UBUS_STATUS_UNKNOWN_ERROR; +} + +static int __ubusd_handle_lookup(struct ubus_client *cl, + struct ubus_msg_buf *ub, + struct blob_attr **attr, + struct ubus_client_cmd *cmd) +{ + struct ubus_object *obj = NULL; char *objpath; bool found = false; int len; if (!attr[UBUS_ATTR_OBJPATH]) { - avl_for_each_element(&path, obj, path) - ubusd_send_obj(cl, ub, obj); + if (cmd) + obj = cmd->obj; + + /* Start from beginning or continue from the last object */ + if (obj == NULL) + obj = avl_first_element(&path, obj, path); + + avl_for_element_range(obj, avl_last_element(&path, obj, path), obj, path) { + /* Keep sending objects until buffering starts */ + if (list_empty(&cl->tx_queue)) { + ubusd_send_obj(cl, ub, obj); + } else { + /* Queue command and continue on the next call */ + int ret; + + if (cmd == NULL) { + ret = ubus_client_cmd_queue_add(cl, ub, obj); + } else { + cmd->obj = obj; + ret = -2; + } + return ret; + } + } return 0; } @@ -230,6 +270,40 @@ static int ubusd_handle_lookup(struct ubus_client *cl, struct ubus_msg_buf *ub, return 0; } +static int ubusd_handle_lookup(struct ubus_client *cl, struct ubus_msg_buf *ub, struct blob_attr **attr) +{ + int rc; + + if (list_empty(&cl->tx_queue)) + rc = __ubusd_handle_lookup(cl, ub, attr, NULL); + else + rc = ubus_client_cmd_queue_add(cl, ub, NULL); + + return rc; +} + +int ubusd_cmd_lookup(struct ubus_client *cl, struct ubus_client_cmd *cmd) +{ + struct ubus_msg_buf *ub = cmd->msg; + struct blob_attr **attr; + int ret; + + attr = ubus_parse_msg(ub->data, blob_raw_len(ub->data)); + ret = __ubusd_handle_lookup(cl, ub, attr, cmd); + + if (ret != -2) { + struct ubus_msg_buf *retmsg = cl->retmsg; + int *retmsg_data = blob_data(blob_data(retmsg->data)); + + retmsg->hdr.seq = ub->hdr.seq; + retmsg->hdr.peer = ub->hdr.peer; + + *retmsg_data = htonl(ret); + ubus_msg_send(cl, retmsg); + } + return ret; +} + static void ubusd_forward_invoke(struct ubus_client *cl, struct ubus_object *obj, const char *method, struct ubus_msg_buf *ub, @@ -458,6 +532,10 @@ void ubusd_proto_receive_message(struct ubus_client *cl, struct ubus_msg_buf *ub else ret = UBUS_STATUS_INVALID_COMMAND; + /* Command has not been completed yet and got queued */ + if (ret == -2) + return; + ubus_msg_free(ub); if (ret == -1) @@ -495,6 +573,7 @@ struct ubus_client *ubusd_proto_new_client(int fd, uloop_fd_handler cb) goto free; INIT_LIST_HEAD(&cl->objects); + INIT_LIST_HEAD(&cl->cmd_queue); INIT_LIST_HEAD(&cl->tx_queue); cl->sock.fd = fd; cl->sock.cb = cb;