mirror of
https://gitlab.freedesktop.org/libinput/libei.git
synced 2026-02-15 06:50:38 +01:00
libei: move the protocol parsing into a separate file
The goal here is to separate any state checking and other processing from the actual bits writing onto the wire so we can test those separately. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
parent
2b9d5d960a
commit
6de95310e1
4 changed files with 451 additions and 290 deletions
|
|
@ -39,6 +39,8 @@ src_libei = [
|
|||
'src/libei-device.c',
|
||||
'src/libei-socket.c',
|
||||
'src/libei-fd.c',
|
||||
'src/libei-proto.h',
|
||||
'src/libei-proto.c',
|
||||
proto_headers,
|
||||
]
|
||||
|
||||
|
|
|
|||
349
src/libei-proto.c
Normal file
349
src/libei-proto.c
Normal file
|
|
@ -0,0 +1,349 @@
|
|||
/*
|
||||
* 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 "util-logger.h"
|
||||
|
||||
#include "proto/ei.pb-c.h"
|
||||
#include "libei-proto.h"
|
||||
|
||||
void
|
||||
message_free(struct message *msg)
|
||||
{
|
||||
switch (msg->type) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
free(msg);
|
||||
}
|
||||
|
||||
static void frame_cleanup(Frame **f) {
|
||||
if (*f)
|
||||
frame__free_unpacked(*f, NULL);
|
||||
}
|
||||
|
||||
static void servermessage_cleanup(ServerMessage **m) {
|
||||
if (*m)
|
||||
server_message__free_unpacked(*m, NULL);
|
||||
}
|
||||
#define _cleanup_frame_ _cleanup_(frame_cleanup)
|
||||
#define _cleanup_servermessage_ _cleanup_(servermessage_cleanup)
|
||||
|
||||
static const unsigned char *
|
||||
next_message(const char *data, size_t *msglen, size_t *consumed)
|
||||
{
|
||||
/* Every message is prefixed by a fixed-length Frame message which
|
||||
* contains the length of the next message. Frames are always the
|
||||
* same length, so we only need to calculate the size once.
|
||||
*/
|
||||
static size_t framelen = 0;
|
||||
|
||||
if (framelen == 0) {
|
||||
Frame f = FRAME__INIT;
|
||||
f.length = 0xffff;
|
||||
framelen = frame__get_packed_size(&f);
|
||||
assert(framelen >= 5);
|
||||
}
|
||||
|
||||
_cleanup_frame_ Frame *frame = frame__unpack(NULL, framelen, (const unsigned char *)data);
|
||||
if (!frame)
|
||||
return NULL;
|
||||
|
||||
*msglen = frame->length;
|
||||
*consumed = framelen;
|
||||
|
||||
return (const unsigned char*)data + framelen;
|
||||
}
|
||||
|
||||
struct message *
|
||||
ei_proto_parse_message(const char *data, size_t len, size_t *consumed)
|
||||
{
|
||||
size_t headerbytes = 0;
|
||||
size_t msglen = 0;
|
||||
const unsigned char *msgdata = next_message(data, &msglen, &headerbytes);
|
||||
|
||||
_cleanup_servermessage_ ServerMessage *proto = server_message__unpack(NULL, msglen, msgdata);
|
||||
if (!proto)
|
||||
return NULL;
|
||||
|
||||
*consumed = headerbytes + msglen;
|
||||
|
||||
_cleanup_message_ struct message *msg = xalloc(sizeof(*msg));
|
||||
|
||||
bool success = true;
|
||||
switch (proto->msg_case) {
|
||||
case SERVER_MESSAGE__MSG_CONNECTED:
|
||||
*msg = (struct message) {
|
||||
.type = MESSAGE_CONNECTED,
|
||||
};
|
||||
break;
|
||||
case SERVER_MESSAGE__MSG_DISCONNECTED:
|
||||
*msg = (struct message) {
|
||||
.type = MESSAGE_DISCONNECTED,
|
||||
};
|
||||
break;
|
||||
case SERVER_MESSAGE__MSG_DEVICE_ADDED:
|
||||
{
|
||||
DeviceAdded *a = proto->device_added;
|
||||
*msg = (struct message) {
|
||||
.type = MESSAGE_DEVICE_ADDED,
|
||||
.added.deviceid = a->deviceid,
|
||||
.added.capabilities = a->capabilities,
|
||||
};
|
||||
}
|
||||
break;
|
||||
case SERVER_MESSAGE__MSG_DEVICE_REMOVED:
|
||||
{
|
||||
DeviceRemoved *r = proto->device_removed;
|
||||
*msg = (struct message) {
|
||||
.type = MESSAGE_DEVICE_REMOVED,
|
||||
.removed.deviceid = r->deviceid,
|
||||
};
|
||||
}
|
||||
break;
|
||||
default:
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
|
||||
return success ? steal(&msg) : NULL;
|
||||
}
|
||||
|
||||
static inline void
|
||||
log_wire_message(struct ei *ei, const ClientMessage *msg)
|
||||
{
|
||||
const char *message = NULL;
|
||||
|
||||
#define MSG_STRING_CASE(_name) \
|
||||
case CLIENT_MESSAGE__MSG_##_name: message = #_name; break;
|
||||
|
||||
switch (msg->msg_case) {
|
||||
case CLIENT_MESSAGE__MSG__NOT_SET:
|
||||
abort();
|
||||
MSG_STRING_CASE(CONNECT);
|
||||
MSG_STRING_CASE(DISCONNECT);
|
||||
MSG_STRING_CASE(ADD_DEVICE);
|
||||
MSG_STRING_CASE(REMOVE_DEVICE);
|
||||
MSG_STRING_CASE(REL);
|
||||
MSG_STRING_CASE(BUTTON);
|
||||
MSG_STRING_CASE(KEY);
|
||||
MSG_STRING_CASE(CONFIGURE_NAME);
|
||||
MSG_STRING_CASE(CONFIGURE_CAPS);
|
||||
default:
|
||||
assert(!"Unimplemented message type");
|
||||
break;
|
||||
}
|
||||
log_debug(ei, "sending wire message %s\n", message);
|
||||
|
||||
#undef MSG_STRING_CASE
|
||||
}
|
||||
|
||||
static int
|
||||
ei_proto_send_msg(struct ei *ei, const ClientMessage *msg)
|
||||
{
|
||||
log_wire_message(ei, msg);
|
||||
|
||||
size_t msglen = client_message__get_packed_size(msg);
|
||||
Frame frame = FRAME__INIT;
|
||||
frame.length = msglen;
|
||||
size_t framelen = frame__get_packed_size(&frame);
|
||||
|
||||
uint8_t buf[framelen + msglen];
|
||||
frame__pack(&frame, buf);
|
||||
client_message__pack(msg, buf + framelen);
|
||||
return min(0, xsend(source_get_fd(ei->source), buf, sizeof(buf)));
|
||||
}
|
||||
|
||||
int
|
||||
ei_proto_send_connect(struct ei *ei)
|
||||
{
|
||||
ClientMessage msg = CLIENT_MESSAGE__INIT;
|
||||
Connect connect = CONNECT__INIT;
|
||||
connect.name = ei->name;
|
||||
|
||||
msg.connect = &connect;
|
||||
msg.msg_case = CLIENT_MESSAGE__MSG_CONNECT;
|
||||
|
||||
return ei_proto_send_msg(ei, &msg);
|
||||
}
|
||||
|
||||
int
|
||||
ei_proto_send_disconnect(struct ei *ei)
|
||||
{
|
||||
ClientMessage msg = CLIENT_MESSAGE__INIT;
|
||||
Disconnect disconnect = DISCONNECT__INIT;
|
||||
|
||||
msg.disconnect = &disconnect;
|
||||
msg.msg_case = CLIENT_MESSAGE__MSG_DISCONNECT;
|
||||
|
||||
return ei_proto_send_msg(ei, &msg);
|
||||
}
|
||||
|
||||
int
|
||||
ei_proto_send_add(struct ei *ei, struct ei_device *device)
|
||||
{
|
||||
ClientMessage msg = CLIENT_MESSAGE__INIT;
|
||||
AddDevice add = ADD_DEVICE__INIT;
|
||||
|
||||
add.deviceid = device->id;
|
||||
add.capabilities = device->capabilities;
|
||||
add.pointer_width = device->abs.dim.width;
|
||||
add.pointer_height = device->abs.dim.height;
|
||||
add.touch_width = device->touch.dim.width;
|
||||
add.touch_height = device->touch.dim.height;
|
||||
|
||||
msg.add_device = &add;
|
||||
msg.msg_case = CLIENT_MESSAGE__MSG_ADD_DEVICE;
|
||||
|
||||
return ei_proto_send_msg(ei, &msg);
|
||||
}
|
||||
|
||||
int
|
||||
ei_proto_send_remove(struct ei *ei, struct ei_device *device)
|
||||
{
|
||||
ClientMessage msg = CLIENT_MESSAGE__INIT;
|
||||
RemoveDevice remove = REMOVE_DEVICE__INIT;
|
||||
|
||||
remove.deviceid = device->id;
|
||||
|
||||
msg.remove_device = &remove;
|
||||
msg.msg_case = CLIENT_MESSAGE__MSG_REMOVE_DEVICE;
|
||||
|
||||
return ei_proto_send_msg(ei, &msg);
|
||||
}
|
||||
|
||||
int
|
||||
ei_proto_send_rel(struct ei *ei, struct ei_device *device,
|
||||
double x, double y)
|
||||
{
|
||||
ClientMessage msg = CLIENT_MESSAGE__INIT;
|
||||
PointerRelative rel = POINTER_RELATIVE__INIT;
|
||||
|
||||
rel.deviceid = device->id;
|
||||
rel.x = x;
|
||||
rel.y = y;
|
||||
|
||||
msg.rel = &rel;
|
||||
msg.msg_case = CLIENT_MESSAGE__MSG_REL;
|
||||
|
||||
return ei_proto_send_msg(ei, &msg);
|
||||
}
|
||||
|
||||
int
|
||||
ei_proto_send_button(struct ei *ei, struct ei_device *device,
|
||||
uint32_t b, bool is_press)
|
||||
{
|
||||
ClientMessage msg = CLIENT_MESSAGE__INIT;
|
||||
PointerButton button = POINTER_BUTTON__INIT;
|
||||
|
||||
button.deviceid = device->id;
|
||||
button.button = b;
|
||||
button.state = is_press;
|
||||
|
||||
msg.button = &button;
|
||||
msg.msg_case = CLIENT_MESSAGE__MSG_BUTTON;
|
||||
|
||||
return ei_proto_send_msg(ei, &msg);
|
||||
}
|
||||
|
||||
int
|
||||
ei_proto_send_key(struct ei *ei, struct ei_device *device,
|
||||
uint32_t k, bool is_press)
|
||||
{
|
||||
ClientMessage msg = CLIENT_MESSAGE__INIT;
|
||||
KeyboardKey key = KEYBOARD_KEY__INIT;
|
||||
|
||||
key.deviceid = device->id;
|
||||
key.key = k;
|
||||
key.state = is_press;
|
||||
|
||||
msg.key = &key;
|
||||
msg.msg_case = CLIENT_MESSAGE__MSG_KEY;
|
||||
|
||||
return ei_proto_send_msg(ei, &msg);
|
||||
}
|
||||
|
||||
|
||||
#ifdef _enable_tests_
|
||||
#include <munit.h>
|
||||
|
||||
static MunitResult
|
||||
test_proto_next_message(const MunitParameter params[], void *user_data)
|
||||
{
|
||||
char data[64];
|
||||
|
||||
/* Invalid frame, rest can be random */
|
||||
data[0] = 0xaa;
|
||||
|
||||
size_t msglen = 0xab;
|
||||
size_t consumed = 0xbc;
|
||||
|
||||
const unsigned char *rval = next_message(data, &msglen, &consumed);
|
||||
munit_assert_ptr_null(rval);
|
||||
munit_assert_int(msglen, ==, 0xab);
|
||||
munit_assert_int(consumed, ==, 0xbc);
|
||||
|
||||
/* Now try a valid one */
|
||||
Frame f = FRAME__INIT;
|
||||
f.length = 0xcd;
|
||||
size_t framelen = frame__get_packed_size(&f);
|
||||
|
||||
unsigned char buf[framelen * 4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
frame__pack(&f, buf + framelen * i);
|
||||
|
||||
const char *ptr = (char*)buf;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
const unsigned char *next_frame = next_message(ptr, &msglen, &consumed);
|
||||
munit_assert_ptr_equal(next_frame, buf + (i + 1) * framelen);
|
||||
munit_assert_int(consumed, ==, framelen);
|
||||
munit_assert_int(msglen, ==, 0xcd);
|
||||
ptr += consumed;
|
||||
}
|
||||
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
#define TEST(_func) \
|
||||
{ .name = #_func, .test = _func }
|
||||
|
||||
static MunitTest ei_tests[] = {
|
||||
TEST(test_proto_next_message),
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
static const MunitSuite libei_suite
|
||||
__attribute__((used))
|
||||
__attribute__((section("test_section"))) = {
|
||||
"",
|
||||
ei_tests,
|
||||
NULL,
|
||||
1,
|
||||
MUNIT_SUITE_OPTION_NONE,
|
||||
};
|
||||
#endif
|
||||
90
src/libei-proto.h
Normal file
90
src/libei-proto.h
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "util-macros.h"
|
||||
#include "util-mem.h"
|
||||
|
||||
#include "libei-private.h"
|
||||
|
||||
/* The message type for the wire format */
|
||||
enum message_type {
|
||||
MESSAGE_CONNECTED = 1,
|
||||
MESSAGE_DISCONNECTED,
|
||||
MESSAGE_DEVICE_ADDED,
|
||||
MESSAGE_DEVICE_REMOVED,
|
||||
};
|
||||
|
||||
struct message {
|
||||
enum message_type type;
|
||||
union {
|
||||
struct message_connected {
|
||||
uint8_t pad; /* no data */
|
||||
} connected;
|
||||
struct message_disconnected {
|
||||
uint8_t pad; /* no data */
|
||||
} disconnected;
|
||||
struct message_device_added {
|
||||
uint32_t deviceid;
|
||||
uint32_t capabilities;
|
||||
} added;
|
||||
struct message_device_removed {
|
||||
uint32_t deviceid;
|
||||
} removed;
|
||||
};
|
||||
};
|
||||
|
||||
void message_free(struct message *msg);
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(struct message*, message_free);
|
||||
#define _cleanup_message_ _cleanup_(message_freep)
|
||||
|
||||
struct message *
|
||||
ei_proto_parse_message(const char *data, size_t len, size_t *consumed);
|
||||
|
||||
int
|
||||
ei_proto_send_connect(struct ei *ei);
|
||||
|
||||
int
|
||||
ei_proto_send_disconnect(struct ei *ei);
|
||||
|
||||
int
|
||||
ei_proto_send_add(struct ei *ei, struct ei_device *device);
|
||||
|
||||
int
|
||||
ei_proto_send_remove(struct ei *ei, struct ei_device *device);
|
||||
|
||||
int
|
||||
ei_proto_send_rel(struct ei *ei, struct ei_device *device,
|
||||
double x, double y);
|
||||
|
||||
int
|
||||
ei_proto_send_button(struct ei *ei, struct ei_device *device,
|
||||
uint32_t b, bool is_press);
|
||||
|
||||
int
|
||||
ei_proto_send_key(struct ei *ei, struct ei_device *device,
|
||||
uint32_t k, bool is_press);
|
||||
300
src/libei.c
300
src/libei.c
|
|
@ -37,48 +37,7 @@
|
|||
|
||||
#include "libei.h"
|
||||
#include "libei-private.h"
|
||||
|
||||
#include "proto/ei.pb-c.h"
|
||||
|
||||
/* The message type for the wire format */
|
||||
enum message_type {
|
||||
MESSAGE_CONNECTED = 1,
|
||||
MESSAGE_DISCONNECTED,
|
||||
MESSAGE_DEVICE_ADDED,
|
||||
MESSAGE_DEVICE_REMOVED,
|
||||
};
|
||||
|
||||
struct message {
|
||||
enum message_type type;
|
||||
union {
|
||||
struct message_connected {
|
||||
uint8_t pad; /* no data */
|
||||
} connected;
|
||||
struct message_disconnected {
|
||||
uint8_t pad; /* no data */
|
||||
} disconnected;
|
||||
struct MESSAGE_DEVICE_ADDED {
|
||||
uint32_t deviceid;
|
||||
uint32_t capabilities;
|
||||
} added;
|
||||
struct MESSAGE_DEVICE_REMOVED {
|
||||
uint32_t deviceid;
|
||||
} removed;
|
||||
};
|
||||
};
|
||||
|
||||
static void
|
||||
message_free(struct message *msg)
|
||||
{
|
||||
switch (msg->type) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
free(msg);
|
||||
}
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(struct message*, message_free);
|
||||
#define _cleanup_message_ _cleanup_(message_freep)
|
||||
#include "libei-proto.h"
|
||||
|
||||
static void
|
||||
ei_event_destroy(struct ei_event *event)
|
||||
|
|
@ -219,52 +178,6 @@ ei_queue_removed_event(struct ei_device *device)
|
|||
ei_queue_event(ei, e);
|
||||
}
|
||||
|
||||
static inline void
|
||||
log_wire_message(struct ei *ei, const ClientMessage *msg)
|
||||
{
|
||||
const char *message = NULL;
|
||||
|
||||
#define MSG_STRING_CASE(_name) \
|
||||
case CLIENT_MESSAGE__MSG_##_name: message = #_name; break;
|
||||
|
||||
switch (msg->msg_case) {
|
||||
case CLIENT_MESSAGE__MSG__NOT_SET:
|
||||
abort();
|
||||
MSG_STRING_CASE(CONNECT);
|
||||
MSG_STRING_CASE(DISCONNECT);
|
||||
MSG_STRING_CASE(ADD_DEVICE);
|
||||
MSG_STRING_CASE(REMOVE_DEVICE);
|
||||
MSG_STRING_CASE(REL);
|
||||
MSG_STRING_CASE(BUTTON);
|
||||
MSG_STRING_CASE(KEY);
|
||||
MSG_STRING_CASE(CONFIGURE_NAME);
|
||||
MSG_STRING_CASE(CONFIGURE_CAPS);
|
||||
default:
|
||||
assert(!"Unimplemented message type");
|
||||
break;
|
||||
}
|
||||
log_debug(ei, "sending wire message %s\n", message);
|
||||
|
||||
#undef MSG_STRING_CASE
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
connection_send_msg(struct ei *ei, const ClientMessage *msg)
|
||||
{
|
||||
log_wire_message(ei, msg);
|
||||
|
||||
size_t msglen = client_message__get_packed_size(msg);
|
||||
Frame frame = FRAME__INIT;
|
||||
frame.length = msglen;
|
||||
size_t framelen = frame__get_packed_size(&frame);
|
||||
|
||||
uint8_t buf[framelen + msglen];
|
||||
frame__pack(&frame, buf);
|
||||
client_message__pack(msg, buf + framelen);
|
||||
return min(0, xsend(source_get_fd(ei->source), buf, sizeof(buf)));
|
||||
}
|
||||
|
||||
static int
|
||||
connection_send_connect(struct ei *ei)
|
||||
{
|
||||
|
|
@ -272,14 +185,7 @@ connection_send_connect(struct ei *ei)
|
|||
ei->state == EI_STATE_DISCONNECTED)
|
||||
return 0;
|
||||
|
||||
ClientMessage msg = CLIENT_MESSAGE__INIT;
|
||||
Connect connect = CONNECT__INIT;
|
||||
connect.name = ei->name;
|
||||
|
||||
msg.connect = &connect;
|
||||
msg.msg_case = CLIENT_MESSAGE__MSG_CONNECT;
|
||||
|
||||
return connection_send_msg(ei, &msg);
|
||||
return ei_proto_send_connect(ei);
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -289,13 +195,7 @@ connection_send_disconnect(struct ei *ei)
|
|||
ei->state == EI_STATE_DISCONNECTED)
|
||||
return 0;
|
||||
|
||||
ClientMessage msg = CLIENT_MESSAGE__INIT;
|
||||
Disconnect disconnect = DISCONNECT__INIT;
|
||||
|
||||
msg.disconnect = &disconnect;
|
||||
msg.msg_case = CLIENT_MESSAGE__MSG_DISCONNECT;
|
||||
|
||||
return connection_send_msg(ei, &msg);
|
||||
return ei_proto_send_disconnect(ei);
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -305,20 +205,7 @@ connection_send_add(struct ei *ei, struct ei_device *device)
|
|||
ei->state == EI_STATE_DISCONNECTED)
|
||||
return 0;
|
||||
|
||||
ClientMessage msg = CLIENT_MESSAGE__INIT;
|
||||
AddDevice add = ADD_DEVICE__INIT;
|
||||
|
||||
add.deviceid = device->id;
|
||||
add.capabilities = device->capabilities;
|
||||
add.pointer_width = device->abs.dim.width;
|
||||
add.pointer_height = device->abs.dim.height;
|
||||
add.touch_width = device->touch.dim.width;
|
||||
add.touch_height = device->touch.dim.height;
|
||||
|
||||
msg.add_device = &add;
|
||||
msg.msg_case = CLIENT_MESSAGE__MSG_ADD_DEVICE;
|
||||
|
||||
return connection_send_msg(ei, &msg);
|
||||
return ei_proto_send_add(ei, device);
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -328,15 +215,7 @@ connection_send_remove(struct ei *ei, struct ei_device *device)
|
|||
ei->state == EI_STATE_DISCONNECTED)
|
||||
return 0;
|
||||
|
||||
ClientMessage msg = CLIENT_MESSAGE__INIT;
|
||||
RemoveDevice remove = REMOVE_DEVICE__INIT;
|
||||
|
||||
remove.deviceid = device->id;
|
||||
|
||||
msg.remove_device = &remove;
|
||||
msg.msg_case = CLIENT_MESSAGE__MSG_REMOVE_DEVICE;
|
||||
|
||||
return connection_send_msg(ei, &msg);
|
||||
return ei_proto_send_remove(ei, device);
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -347,17 +226,7 @@ connection_send_rel(struct ei *ei, struct ei_device *device,
|
|||
ei->state == EI_STATE_DISCONNECTED)
|
||||
return 0;
|
||||
|
||||
ClientMessage msg = CLIENT_MESSAGE__INIT;
|
||||
PointerRelative rel = POINTER_RELATIVE__INIT;
|
||||
|
||||
rel.deviceid = device->id;
|
||||
rel.x = x;
|
||||
rel.y = y;
|
||||
|
||||
msg.rel = &rel;
|
||||
msg.msg_case = CLIENT_MESSAGE__MSG_REL;
|
||||
|
||||
return connection_send_msg(ei, &msg);
|
||||
return ei_proto_send_rel(ei, device, x, y);
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -368,17 +237,7 @@ connection_send_button(struct ei *ei, struct ei_device *device,
|
|||
ei->state == EI_STATE_DISCONNECTED)
|
||||
return 0;
|
||||
|
||||
ClientMessage msg = CLIENT_MESSAGE__INIT;
|
||||
PointerButton button = POINTER_BUTTON__INIT;
|
||||
|
||||
button.deviceid = device->id;
|
||||
button.button = b;
|
||||
button.state = is_press;
|
||||
|
||||
msg.button = &button;
|
||||
msg.msg_case = CLIENT_MESSAGE__MSG_BUTTON;
|
||||
|
||||
return connection_send_msg(ei, &msg);
|
||||
return ei_proto_send_button(ei, device, b, is_press);
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -389,17 +248,7 @@ connection_send_key(struct ei *ei, struct ei_device *device,
|
|||
ei->state == EI_STATE_DISCONNECTED)
|
||||
return 0;
|
||||
|
||||
ClientMessage msg = CLIENT_MESSAGE__INIT;
|
||||
KeyboardKey key = KEYBOARD_KEY__INIT;
|
||||
|
||||
key.deviceid = device->id;
|
||||
key.key = k;
|
||||
key.state = is_press;
|
||||
|
||||
msg.key = &key;
|
||||
msg.msg_case = CLIENT_MESSAGE__MSG_KEY;
|
||||
|
||||
return connection_send_msg(ei, &msg);
|
||||
return ei_proto_send_key(ei, device, k, is_press);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -552,97 +401,6 @@ ei_peek_event(struct ei *ei)
|
|||
return ei_event_ref(e);
|
||||
}
|
||||
|
||||
static void frame_cleanup(Frame **f) {
|
||||
if (*f)
|
||||
frame__free_unpacked(*f, NULL);
|
||||
}
|
||||
static void servermessage_cleanup(ServerMessage **m) {
|
||||
if (*m)
|
||||
server_message__free_unpacked(*m, NULL);
|
||||
}
|
||||
#define _cleanup_frame_ _cleanup_(frame_cleanup)
|
||||
#define _cleanup_servermessage_ _cleanup_(servermessage_cleanup)
|
||||
|
||||
static const unsigned char *
|
||||
next_message(const char *data, size_t *msglen, size_t *consumed)
|
||||
{
|
||||
/* Every message is prefixed by a fixed-length Frame message which
|
||||
* contains the length of the next message. Frames are always the
|
||||
* same length, so we only need to calculate the size once.
|
||||
*/
|
||||
static size_t framelen = 0;
|
||||
|
||||
if (framelen == 0) {
|
||||
Frame f = FRAME__INIT;
|
||||
f.length = 0xffff;
|
||||
framelen = frame__get_packed_size(&f);
|
||||
assert(framelen >= 5);
|
||||
}
|
||||
|
||||
_cleanup_frame_ Frame *frame = frame__unpack(NULL, framelen, (const unsigned char *)data);
|
||||
if (!frame)
|
||||
return NULL;
|
||||
|
||||
*msglen = frame->length;
|
||||
*consumed = framelen;
|
||||
|
||||
return (const unsigned char*)data + framelen;
|
||||
}
|
||||
|
||||
static struct message *
|
||||
connection_parse_message(const char *data, size_t len, size_t *consumed)
|
||||
{
|
||||
size_t headerbytes = 0;
|
||||
size_t msglen = 0;
|
||||
const unsigned char *msgdata = next_message(data, &msglen, &headerbytes);
|
||||
|
||||
_cleanup_servermessage_ ServerMessage *proto = server_message__unpack(NULL, msglen, msgdata);
|
||||
if (!proto)
|
||||
return NULL;
|
||||
|
||||
*consumed = headerbytes + msglen;
|
||||
|
||||
_cleanup_message_ struct message *msg = xalloc(sizeof(*msg));
|
||||
|
||||
bool success = true;
|
||||
switch (proto->msg_case) {
|
||||
case SERVER_MESSAGE__MSG_CONNECTED:
|
||||
*msg = (struct message) {
|
||||
.type = MESSAGE_CONNECTED,
|
||||
};
|
||||
break;
|
||||
case SERVER_MESSAGE__MSG_DISCONNECTED:
|
||||
*msg = (struct message) {
|
||||
.type = MESSAGE_DISCONNECTED,
|
||||
};
|
||||
break;
|
||||
case SERVER_MESSAGE__MSG_DEVICE_ADDED:
|
||||
{
|
||||
DeviceAdded *a = proto->device_added;
|
||||
*msg = (struct message) {
|
||||
.type = MESSAGE_DEVICE_ADDED,
|
||||
.added.deviceid = a->deviceid,
|
||||
.added.capabilities = a->capabilities,
|
||||
};
|
||||
}
|
||||
break;
|
||||
case SERVER_MESSAGE__MSG_DEVICE_REMOVED:
|
||||
{
|
||||
DeviceRemoved *r = proto->device_removed;
|
||||
*msg = (struct message) {
|
||||
.type = MESSAGE_DEVICE_REMOVED,
|
||||
.removed.deviceid = r->deviceid,
|
||||
};
|
||||
}
|
||||
break;
|
||||
default:
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
|
||||
return success ? steal(&msg) : NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
connection_new_handle_msg(struct ei *ei, struct message *msg)
|
||||
{
|
||||
|
|
@ -731,8 +489,8 @@ connection_dispatch(struct source *source, void *userdata)
|
|||
if (len == 0)
|
||||
break;
|
||||
|
||||
_cleanup_(message_freep) struct message *msg =
|
||||
connection_parse_message(data, len, &consumed);
|
||||
_cleanup_message_ struct message *msg =
|
||||
ei_proto_parse_message(data, len, &consumed);
|
||||
if (!msg) {
|
||||
rc = -EBADMSG;
|
||||
break;
|
||||
|
|
@ -875,50 +633,12 @@ test_configure_name(const MunitParameter params[], void *user_data)
|
|||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static MunitResult
|
||||
test_proto_next_message(const MunitParameter params[], void *user_data)
|
||||
{
|
||||
char data[64];
|
||||
|
||||
/* Invalid frame, rest can be random */
|
||||
data[0] = 0xaa;
|
||||
|
||||
size_t msglen = 0xab;
|
||||
size_t consumed = 0xbc;
|
||||
|
||||
const unsigned char *rval = next_message(data, &msglen, &consumed);
|
||||
munit_assert_ptr_null(rval);
|
||||
munit_assert_int(msglen, ==, 0xab);
|
||||
munit_assert_int(consumed, ==, 0xbc);
|
||||
|
||||
/* Now try a valid one */
|
||||
Frame f = FRAME__INIT;
|
||||
f.length = 0xcd;
|
||||
size_t framelen = frame__get_packed_size(&f);
|
||||
|
||||
unsigned char buf[framelen * 4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
frame__pack(&f, buf + framelen * i);
|
||||
|
||||
const char *ptr = (char*)buf;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
const unsigned char *next_frame = next_message(ptr, &msglen, &consumed);
|
||||
munit_assert_ptr_equal(next_frame, buf + (i + 1) * framelen);
|
||||
munit_assert_int(consumed, ==, framelen);
|
||||
munit_assert_int(msglen, ==, 0xcd);
|
||||
ptr += consumed;
|
||||
}
|
||||
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
#define TEST(_func) \
|
||||
{ .name = #_func, .test = _func }
|
||||
|
||||
static MunitTest ei_tests[] = {
|
||||
TEST(test_init_unref),
|
||||
TEST(test_configure_name),
|
||||
TEST(test_proto_next_message),
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue