proto: switch object ids to 64 bits

This commit is contained in:
Peter Hutterer 2023-02-28 14:20:03 +10:00
parent d4980d8579
commit ba51f434a6
11 changed files with 90 additions and 71 deletions

View file

@ -33,7 +33,7 @@
Protocol wire format: [sender-id, length | opcode, ...]
Where:
- sender-id is one 32-bit integer
- sender-id is one 64-bit integer
- length and opcode share one 32-bit integer, and
length are the high 16 bits and opcode are the low 16 bits.
- all integers are in the EIS implementation's native byte order.
@ -60,11 +60,15 @@
length field thus takes 12 bytes in total. Full (le) encoding:
[0x06, 0x00, 0x00, 0x00, 'h', 'e', 'l', 'l', 'o', '\0', '\0\, '\0']
- 'new_id': an object id allocated by the caller. Client-allocated IDs begin
at 1 and must be less than 0xff000000.
at 1 and must be less than 0xff00000000000000.
IDs allocated by the EIS implementation start at and must not be less
than 0xff000000.
than 0xff00000000000000.
- 'object_id': a previously allocated object id
Object IDs:
Object IDs are unique, monotonically increasing and must not be re-used by the
client or the server.
Protocol XML:
- a request or event marked as type="destructor" causes the object to be
destroyed immediately after that message has been sent.
@ -451,7 +455,7 @@
to the object since the last successful message.
</description>
<arg name="last_serial" type="uint32" summary="the last serial sent by the EIS implementation"/>
<arg name="invalid_id" type="uint32" />
<arg name="invalid_id" type="uint64" />
</event>
<event name="ping" since="1">

View file

@ -25,6 +25,7 @@
#include "config.h"
#include <stdbool.h>
#include <inttypes.h>
#include "util-mem.h"
#include "util-io.h"
@ -197,8 +198,6 @@ brei_demarshal(struct brei_context *brei, struct iobuf *buf, const char *signatu
case 'i':
case 'u':
case 'f':
case 'o':
case 'n':
arg->u = *p++;
break;
case 'x':
@ -206,6 +205,8 @@ brei_demarshal(struct brei_context *brei, struct iobuf *buf, const char *signatu
p++;
p++;
break;
case 'o':
case 'n':
case 't':
arg->x = *(uint64_t *) p;
p++;
@ -269,8 +270,6 @@ brei_marshal(struct brei_context *brei, struct iobuf *buf, const char *signature
iobuf_append(buf, (const char*)(&i), 4);
break;
case 'u':
case 'o':
case 'n':
u = va_arg(args, uint32_t);
iobuf_append(buf, (const char*)(&u), 4);
break;
@ -278,6 +277,8 @@ brei_marshal(struct brei_context *brei, struct iobuf *buf, const char *signature
x = va_arg(args, int64_t);
iobuf_append(buf, (const char*)(&x), 8);
break;
case 'o':
case 'n':
case 't':
t = va_arg(args, uint64_t);
iobuf_append(buf, (const char*)(&t), 8);
@ -329,8 +330,9 @@ brei_marshal_message(struct brei_context *brei,
if (result)
return steal(&result);
size_t message_len = iobuf_len(buf) + 8;
uint32_t header[2] = {id, message_len << 16 | opcode};
size_t message_len = iobuf_len(buf) + 12;
uint32_t header[3] = {0, 0, message_len << 16 | opcode};
memcpy(header, &id, sizeof(id));
iobuf_prepend(buf, (const char *)header, sizeof(header));
return brei_result_new_success(steal(&buf));
@ -359,14 +361,14 @@ brei_dispatch(struct brei_context *brei,
uint32_t *data = (uint32_t*)iobuf_data(buf);
size_t len = iobuf_len(buf);
const size_t headersize = 8; /* object-id, length | opcode */
const size_t headersize = 12; /* object-id, length | opcode */
if (len < headersize)
break;
object_id_t object_id = data[0]; /* 4 bytes for object id */
size_t msglen = data[1] >> 16; /* 2 bytes message length */
uint32_t opcode = data[1] & 0xFFFF; /* 2 bytes for opcode */
object_id_t object_id = *(uint64_t*)data; /* 8 bytes for object id */
size_t msglen = data[2] >> 16; /* 2 bytes message length */
uint32_t opcode = data[2] & 0xFFFF; /* 2 bytes for opcode */
if (len < msglen)
break;
@ -407,7 +409,7 @@ brei_dispatch(struct brei_context *brei,
if (result)
goto error;
log_debug(brei, "dispatching %s.%s() on object %#x", interface->name, interface->incoming[opcode].name, object_id);
log_debug(brei, "dispatching %s.%s() on object %#" PRIx64 "", interface->name, interface->incoming[opcode].name, object_id);
/* Success! Let's pass this on to the
* context to process */
@ -562,7 +564,7 @@ MUNIT_TEST(test_brei_send_message)
int sock_read = sv[0];
int sock_write = sv[1];
const int header_size = 8;
const int header_size = 12;
{
const int msglen = header_size + 8; /* 2 * 4 bytes */
@ -573,12 +575,13 @@ MUNIT_TEST(test_brei_send_message)
munit_assert_int(rc, ==, msglen);
uint32_t buf[64];
uint64_t *buf_id = (uint64_t*)buf;
int len = read(sock_read, buf, sizeof(buf));
munit_assert_int(len, ==, msglen);
munit_assert_int(buf[0], ==, id);
munit_assert_int(buf[1], ==, msglen << 16 | opcode);
munit_assert_int(buf[2], ==, 0xff);
munit_assert_int(buf[3], ==, 0xdddd);
munit_assert_int(*buf_id, ==, id);
munit_assert_int(buf[2], ==, msglen << 16 | opcode);
munit_assert_int(buf[3], ==, 0xff);
munit_assert_int(buf[4], ==, 0xdddd);
}
{
const int msglen = header_size + 8; /* 2 * 4 bytes */
@ -589,17 +592,18 @@ MUNIT_TEST(test_brei_send_message)
munit_assert_int(rc, ==, msglen);
uint32_t buf[64];
uint64_t *buf_id = (uint64_t*)buf;
int len = read(sock_read, buf, sizeof(buf));
union {
uint32_t bytes;
float f;
} ufloat;
munit_assert_int(len, ==, msglen);
munit_assert_int(buf[0], ==, id);
munit_assert_int(buf[1], ==, msglen << 16 | opcode);
ufloat.bytes = buf[2];
munit_assert_int(*buf_id, ==, id);
munit_assert_int(buf[2], ==, msglen << 16 | opcode);
ufloat.bytes = buf[3];
munit_assert_double_equal(ufloat.f, 1.234, 4/* precision */);
munit_assert_int(buf[3], ==, -12);
munit_assert_int(buf[4], ==, -12);
}
{
@ -607,7 +611,7 @@ MUNIT_TEST(test_brei_send_message)
int slen = bytes_to_int32(strlen0(string)) * 4;
munit_assert_int(slen, ==, sizeof(string));
const int msglen = header_size + 16 + slen; /* 3 * 4 bytes + 4 bytes slen + string length */
const int msglen = header_size + 24 + slen; /* 4 bytes + 2 * 8 bytes + string length */
object_id_t id = 2;
uint32_t opcode = 3;
const char *signature = "ison";
@ -616,19 +620,20 @@ MUNIT_TEST(test_brei_send_message)
munit_assert_int(rc, ==, msglen);
uint32_t buf[64];
uint64_t *buf_id = (uint64_t*)buf;
int len = read(sock_read, buf, sizeof(buf));
munit_assert_int(len, ==, msglen);
munit_assert_int(buf[0], ==, id);
munit_assert_int(buf[1], ==, msglen << 16 | opcode);
munit_assert_int(buf[2], ==, -42);
munit_assert_int(*buf_id, ==, id);
munit_assert_int(buf[2], ==, msglen << 16 | opcode);
munit_assert_int(buf[3], ==, -42);
const struct brei_string *s = (const struct brei_string *)&buf[3];
const struct brei_string *s = (const struct brei_string *)&buf[4];
munit_assert_int(s->len, ==, strlen0(string));
munit_assert_string_equal(s->str, string);
munit_assert_int(memcmp(s->str, string, brei_string_proto_length(s->len) - 4), ==, 0);
munit_assert_int(buf[4 + slen/4], ==, 0xab);
munit_assert_int(buf[5 + slen/4], ==, 0xcdef);
munit_assert_int(buf[5 + slen/4], ==, 0xab);
munit_assert_int(buf[7 + slen/4], ==, 0xcdef);
}
{
@ -643,17 +648,18 @@ MUNIT_TEST(test_brei_send_message)
munit_assert_int(rc, ==, msglen);
uint32_t buf[64];
uint64_t *buf_id = (uint64_t*)buf;
int len = read(sock_read, buf, sizeof(buf));
munit_assert_int(len, ==, msglen);
munit_assert_int(buf[0], ==, id);
munit_assert_int(buf[1], ==, msglen << 16 | opcode);
munit_assert_int(*buf_id, ==, id);
munit_assert_int(buf[2], ==, msglen << 16 | opcode);
const struct brei_string *s1 = (const struct brei_string *)&buf[2];
const struct brei_string *s1 = (const struct brei_string *)&buf[3];
munit_assert_int(s1->len, ==, strlen0(string1));
munit_assert_string_equal(s1->str, string1);
munit_assert_int(memcmp(s1->str, string1, brei_string_proto_length(s1->len) - 4), ==, 0);
const struct brei_string *s2 = (const struct brei_string *)&buf[6];
const struct brei_string *s2 = (const struct brei_string *)&buf[7];
munit_assert_int(s2->len, ==, strlen0(string2));
munit_assert_string_equal(s2->str, string2);
munit_assert_int(memcmp(s2->str, string2, brei_string_proto_length(s2->len) - 4), ==, 0);
@ -685,12 +691,13 @@ MUNIT_TEST(test_brei_send_message)
int len = iobuf_recv_from_fd(recv, sock_read);
uint32_t *buf = (uint32_t*)iobuf_data(recv);
uint64_t *buf_id = (uint64_t*)buf;
munit_assert_int(len, ==, msglen);
munit_assert_int(buf[0], ==, id);
munit_assert_int(buf[1], ==, msglen << 16 | opcode);
munit_assert_int(buf[2], ==, 0xab);
munit_assert_int(*buf_id, ==, id);
munit_assert_int(buf[2], ==, msglen << 16 | opcode);
munit_assert_int(buf[3], ==, 0xab);
/* fd is not in data */
munit_assert_int(buf[3], ==, 0xcd);
munit_assert_int(buf[4], ==, 0xcd);
_cleanup_close_ int fd = iobuf_take_fd(recv);
munit_assert_int(fd, !=, -1);

View file

@ -34,7 +34,7 @@
#include "util-list.h"
#include "util-object.h"
typedef uint32_t object_id_t;
typedef uint64_t object_id_t;
struct brei_interface;
struct brei_message;

View file

@ -37,8 +37,8 @@ extern "C" {
* any of the actual sources files.
*/
typedef uint32_t new_id_t;
typedef uint32_t object_id_t;
typedef uint64_t object_id_t;
typedef object_id_t new_id_t;
struct {{target.name}};

View file

@ -59,7 +59,7 @@ ei_device_set_state(struct ei_device *device,
{
enum ei_device_state old_state = device->state;
device->state = state;
log_debug(ei_device_get_context(device), "device %#x: %s → %s",
log_debug(ei_device_get_context(device), "device %#" PRIx64 ": %s → %s",
ei_device_get_id(device), ei_device_state_to_string(old_state),
ei_device_state_to_string(state));
}
@ -148,7 +148,7 @@ handle_msg_destroy(struct ei_device *device, uint32_t serial)
{
struct ei *ei = ei_device_get_context(device);
ei_update_serial(ei, serial);
log_debug(ei, "Removed device %#x", ei_device_get_id(device));
log_debug(ei, "Removed device %#" PRIx64 "", ei_device_get_id(device));
ei_device_removed_by_server(device);
return NULL;
}
@ -233,7 +233,7 @@ handle_msg_done(struct ei_device *device)
!ei_device_has_capability(device, EI_DEVICE_CAP_POINTER_ABSOLUTE) &&
!ei_device_has_capability(device, EI_DEVICE_CAP_KEYBOARD) &&
!ei_device_has_capability(device, EI_DEVICE_CAP_TOUCH)) {
log_debug(ei, "Rejecting device %#x '%s' with no known capabilities",
log_debug(ei, "Rejecting device %#" PRIx64 " '%s' with no known capabilities",
ei_device_get_id(device), ei_device_get_name(device));
ei_device_close(device);
/* FIXME: this is untested */
@ -244,7 +244,7 @@ handle_msg_done(struct ei_device *device)
ei_queue_device_added_event(device);
ei_device_done(device);
log_debug(ei,
"Added device %#x '%s' caps: %s%s%s%s seat: %s",
"Added device %#" PRIx64 " '%s' caps: %s%s%s%s seat: %s",
ei_device_get_id(device), ei_device_get_name(device),
ei_device_has_capability(device, EI_DEVICE_CAP_POINTER) ? "p" : "",
ei_device_has_capability(device, EI_DEVICE_CAP_POINTER_ABSOLUTE) ? "a" : "",
@ -783,7 +783,7 @@ ei_device_new(struct ei_seat *seat, object_id_t deviceid, uint32_t version)
device->capabilities = 0;
device->state = EI_DEVICE_STATE_NEW;
device->name = xaprintf("unnamed device %#x", deviceid);
device->name = xaprintf("unnamed device %#" PRIx64 "", deviceid);
list_init(&device->regions);
list_init(&device->pending_event_queue);

View file

@ -25,6 +25,7 @@
#pragma once
#include <stdarg.h>
#include <inttypes.h>
#include "util-macros.h"
#include "util-object.h"

View file

@ -123,7 +123,7 @@ handle_msg_device(struct ei_seat *seat, object_id_t id, uint32_t version)
{
struct ei *ei = ei_seat_get_context(seat);
log_debug(ei, "Added device %#x@v%u", id, version);
log_debug(ei, "Added device %#" PRIx64 "@v%u", id, version);
/* device is in the seat's device list */
struct ei_device *device = ei_device_new(seat, id, version);
/* this list "owns" the ref for this device */

View file

@ -137,7 +137,7 @@ ei_create_context(bool is_sender, void *user_data)
object_id_t
ei_get_new_id(struct ei *ei)
{
static const int server_range = 0xff000000;
static const uint64_t server_range = 0xff00000000000000;
return ei->next_object_id++ & ~server_range;
}
@ -150,14 +150,14 @@ ei_update_serial(struct ei *ei, uint32_t serial)
void
ei_register_object(struct ei *ei, struct brei_object *object)
{
log_debug(ei, "registering %s v%u object %#x", object->interface->name, object->version, object->id);
log_debug(ei, "registering %s v%u object %#" PRIx64 "", object->interface->name, object->version, object->id);
list_append(&ei->proto_objects, &object->link);
}
void
ei_unregister_object(struct ei *ei, struct brei_object *object)
{
log_debug(ei, "deregistering %s v%u object %#x", object->interface->name, object->version, object->id);
log_debug(ei, "deregistering %s v%u object %#" PRIx64 "", object->interface->name, object->version, object->id);
list_remove(&object->link);
}
@ -680,11 +680,11 @@ handle_msg_disconnected(struct ei_connection *connection, uint32_t last_serial,
}
static struct brei_result *
handle_msg_invalid_object(struct ei_connection *connection, uint32_t last_serial, uint32_t object)
handle_msg_invalid_object(struct ei_connection *connection, uint32_t last_serial, object_id_t object)
{
struct ei *ei = ei_connection_get_context(connection);
log_bug(ei, "Invalid object %#x after %u, I don't yet know how to handle that", object, last_serial);
log_bug(ei, "Invalid object %#" PRIx64 " after %u, I don't yet know how to handle that", object, last_serial);
return NULL;
}
@ -726,7 +726,7 @@ lookup_object(object_id_t object_id, struct brei_object **object, void *userdata
}
}
log_debug(ei, "Failed to find object %#x", object_id);
log_debug(ei, "Failed to find object %#" PRIx64 "", object_id);
return -ENOENT;
}
@ -765,7 +765,7 @@ int
ei_send_message(struct ei *ei, const struct brei_object *object,
uint32_t opcode, const char *signature, size_t nargs, ...)
{
log_debug(ei, "sending: object %#x (%s@v%u:%s(%u)) signature '%s'",
log_debug(ei, "sending: object %#" PRIx64 " (%s@v%u:%s(%u)) signature '%s'",
object->id,
object->interface->name,
object->interface->version,

View file

@ -104,15 +104,16 @@ eis_client_get_proto_object(struct eis_client *client)
object_id_t
eis_client_get_new_id(struct eis_client *client)
{
static const int offset = 0xff000000;
return offset | (client->next_object_id++ & ~offset);
static const uint64_t mask = -1 >> 8;
static const uint64_t offset = 0xff00000000000000;
return offset | (client->next_object_id++ & mask);
}
void
eis_client_register_object(struct eis_client *client, struct brei_object *object)
{
struct eis *eis = eis_client_get_context(client);
log_debug(eis, "registering %s v%u object %#x", object->interface->name, object->version, object->id);
log_debug(eis, "registering %s v%u object %#" PRIx64 "", object->interface->name, object->version, object->id);
list_append(&client->proto_objects, &object->link);
}
@ -120,7 +121,7 @@ void
eis_client_unregister_object(struct eis_client *client, struct brei_object *object)
{
struct eis *eis = eis_client_get_context(client);
log_debug(eis, "deregistering %s v%u object %#x", object->interface->name, object->version, object->id);
log_debug(eis, "deregistering %s v%u object %#" PRIx64 "", object->interface->name, object->version, object->id);
list_remove(&object->link);
}
@ -160,7 +161,7 @@ eis_client_send_message(struct eis_client *client, const struct brei_object *obj
{
struct eis *eis = eis_client_get_context(client);
log_debug(eis, "sending: object %#x (%s@v%u:%s(%u)) signature '%s'",
log_debug(eis, "sending: object %#" PRIx64 " (%s@v%u:%s(%u)) signature '%s'",
object->id,
object->interface->name,
object->interface->version,
@ -304,7 +305,7 @@ client_msg_sync(struct eis_connection *connection, object_id_t new_id)
struct eis_client *client = eis_connection_get_client(connection);
struct eis_callback *callback = eis_callback_new(client, new_id, client->interface_versions.ei_callback);
log_debug(eis_client_get_context(client) , "object %u: connection sync done", new_id);
log_debug(eis_client_get_context(client) , "object %#" PRIx64 ": connection sync done", new_id);
int rc = eis_callback_event_done(callback, 0);
eis_callback_unref(callback);
return brei_result_new_from_neg_errno(rc);
@ -353,7 +354,7 @@ lookup_object(object_id_t object_id, struct brei_object **object, void *userdata
}
}
log_debug(eis_client_get_context(client), "Failed to find object %#x", object_id);
log_debug(eis_client_get_context(client), "Failed to find object %#" PRIx64 "", object_id);
if (client->connection)
eis_connection_event_invalid_object(client->connection,
client->last_client_serial,

View file

@ -25,6 +25,7 @@
#pragma once
#include <stdarg.h>
#include <inttypes.h>
#include "util-object.h"

View file

@ -63,11 +63,11 @@ class MessageHeader:
@classmethod
def size(cls) -> int:
return 8
return 12
@classmethod
def from_data(cls, data: bytes) -> "MessageHeader":
object_id, opcode = struct.unpack("II", data[:8])
object_id, opcode = struct.unpack("=QI", data[:cls.size()])
msglen = opcode >> 16
opcode = opcode & 0xFFFF
return cls(object_id, msglen, opcode)
@ -150,16 +150,16 @@ class Interface:
outgoing: dict[int, str] = attr.ib(default=attr.Factory(list), repr=False)
def format(self, *args, opcode: int, signature: str) -> bytes:
encoding = ["II"]
encoding = ["=QI"]
arguments = []
for sig, arg in zip(signature, args):
if sig in ["u", "n", "o"]:
if sig in ["u"]:
encoding.append("I")
elif sig in ["i"]:
encoding.append("i")
elif sig in ["f"]:
encoding.append("f")
elif sig in ["t"]:
elif sig in ["n", "o", "t"]:
encoding.append("Q")
elif sig in ["x"]:
encoding.append("q")
@ -181,9 +181,9 @@ class Interface:
return struct.pack(format, *header.as_tuple, *arguments)
def unpack(self, data, signature: str, names: list[str]) -> Tuple[int, dict[str, Any]]:
encoding = ["II"] # the header
encoding = ["=QI"] # the header
for sig in signature:
if sig in ["u", "n", "o"]:
if sig in ["u"]:
encoding.append("I")
elif sig in ["i"]:
encoding.append("i")
@ -191,7 +191,7 @@ class Interface:
encoding.append("f")
elif sig in ["x"]:
encoding.append("q")
elif sig in ["t"]:
elif sig in ["n", "o", "t"]:
encoding.append("Q")
elif sig in ["s"]:
length_so_far = struct.calcsize("".join(encoding))
@ -203,7 +203,12 @@ class Interface:
format = "".join(encoding)
msglen = struct.calcsize(format)
values = list(struct.unpack(format, data[:msglen]))
try:
values = list(struct.unpack(format, data[:msglen]))
except struct.error as e:
logger.error(f"{e}", bytes=hexlify(data), length=len(data), encoding=format)
raise e
# logger.debug(f"unpacked {format} to {values}")
results = []