Author: Andy Green Date: Sun Sep 06 08:42:58 2026 +0100 web: forward taskcan to sai-server over the ss link, fixes F-008 The browser TASKCANCEL case called saiw_task_cancel(), which appended a sai_cancel_t to vhd->web_to_srv_owner... an owner with no consumer anywhere, so the UI's task STOP button did nothing via this path and each admin click leaked one small heap allocation for the life of the vhd. Forward com.warmcat.sai.taskcan to sai-server on the websrv ss link like the other admin ops (the raw browser JSON is queued on the ss tx buflist at the end of the rx handler), and remove the orphaned saiw_task_cancel(), its declaration and the dead web_to_srv_owner field. sai-server already had a handler for the forwarded schema, but it cast the decoded object to sai_browse_rx_evinfo_t and read event_hash at struct offset 0 -- com.warmcat.sai.taskcan decodes into sai_cancel_t, whose first member is the lws_dll2 and the uuid sits after it, so the handler validated garbage and always rejected. Cast to sai_cancel_t and use task_uuid as the map defines. diff --git a/src/server/s-ws-web.c b/src/server/s-ws-web.c index 7b3600f..a9acebb 100644 --- a/src/server/s-ws-web.c +++ b/src/server/s-ws-web.c @@ -450,6 +450,7 @@ websrvss_ws_rx(void *userobj, const uint8_t *buf, size_t len, int flags) { websrvss_srv_t *m = (websrvss_srv_t *)userobj; sai_browse_rx_evinfo_t *ei; + sai_cancel_t *can; lws_struct_args_t a; sai_db_result_t r; int n; @@ -619,11 +620,11 @@ websrvss_ws_rx(void *userobj, const uint8_t *buf, size_t len, int flags) break; case SAIS_WS_WEBSRV_RX_TASKCANCEL: - ei = (sai_browse_rx_evinfo_t *)a.dest; - if (sais_validate_id(ei->event_hash, SAI_TASKID_LEN)) + can = (sai_cancel_t *)a.dest; + if (sais_validate_id(can->task_uuid, SAI_TASKID_LEN)) goto soft_error; - sais_task_cancel(m->vhd, ei->event_hash, 0, 0); + sais_task_cancel(m->vhd, can->task_uuid, 0, 0); break; diff --git a/src/web/w-comms.c b/src/web/w-comms.c index 83abb12..c70e8a4 100644 --- a/src/web/w-comms.c +++ b/src/web/w-comms.c @@ -72,25 +72,6 @@ static const char * const well_known[] = { #define SAIW_BROWSER_MAX_CONNS 100 int -saiw_task_cancel(struct vhd *vhd, const char *task_uuid) -{ - sai_cancel_t *can = malloc(sizeof(*can)); - - if (!can) - return 1; - - - memset(can, 0, sizeof(*can)); - - lws_strncpy(can->task_uuid, task_uuid, sizeof(can->task_uuid)); - - lws_dll2_add_tail(&can->list, &vhd->web_to_srv_owner); - - - return 0; -} - -int sai_get_head_status(struct vhd *vhd, const char *projname) { struct lwsac *ac = NULL; diff --git a/src/web/w-private.h b/src/web/w-private.h index 4f6bef7..a0a32c1 100644 --- a/src/web/w-private.h +++ b/src/web/w-private.h @@ -176,7 +176,6 @@ struct vhd { struct lws_dll2_owner pcons_owner; struct lwsac *pcons; - lws_dll2_owner_t web_to_srv_owner; lws_dll2_owner_t subs_owner; sqlite3 *pdb; @@ -253,9 +252,6 @@ void saiw_central_cb(lws_sorted_usec_list_t *sul); int -saiw_task_cancel(struct vhd *vhd, const char *task_uuid); - -int saiw_get_blob(struct vhd *vhd, const char *url, sqlite3 **pdb, sqlite3_blob **blob, uint64_t *length); diff --git a/src/web/w-ws-browser.c b/src/web/w-ws-browser.c index 3e0422c..9eba68a 100644 --- a/src/web/w-ws-browser.c +++ b/src/web/w-ws-browser.c @@ -1105,9 +1105,7 @@ saiw_ws_json_rx_browser(struct vhd *vhd, struct pss *pss, uint8_t *buf, lwsl_notice("%s: received request to cancel task %s\n", __func__, can->task_uuid); - - saiw_task_cancel(vhd, can->task_uuid); - goto ok; + break; /* forward it to sai-server with the rest */ case SAIM_WS_BROWSER_RX_REBUILD: /*