diff --git a/src/api/api_status.c b/src/api/api_status.c index 6d19e843..0057109f 100644 --- a/src/api/api_status.c +++ b/src/api/api_status.c @@ -90,12 +90,43 @@ api_status_connections return 0; } +static int +api_connections_cancel + ( access_t *perm, void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp ) +{ + htsmsg_field_t *f; + htsmsg_t *ids; + uint32_t id; + + if (!(f = htsmsg_field_find(args, "id"))) + return EINVAL; + if (!(ids = htsmsg_field_get_list(f))) + if (htsmsg_field_get_u32(f, &id)) + return EINVAL; + + if (ids) { + HTSMSG_FOREACH(f, ids) { + if (htsmsg_field_get_u32(f, &id)) continue; + if (!id) continue; + pthread_mutex_lock(&global_lock); + tcp_connection_cancel(id); + pthread_mutex_unlock(&global_lock); + } + } else { + pthread_mutex_lock(&global_lock); + tcp_connection_cancel(id); + pthread_mutex_unlock(&global_lock); + } + return 0; +} + void api_status_init ( void ) { static api_hook_t ah[] = { { "status/connections", ACCESS_ADMIN, api_status_connections, NULL }, { "status/subscriptions", ACCESS_ADMIN, api_status_subscriptions, NULL }, { "status/inputs", ACCESS_ADMIN, api_status_inputs, NULL }, + { "connections/cancel", ACCESS_ADMIN, api_connections_cancel, NULL }, { NULL }, }; diff --git a/src/htsp_server.c b/src/htsp_server.c index a7ab5dbe..df929355 100644 --- a/src/htsp_server.c +++ b/src/htsp_server.c @@ -2567,6 +2567,10 @@ htsp_serve(int fd, void **opaque, struct sockaddr_storage *source, static void htsp_server_cancel ( void *opaque ) { + htsp_connection_t *htsp = opaque; + + if (htsp) + shutdown(htsp->htsp_fd, SHUT_RDWR); } /** diff --git a/src/http.c b/src/http.c index 692de1ec..19ecc4cf 100644 --- a/src/http.c +++ b/src/http.c @@ -976,16 +976,14 @@ http_serve(int fd, void **opaque, struct sockaddr_storage *peer, *opaque = NULL; } -#if 0 static void -http_server_status ( void *opaque, htsmsg_t *m ) +http_cancel( void *opaque ) { -// http_connection_t *hc = opaque; - htsmsg_add_str(m, "type", "HTTP"); - if (hc->hc_username) - htsmsg_add_str(m, "user", hc->hc_username); + http_connection_t *hc = opaque; + + if (hc) + shutdown(hc->hc_fd, SHUT_RDWR); } -#endif /** * Fire up HTTP server @@ -996,7 +994,7 @@ http_server_init(const char *bindaddr) static tcp_server_ops_t ops = { .start = http_serve, .stop = NULL, - .cancel = NULL + .cancel = http_cancel }; http_server = tcp_server_create(bindaddr, tvheadend_webui_port, &ops, NULL); } diff --git a/src/tcp.c b/src/tcp.c index 47c0d16d..8c0576b4 100644 --- a/src/tcp.c +++ b/src/tcp.c @@ -459,13 +459,13 @@ try_again: * */ void -tcp_connection_land(void *id) +tcp_connection_land(void *tcp_id) { - tcp_server_launch_t *tsl = id; + tcp_server_launch_t *tsl = tcp_id; lock_assert(&global_lock); - if (id == NULL) + if (tsl == NULL) return; LIST_REMOVE(tsl, link); @@ -475,6 +475,24 @@ tcp_connection_land(void *id) tsl->representative = NULL; } +/** + * + */ +void +tcp_connection_cancel(uint32_t id) +{ + tcp_server_launch_t *tsl; + + lock_assert(&global_lock); + + LIST_FOREACH(tsl, &tcp_server_active, alink) + if (tsl->id == id) { + if (tsl->ops.cancel) + tsl->ops.cancel(tsl->opaque); + break; + } +} + /* * */ diff --git a/src/tcp.h b/src/tcp.h index d08adc35..43dd7d44 100644 --- a/src/tcp.h +++ b/src/tcp.h @@ -83,7 +83,8 @@ struct access; void *tcp_connection_launch(int fd, void (*status) (void *opaque, htsmsg_t *m), struct access *aa); -void tcp_connection_land(void *id); +void tcp_connection_land(void *tcp_id); +void tcp_connection_cancel(uint32_t id); htsmsg_t *tcp_server_connections ( void ); diff --git a/src/webui/static/app/status.js b/src/webui/static/app/status.js index 2d39e151..868f4f8f 100644 --- a/src/webui/static/app/status.js +++ b/src/webui/static/app/status.js @@ -449,6 +449,33 @@ tvheadend.status_conns = function(panel, index) { if (grid) return; + var actions = new Ext.ux.grid.RowActions({ + header: '', + width: 10, + actions: [ + { + iconCls: 'cancel', + qtip: 'Cancel this connection', + cb: function(grid, rec, act, row) { + var id = grid.getStore().getAt(row).data.id; + Ext.MessageBox.confirm('Cancel Connection', + 'Cancel the selected connection?', + function(button) { + if (button === 'no') + return; + Ext.Ajax.request({ + url: 'api/connections/cancel', + params: { id: id }, + }); + } + ); + } + }, + ], + destroy: function() { + } + }); + store = new Ext.data.JsonStore({ root: 'entries', totalProperty: 'totalCount', @@ -475,7 +502,9 @@ tvheadend.status_conns = function(panel, index) { return dt.format('Y-m-d H:i:s'); } - var cm = new Ext.grid.ColumnModel([{ + var cm = new Ext.grid.ColumnModel([ + actions, + { width: 50, id: 'type', header: "Type", @@ -508,7 +537,8 @@ tvheadend.status_conns = function(panel, index) { flex: 1, viewConfig: { forceFit: true - } + }, + plugins: [actions], }); dpanel.add(grid);