static void client_close(struct client *cl)
{
+ if (cl->refcount) {
+ cl->state = CLIENT_STATE_CLEANUP;
+ return;
+ }
+
client_done = true;
n_clients--;
uh_dispatch_done(cl);
{
struct ustream *s = cl->us;
- if (!s->write_error) {
+ if (!s->write_error && cl->state != CLIENT_STATE_CLEANUP) {
if (cl->state == CLIENT_STATE_DATA)
return;
blob_buf_init(data.buf, 0);
+ uh_client_ref(cl);
+
if (!params || blob_id(params) != BLOBMSG_TYPE_ARRAY) {
r = blobmsg_open_array(data.buf, "result");
ubus_lookup(ctx, NULL, uh_ubus_list_cb, &data);
blobmsg_close_table(data.buf, r);
}
+ uh_client_unref(cl);
+
uh_ubus_init_response(cl);
blobmsg_add_blob(&buf, blob_data(data.buf->head));
uh_ubus_send_response(cl);
struct rpc_data data = {};
enum rpc_error err = ERROR_PARSE;
+ uh_client_ref(cl);
+
if (json_object_get_type(obj) != json_type_object)
goto error;
out:
if (data.params)
free(data.params);
+
+ uh_client_unref(cl);
}
static void __uh_ubus_next_batched_request(struct uloop_timeout *timeout)
CLIENT_STATE_DATA,
CLIENT_STATE_DONE,
CLIENT_STATE_CLOSE,
+ CLIENT_STATE_CLEANUP,
};
struct interpreter {
struct client {
struct list_head list;
+ int refcount;
int id;
struct ustream *us;
int uh_plugin_init(const char *name);
void uh_plugin_post_init(void);
+static inline void uh_client_ref(struct client *cl)
+{
+ cl->refcount++;
+}
+
+static inline void uh_client_unref(struct client *cl)
+{
+ if (--cl->refcount)
+ return;
+
+ if (cl->state == CLIENT_STATE_CLEANUP)
+ ustream_state_change(cl->us);
+}
+
#endif
{
bool chunked = uh_use_chunked(cl);
+ if (cl->state == CLIENT_STATE_CLEANUP)
+ return;
+
uloop_timeout_set(&cl->timeout, conf.network_timeout * 1000);
if (chunked)
ustream_printf(cl->us, "%X\r\n", len);
va_list arg2;
int len;
+ if (cl->state == CLIENT_STATE_CLEANUP)
+ return;
+
uloop_timeout_set(&cl->timeout, conf.network_timeout * 1000);
if (!uh_use_chunked(cl)) {
ustream_vprintf(cl->us, format, arg);
if (!uh_use_chunked(cl))
return;
+ if (cl->state == CLIENT_STATE_CLEANUP)
+ return;
+
ustream_printf(cl->us, "0\r\n\r\n");
}