aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/protocol.h2
-rw-r--r--libseat/backend/seatd.c45
-rw-r--r--seatd/client.c22
3 files changed, 65 insertions, 4 deletions
diff --git a/include/protocol.h b/include/protocol.h
index b3361ba..cb994fc 100644
--- a/include/protocol.h
+++ b/include/protocol.h
@@ -15,6 +15,7 @@
#define CLIENT_CLOSE_DEVICE CLIENT_EVENT(4)
#define CLIENT_DISABLE_SEAT CLIENT_EVENT(5)
#define CLIENT_SWITCH_SESSION CLIENT_EVENT(6)
+#define CLIENT_PING CLIENT_EVENT(7)
#define SERVER_SEAT_OPENED SERVER_EVENT(1)
#define SERVER_SEAT_CLOSED SERVER_EVENT(2)
@@ -22,6 +23,7 @@
#define SERVER_DEVICE_CLOSED SERVER_EVENT(4)
#define SERVER_DISABLE_SEAT SERVER_EVENT(5)
#define SERVER_ENABLE_SEAT SERVER_EVENT(6)
+#define SERVER_PONG SERVER_EVENT(7)
#define SERVER_ERROR SERVER_EVENT(0x7FFF)
#include <stdint.h>
diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c
index 85df9f5..26308d1 100644
--- a/libseat/backend/seatd.c
+++ b/libseat/backend/seatd.c
@@ -36,6 +36,7 @@ struct backend_seatd {
const struct libseat_seat_listener *seat_listener;
void *seat_listener_data;
struct linked_list pending_events;
+ bool awaiting_pong;
bool error;
char seat_name[MAX_SEAT_LEN];
@@ -243,6 +244,12 @@ static int dispatch_pending(struct backend_seatd *backend, int *opcode) {
while (connection_get(&backend->connection, &header, sizeof header) != -1) {
packets++;
switch (header.opcode) {
+ case SERVER_PONG:
+ // We care about whether or not the answer has been
+ // read from the connection, so handle it here instead
+ // of pushing it to the pending event list.
+ backend->awaiting_pong = false;
+ break;
case SERVER_DISABLE_SEAT:
case SERVER_ENABLE_SEAT:
if (queue_event(backend, header.opcode) == -1) {
@@ -450,6 +457,36 @@ static const char *seat_name(struct libseat *base) {
return backend->seat_name;
}
+static int send_ping(struct backend_seatd *backend) {
+ struct proto_header header = {
+ .opcode = CLIENT_PING,
+ .size = 0,
+ };
+ if (conn_put(backend, &header, sizeof header) == -1 || conn_flush(backend) == -1) {
+ return -1;
+ }
+ return 0;
+}
+
+static void check_pending_events(struct backend_seatd *backend) {
+ if (linked_list_empty(&backend->pending_events)) {
+ return;
+ }
+ if (backend->awaiting_pong) {
+ return;
+ }
+
+ // We have events pending execution, so a dispatch is required.
+ // However, we likely already drained our socket, so there will not be
+ // anything to read. Instead, send a ping request to seatd, so that the
+ // user will be woken up by its response.
+ if (send_ping(backend) == -1) {
+ log_errorf("Could not send ping request: %s", strerror(errno));
+ return;
+ }
+ backend->awaiting_pong = true;
+}
+
static int open_device(struct libseat *base, const char *path, int *fd) {
struct backend_seatd *backend = backend_seatd_from_libseat_backend(base);
if (backend->error) {
@@ -481,11 +518,11 @@ static int open_device(struct libseat *base, const char *path, int *fd) {
goto error;
}
- execute_events(backend);
+ check_pending_events(backend);
return rmsg.device_id;
error:
- execute_events(backend);
+ check_pending_events(backend);
return -1;
}
@@ -516,11 +553,11 @@ static int close_device(struct libseat *base, int device_id) {
goto error;
}
- execute_events(backend);
+ check_pending_events(backend);
return 0;
error:
- execute_events(backend);
+ check_pending_events(backend);
return -1;
}
diff --git a/seatd/client.c b/seatd/client.c
index 1bfe94a..220c5d3 100644
--- a/seatd/client.c
+++ b/seatd/client.c
@@ -309,6 +309,20 @@ error:
return client_send_error(client, errno);
}
+static int handle_ping(struct client *client) {
+ struct proto_header header = {
+ .opcode = SERVER_PONG,
+ .size = 0,
+ };
+
+ if (connection_put(&client->connection, &header, sizeof header) == -1) {
+ log_errorf("Could not write response: %s", strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
static int client_handle_opcode(struct client *client, uint16_t opcode, size_t size) {
int res = 0;
switch (opcode) {
@@ -372,6 +386,14 @@ static int client_handle_opcode(struct client *client, uint16_t opcode, size_t s
res = handle_disable_seat(client);
break;
}
+ case CLIENT_PING: {
+ if (size != 0) {
+ log_error("Protocol error: invalid ping message");
+ return -1;
+ }
+ res = handle_ping(client);
+ break;
+ }
default:
log_errorf("Protocol error: unknown opcode: %d", opcode);
res = -1;