libei/src/libei-proto.c
David Redondo 30d154b0d8 Allow compiling against newer protobuf-c
The internal enumerator name changed.

Signed-off-by: David Redondo <kde@david-redondo.de>
2021-12-01 17:04:39 +01:00

498 lines
13 KiB
C

/*
* Copyright © 2020 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "config.h"
#include <stdbool.h>
#include "util-object.h"
#include "util-io.h"
#include "proto/ei.pb-c.h"
#include "libei-proto.h"
#include "brei-shared.h"
static void servermessage_cleanup(ServerMessage **m) {
if (*m)
server_message__free_unpacked(*m, NULL);
}
#define _cleanup_servermessage_ _cleanup_(servermessage_cleanup)
int
ei_proto_handle_message(struct ei *ei,
const struct ei_proto_interface *interface,
struct brei_message *bmsg)
{
_cleanup_servermessage_ ServerMessage *proto = server_message__unpack(NULL,
bmsg->len,
(const unsigned char*)bmsg->data);
if (!proto)
return -EAGAIN;
#define call(field, ...) \
({ \
int r = (interface->field == NULL) ? -EPROTO : interface->field(__VA_ARGS__); \
log_debug(ei, "message type '" #field "': %d\n", r); \
r; \
})
int rc;
switch (proto->msg_case) {
case SERVER_MESSAGE__MSG_CONNECTED:
rc = call(connected, ei);
break;
case SERVER_MESSAGE__MSG_DISCONNECTED:
rc = call(disconnected, ei);
break;
case SERVER_MESSAGE__MSG_SEAT_ADDED:
rc = call(seat_added, ei,
proto->seat_added->seatid,
proto->seat_added->name, proto->seat_added->capabilities);
break;
case SERVER_MESSAGE__MSG_SEAT_REMOVED:
rc = call(seat_removed, ei,
proto->seat_removed->seatid);
break;
case SERVER_MESSAGE__MSG_DEVICE_ADDED:
rc = call(device_added, ei,
proto->device_added->deviceid,
proto->device_added->seatid,
proto->device_added->name,
proto->device_added->capabilities);
break;
case SERVER_MESSAGE__MSG_DEVICE_DONE:
rc = call(device_done, ei,
proto->device_done->deviceid);
break;
case SERVER_MESSAGE__MSG_DEVICE_KEYMAP:
{
int fd = brei_message_take_fd(bmsg);
rc = call(device_keymap, ei,
proto->device_keymap->deviceid,
proto->device_keymap->keymap_type,
fd,
proto->device_keymap->keymap_size);
xclose(fd);
}
break;
case SERVER_MESSAGE__MSG_DEVICE_REGION:
rc = call(device_region, ei,
proto->device_region->deviceid,
proto->device_region->offset_x,
proto->device_region->offset_y,
proto->device_region->width,
proto->device_region->height,
proto->device_region->scale);
break;
case SERVER_MESSAGE__MSG_KEYBOARD_MODIFIERS:
rc = call(keyboard_modifiers, ei,
proto->keyboard_modifiers->deviceid,
proto->keyboard_modifiers->depressed,
proto->keyboard_modifiers->latched,
proto->keyboard_modifiers->locked,
proto->keyboard_modifiers->group);
break;
case SERVER_MESSAGE__MSG_DEVICE_REMOVED:
rc = call(device_removed, ei,
proto->device_removed->deviceid);
break;
case SERVER_MESSAGE__MSG_DEVICE_RESUMED:
rc = call(device_resumed, ei,
proto->device_resumed->deviceid);
break;
case SERVER_MESSAGE__MSG_DEVICE_PAUSED:
rc = call(device_paused, ei,
proto->device_paused->deviceid);
break;
case SERVER_MESSAGE__MSG_PROPERTY:
rc = call(property, ei,
proto->property->name,
proto->property->value[0] ? proto->property->value : NULL,
proto->property->permissions);
break;
default:
rc = -EBADMSG;
break;
}
return rc < 0 ? rc : (int)bmsg->len;
}
static inline void
log_wire_message(struct ei *ei, const ClientMessage *msg, int error)
{
const char *message = NULL;
#define MSG_STRING_CASE(_name) \
case CLIENT_MESSAGE__MSG_##_name: message = #_name; break;
switch (msg->msg_case) {
#if PROTOBUF_C_VERSION_NUMBER >= 1004000
case _CLIENT_MESSAGE__MSG__CASE_IS_INT_SIZE:
#else
case _CLIENT_MESSAGE__MSG_IS_INT_SIZE:
#endif
/* protobuf-internal thing */
return;
case CLIENT_MESSAGE__MSG__NOT_SET:
abort();
MSG_STRING_CASE(CONNECT);
MSG_STRING_CASE(CONNECT_DONE);
MSG_STRING_CASE(DISCONNECT);
MSG_STRING_CASE(BIND_SEAT);
MSG_STRING_CASE(UNBIND_SEAT);
MSG_STRING_CASE(CLOSE_DEVICE);
MSG_STRING_CASE(START_EMULATING);
MSG_STRING_CASE(STOP_EMULATING);
MSG_STRING_CASE(POINTER_RELATIVE);
MSG_STRING_CASE(POINTER_ABSOLUTE);
MSG_STRING_CASE(POINTER_BUTTON);
MSG_STRING_CASE(POINTER_SCROLL);
MSG_STRING_CASE(POINTER_SCROLL_STOP);
MSG_STRING_CASE(POINTER_SCROLL_DISCRETE);
MSG_STRING_CASE(KEYBOARD_KEY);
MSG_STRING_CASE(TOUCH_DOWN);
MSG_STRING_CASE(TOUCH_MOTION);
MSG_STRING_CASE(TOUCH_UP);
MSG_STRING_CASE(CONFIGURE_NAME);
MSG_STRING_CASE(CONFIGURE_CAPABILITIES);
MSG_STRING_CASE(FRAME);
MSG_STRING_CASE(PROPERTY);
}
if (message == NULL)
assert(!"Unimplemented message type");
log_debug(ei, "sending wire message %s (%s)\n", message,
strerror(-error));
#undef MSG_STRING_CASE
}
static int
ei_proto_send_msg(struct ei *ei, const ClientMessage *msg)
{
size_t msglen = client_message__get_packed_size(msg);
Packet packet = PACKET__INIT;
packet.length = msglen;
size_t packetlen = packet__get_packed_size(&packet);
uint8_t buf[packetlen + msglen];
packet__pack(&packet, buf);
client_message__pack(msg, buf + packetlen);
int rc = min(0, xsend(source_get_fd(ei->source), buf, sizeof(buf)));
log_wire_message(ei, msg, rc);
return rc;
}
_unused_ static int
ei_proto_send_msg_with_fds(struct ei *ei, const ClientMessage *msg, int *fds)
{
size_t msglen = client_message__get_packed_size(msg);
Packet packet = PACKET__INIT;
packet.length = msglen;
size_t packetlen = packet__get_packed_size(&packet);
uint8_t buf[packetlen + msglen];
packet__pack(&packet, buf);
client_message__pack(msg, buf + packetlen);
int rc = min(0, xsend_with_fd(source_get_fd(ei->source), buf, sizeof(buf), fds));
log_wire_message(ei, msg, rc);
return rc;
}
#define prepare_msg(_type, _struct, _field) \
ClientMessage msg = CLIENT_MESSAGE__INIT; \
_struct _field = _type##__INIT; \
msg.msg_case = CLIENT_MESSAGE__MSG_##_type; \
msg._field = &_field
static int
ei_proto_send_connect(struct ei *ei)
{
prepare_msg(CONNECT, Connect, connect);
connect.name = ei->name;
return ei_proto_send_msg(ei, &msg);
}
static int
ei_proto_send_connect_done(struct ei *ei)
{
prepare_msg(CONNECT_DONE, ConnectDone, connect_done);
return ei_proto_send_msg(ei, &msg);
}
static int
ei_proto_send_disconnect(struct ei *ei)
{
prepare_msg(DISCONNECT, Disconnect, disconnect);
return ei_proto_send_msg(ei, &msg);
}
static int
ei_proto_send_bind_seat(struct ei_seat *seat, uint32_t capabilities)
{
prepare_msg(BIND_SEAT, BindSeat, bind_seat);
bind_seat.seatid = seat->id;
bind_seat.capabilities = capabilities;
return ei_proto_send_msg(ei_seat_get_context(seat), &msg);
}
static int
ei_proto_send_unbind_seat(struct ei_seat *seat)
{
prepare_msg(UNBIND_SEAT, UnbindSeat, unbind_seat);
unbind_seat.seatid = seat->id;
return ei_proto_send_msg(ei_seat_get_context(seat), &msg);
}
static int
ei_proto_send_close_device(struct ei_device *device)
{
prepare_msg(CLOSE_DEVICE, CloseDevice, close_device);
close_device.deviceid = device->id;
return ei_proto_send_msg(ei_device_get_context(device), &msg);
}
static int
ei_proto_send_start_emulating(struct ei_device *device)
{
prepare_msg(START_EMULATING, StartEmulating, start_emulating);
start_emulating.deviceid = device->id;
return ei_proto_send_msg(ei_device_get_context(device), &msg);
}
static int
ei_proto_send_stop_emulating(struct ei_device *device)
{
prepare_msg(STOP_EMULATING, StopEmulating, stop_emulating);
stop_emulating.deviceid = device->id;
return ei_proto_send_msg(ei_device_get_context(device), &msg);
}
static int
ei_proto_send_rel(struct ei_device *device, double x, double y)
{
prepare_msg(POINTER_RELATIVE, PointerRelative, pointer_relative);
pointer_relative.deviceid = device->id;
pointer_relative.x = x;
pointer_relative.y = y;
return ei_proto_send_msg(ei_device_get_context(device), &msg);
}
static int
ei_proto_send_abs(struct ei_device *device, double x, double y)
{
prepare_msg(POINTER_ABSOLUTE, PointerAbsolute, pointer_absolute);
pointer_absolute.deviceid = device->id;
pointer_absolute.x = x;
pointer_absolute.y = y;
return ei_proto_send_msg(ei_device_get_context(device), &msg);
}
static int
ei_proto_send_button(struct ei_device *device, uint32_t b, bool is_press)
{
prepare_msg(POINTER_BUTTON, PointerButton, pointer_button);
pointer_button.deviceid = device->id;
pointer_button.button = b;
pointer_button.state = is_press;
return ei_proto_send_msg(ei_device_get_context(device), &msg);
}
static int
ei_proto_send_scroll(struct ei_device *device, double x, double y)
{
prepare_msg(POINTER_SCROLL, PointerScroll, pointer_scroll);
pointer_scroll.deviceid = device->id;
pointer_scroll.x = x;
pointer_scroll.y = y;
return ei_proto_send_msg(ei_device_get_context(device), &msg);
}
static int
ei_proto_send_scroll_stop(struct ei_device *device, bool x, bool y)
{
prepare_msg(POINTER_SCROLL_STOP, PointerScrollStop, pointer_scroll_stop);
pointer_scroll_stop.deviceid = device->id;
pointer_scroll_stop.x = x;
pointer_scroll_stop.y = y;
pointer_scroll_stop.is_cancel = false;
return ei_proto_send_msg(ei_device_get_context(device), &msg);
}
static int
ei_proto_send_scroll_cancel(struct ei_device *device, bool x, bool y)
{
prepare_msg(POINTER_SCROLL_STOP, PointerScrollStop, pointer_scroll_stop);
pointer_scroll_stop.deviceid = device->id;
pointer_scroll_stop.x = x;
pointer_scroll_stop.y = y;
pointer_scroll_stop.is_cancel = true;
return ei_proto_send_msg(ei_device_get_context(device), &msg);
}
static int
ei_proto_send_scroll_discrete(struct ei_device *device, int32_t x, int32_t y)
{
prepare_msg(POINTER_SCROLL_DISCRETE, PointerScrollDiscrete, pointer_scroll_discrete);
pointer_scroll_discrete.deviceid = device->id;
pointer_scroll_discrete.x = x;
pointer_scroll_discrete.y = y;
return ei_proto_send_msg(ei_device_get_context(device), &msg);
}
static int
ei_proto_send_key(struct ei_device *device, uint32_t k, bool is_press)
{
prepare_msg(KEYBOARD_KEY, KeyboardKey, keyboard_key);
keyboard_key.deviceid = device->id;
keyboard_key.key = k;
keyboard_key.state = is_press;
return ei_proto_send_msg(ei_device_get_context(device), &msg);
}
static int
ei_proto_send_touch_down(struct ei_device *device, uint32_t tid, double x, double y)
{
prepare_msg(TOUCH_DOWN, TouchDown, touch_down);
touch_down.deviceid = device->id;
touch_down.touchid = tid;
touch_down.x = x;
touch_down.y = y;
return ei_proto_send_msg(ei_device_get_context(device), &msg);
}
static int
ei_proto_send_touch_motion(struct ei_device *device, uint32_t tid, double x, double y)
{
prepare_msg(TOUCH_MOTION, TouchMotion, touch_motion);
touch_motion.deviceid = device->id;
touch_motion.touchid = tid;
touch_motion.x = x;
touch_motion.y = y;
return ei_proto_send_msg(ei_device_get_context(device), &msg);
}
static int
ei_proto_send_touch_up(struct ei_device *device, uint32_t tid)
{
prepare_msg(TOUCH_UP, TouchUp, touch_up);
touch_up.deviceid = device->id;
touch_up.touchid = tid;
return ei_proto_send_msg(ei_device_get_context(device), &msg);
}
static int
ei_proto_send_frame(struct ei_device *device)
{
prepare_msg(FRAME, Frame, frame);
frame.deviceid = device->id;
return ei_proto_send_msg(ei_device_get_context(device), &msg);
}
static int
ei_proto_send_property(struct ei *ei, const char *name, const char *value, uint32_t permissions)
{
prepare_msg(PROPERTY, Property, property);
property.name = (char*)name;
property.value = value ? (char*)value : "";
property.permissions = permissions;
return ei_proto_send_msg(ei, &msg);
}
static const struct ei_proto_requests requests = {
.connect = ei_proto_send_connect,
.connect_done = ei_proto_send_connect_done,
.disconnect = ei_proto_send_disconnect,
.bind_seat = ei_proto_send_bind_seat,
.unbind_seat = ei_proto_send_unbind_seat,
.close_device = ei_proto_send_close_device,
.start_emulating = ei_proto_send_start_emulating,
.stop_emulating = ei_proto_send_stop_emulating,
.rel = ei_proto_send_rel,
.abs = ei_proto_send_abs,
.button = ei_proto_send_button,
.scroll = ei_proto_send_scroll,
.scroll_stop = ei_proto_send_scroll_stop,
.scroll_cancel = ei_proto_send_scroll_cancel,
.scroll_discrete = ei_proto_send_scroll_discrete,
.key = ei_proto_send_key,
.touch_down = ei_proto_send_touch_down,
.touch_motion = ei_proto_send_touch_motion,
.touch_up = ei_proto_send_touch_up,
.frame = ei_proto_send_frame,
.property = ei_proto_send_property,
};
const struct ei_proto_requests *
ei_proto_get_requests(void)
{
return &requests;
}