diff --git a/include/ctl-server.h b/include/ctl-server.h index 2f8a1dd..9dfbb8e 100644 --- a/include/ctl-server.h +++ b/include/ctl-server.h @@ -41,6 +41,8 @@ struct ctl_server_actions { enum output_cycle_direction direction); struct cmd_response* (*on_output_switch)(struct ctl*, const char* output_name); + struct cmd_response* (*on_disconnect_client)(struct ctl*, + const char* id); // Return number of elements created // Allocate 'clients' array or set ton ULL if none diff --git a/src/ctl-server.c b/src/ctl-server.c index 8ca9ffa..6d073ee 100644 --- a/src/ctl-server.c +++ b/src/ctl-server.c @@ -48,6 +48,7 @@ enum cmd_type { CMD_SET_OUTPUT, CMD_GET_CLIENTS, CMD_GET_OUTPUTS, + CMD_DISCONNECT_CLIENT, CMD_UNKNOWN, }; #define CMD_LIST_LEN CMD_UNKNOWN @@ -104,6 +105,13 @@ static struct cmd_info cmd_list[] = { "Return a list of all currently detected Wayland outputs", {{NULL, NULL}} }, + [CMD_DISCONNECT_CLIENT] = { "disconnect-client", + "Disconnect a VNC session", + { + {"id", "The ID of the client to disconnect"}, + {NULL, NULL}, + } + }, }; #define CLIENT_EVENT_PARAMS(including) \ @@ -140,6 +148,11 @@ struct cmd_set_output { enum output_cycle_direction cycle; }; +struct cmd_disconnect_client { + struct cmd cmd; + char id[64]; +}; + struct cmd_response { int code; json_t* data; @@ -257,6 +270,21 @@ static struct cmd_set_output* cmd_set_output_new(json_t* args, return cmd; } +static struct cmd_disconnect_client* cmd_disconnect_client_new(json_t* args, + struct jsonipc_error* err) +{ + const char* id = NULL; + if (json_unpack(args, "{s:s}", + "id", &id) == -1) { + jsonipc_error_printf(err, EINVAL, + "required: \"id\""); + return NULL; + } + struct cmd_disconnect_client* cmd = calloc(1, sizeof(*cmd)); + strlcpy(cmd->id, id, sizeof(cmd->id)); + return cmd; +} + static json_t* list_allowed(struct cmd_info (*list)[], size_t len) { json_t* allowed = json_array(); @@ -289,6 +317,9 @@ static struct cmd* parse_command(struct jsonipc_request* ipc, case CMD_SET_OUTPUT: cmd = (struct cmd*)cmd_set_output_new(ipc->params, err); break; + case CMD_DISCONNECT_CLIENT: + cmd = (struct cmd*)cmd_disconnect_client_new(ipc->params, err); + break; case CMD_VERSION: case CMD_EVENT_RECEIVE: case CMD_GET_CLIENTS: @@ -492,6 +523,12 @@ static struct cmd_response* ctl_server_dispatch_cmd(struct ctl* self, response = self->actions.on_output_cycle(self, c->cycle); break; } + case CMD_DISCONNECT_CLIENT: { + struct cmd_disconnect_client* c = + (struct cmd_disconnect_client*)cmd; + response = self->actions.on_disconnect_client(self, c->id); + break; + } case CMD_VERSION: response = generate_version_object(); break; diff --git a/src/main.c b/src/main.c index bbc1b02..ae86b59 100644 --- a/src/main.c +++ b/src/main.c @@ -517,6 +517,28 @@ static int get_output_list(struct ctl* ctl, return n; } +static struct cmd_response* on_disconnect_client(struct ctl* ctl, + const char* id_string) +{ + int id = atoi(id_string); + if (id <= 0) + return cmd_failed("Invalid client ID \"%s\"", id_string); + + struct wayvnc* self = ctl_server_userdata(ctl); + for (struct nvnc_client* nvnc_client = nvnc_client_first(self->nvnc); + nvnc_client; + nvnc_client = nvnc_client_next(nvnc_client)) { + struct wayvnc_client* client = nvnc_get_userdata(nvnc_client); + if (client->id == id) { + nvnc_log(NVNC_LOG_WARNING, "Disconnecting client %d via control socket command", + client->id); + nvnc_client_close(nvnc_client); + return cmd_ok(); + } + } + return cmd_failed("No such client with ID \"%s\"", id_string); +} + int init_main_loop(struct wayvnc* self) { struct aml* loop = aml_get_default(); @@ -1360,6 +1382,7 @@ int main(int argc, char* argv[]) .on_output_switch = on_output_switch, .get_client_list = get_client_list, .get_output_list = get_output_list, + .on_disconnect_client = on_disconnect_client, }; self.ctl = ctl_server_new(socket_path, &ctl_actions); if (!self.ctl) diff --git a/wayvnc.scd b/wayvnc.scd index 8041a21..9202aba 100644 --- a/wayvnc.scd +++ b/wayvnc.scd @@ -203,6 +203,16 @@ which parameters are supplied: *switch-to=output-name* Switch to a specific output by name. +_DISCONNECT_CLIENT_ + +The *disconnect-client* command disconnects a single VNC client. + +Parameters: + +*id* + Required: The ID of the client to disconnect. This ID can be found from the + _GET-CLIENTS_ command or receipt of a _CLIENT-CONNECTED_ event. + _GET-CLIENTS_ The *get-clients* command retrieves a list of all VNC clients currently