#ifndef _JITTERBUG__WIRE_H #define _JITTERBUG__WIRE_H #include #include #include #include #include "util.h" #include "try.h" #define DBUS_PROTOCOL_VERSION 1 #define DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER 1 #define DBUS_REQUEST_NAME_REPLY_IN_QUEUE 2 #define DBUS_REQUEST_NAME_REPLY_EXISTS 3 #define DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER 4 #define DBUS_FLAG_NO_REPLY_EXPECTED 0x1 #define DBUS_FLAG_NO_AUTO_START 0x1 #define DBUS_FLAG_ALLOW_INTERACTIVE_AUTHORIZATION 0x1 #define UNIQUE_NAME_LENGTH 16 enum { DBUS_HEADER_FIELD_INVALID = 0, DBUS_HEADER_FIELD_PATH, DBUS_HEADER_FIELD_INTERFACE, DBUS_HEADER_FIELD_MEMBER, DBUS_HEADER_FIELD_ERROR_NAME, DBUS_HEADER_FIELD_REPLY_SERIAL, DBUS_HEADER_FIELD_DESTINATION, DBUS_HEADER_FIELD_SENDER, DBUS_HEADER_FIELD_SIGNATURE, DBUS_HEADER_FIELD_UNIX_FDS, }; enum { DBUS_MESSAGE_INVALID = 0, DBUS_MESSAGE_METHOD_CALL, DBUS_MESSAGE_METHOD_RETURN, DBUS_MESSAGE_ERROR, DBUS_MESSAGE_SIGNAL, }; typedef struct { uint32_t byte_cursor; uint8_t *data; size_t data_len; } WireCtx; // SPEC: https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-messages typedef struct { bool present; union { char *str; uint32_t u32; } t; } WireMsgField; #define WIRE_MESSAGE_MAX_HEADER_FIELDS 9 typedef struct { uint8_t endianness, type, flags, protocol_version; uint32_t body_length, serial, header_fields_length, header_length; uint8_t header_fields_count; WireMsgField fields[WIRE_MESSAGE_MAX_HEADER_FIELDS]; /* cannot have more than 9 header fields */ } WireMsg; typedef struct { uint16_t index; char *str; } WireMsgBodyString; bool wire_write_align(WireCtx *c, uint32_t alignment); bool wire_align(WireCtx *c, uint32_t alignment); #define _WIRE_DECL_BYTE_TYPE(M_mnemonic, M_type) \ M_type *wire_get_##M_mnemonic(WireCtx *c); \ M_type *wire_set_##M_mnemonic(WireCtx *c, M_type val); \ #define _WIRE_DECL_TYPE(M_mnemonic, M_type, M_alignment) \ M_type *wire_get_##M_mnemonic(WireCtx *c); \ M_type *wire_set_##M_mnemonic(WireCtx *c, M_type val); \ #define _WIRE_DEF_BYTE_TYPE(M_mnemonic, M_type) \ M_type *wire_get_##M_mnemonic(WireCtx *restrict c) { \ if (unlikely(c->byte_cursor + 1 >= c->data_len)) return NULL; \ M_type *value = (M_type*)&c->data[c->byte_cursor++]; \ return value; \ } \ M_type *wire_set_##M_mnemonic(WireCtx *restrict c, M_type val) { \ if (unlikely(c->byte_cursor + 1 >= c->data_len)) return NULL; \ M_type *dest = (M_type*)&c->data[c->byte_cursor++]; \ *dest = val; \ return dest; \ } \ #define _WIRE_DEF_TYPE(M_mnemonic, M_type, M_alignment) \ M_type *wire_get_##M_mnemonic(WireCtx *restrict c) { \ if (unlikely(!wire_align(c, M_alignment))) return NULL; \ uint32_t new_cursor = c->byte_cursor + sizeof(M_type); \ if (unlikely(new_cursor >= c->data_len)) return NULL; \ M_type *value = (M_type*)&c->data[c->byte_cursor]; \ c->byte_cursor = new_cursor; \ return value; \ } \ M_type *wire_set_##M_mnemonic(WireCtx *restrict c, M_type val) { \ if (unlikely(!wire_write_align(c, M_alignment))) return NULL; \ uint32_t new_cursor = c->byte_cursor + sizeof(M_type); \ if (unlikely(new_cursor >= c->data_len)) return NULL; \ M_type *dest = (M_type*)&c->data[c->byte_cursor]; \ *dest = val; \ c->byte_cursor = new_cursor; \ return dest; \ } \ bool wire_align(WireCtx *c, uint32_t alignment); bool wire_write_align(WireCtx *c, uint32_t alignment); // SPEC: https://dbus.freedesktop.org/doc/dbus-specification.html#id-1.4.6 _WIRE_DECL_BYTE_TYPE(i8, int8_t) _WIRE_DECL_BYTE_TYPE(u8, uint8_t) _WIRE_DECL_TYPE(i16, int16_t, 2) _WIRE_DECL_TYPE(u16, uint16_t, 2) _WIRE_DECL_TYPE(i32, int32_t, 4) _WIRE_DECL_TYPE(u32, uint32_t, 4) _WIRE_DECL_TYPE(boolean, uint32_t, 4) char *wire_get_string_impl(WireCtx *c, bool as_signature); char *wire_set_string_impl(WireCtx *c, const char *str, bool as_signature); char *wire_get_string_check(WireCtx *c, int min_length, int max_length); char *wire_set_string_fixed(WireCtx *c, const char *str, uint32_t len); int wire_parse_message(WireCtx *c, WireMsg *msg); int wire_compose_reply(WireCtx *c, WireMsg *msg, const char *signature, uint32_t **out_body_length); int wire_compose_error(WireCtx *c, WireMsg *msg, const char *error_name); int wire_compose_unicast_reply(WireCtx *msg_c, WireMsg *msg, char *sender_unique_name, struct iovec bufs[2], WireCtx *header_ctx); int wire_compose_signal(WireCtx *c, WireMsg *out_msg, const char *signature, const char *member, uint32_t **out_body_length); int wire_collect_strings(WireCtx *c, WireMsg *msg, WireMsgBodyString *strings, int strings_count); static inline char *wire_get_signature(WireCtx *c) { return wire_get_string_impl(c, true); } static inline char *wire_set_signature(WireCtx *c, const char *str) { return wire_set_string_impl(c, str, true); } static inline char *wire_get_string(WireCtx *c) { return wire_get_string_impl(c, false); } static inline char *wire_set_string(WireCtx *c, const char *str) { return wire_set_string_impl(c, str, false); } char *wire_set_signature_single_char(WireCtx *c, const char s); // maximum name length is 255 static inline char *wire_get_name_string(WireCtx *c) { return wire_get_string_check(c, 1, 255); } #endif // _JITTERBUG__WIRE_H