don't copy the header fields in wire_compose_unicast_reply

This commit is contained in:
hippoz 2023-01-21 05:43:00 +02:00
parent e744f4afed
commit 5acf0e6422
Signed by: hippoz
GPG key ID: 56C4E02A85F2FBED
3 changed files with 47 additions and 131 deletions

View file

@ -327,8 +327,15 @@ int bus_broadcast_message(Bus *s, BusClient *sender_client, WireMsg *msg, WireCt
uint32_t previous_cursor = ctx->byte_cursor;
if (match_rule_check(sender_client, c->matches[j], msg, ctx) >= 0) {
TRYST(wire_compose_unicast_reply(reply_ctx, ctx, msg, sender_client->unique_name->name, false));
TRYST(send(c->fd, reply_ctx->data, reply_ctx->byte_cursor, 0));
struct iovec bufs[2] = {0};
uint8_t header_data[384];
WireCtx header_ctx = {
.byte_cursor = 0,
.data_len = 384,
.data = header_data
};
TRYST(wire_compose_unicast_reply(ctx, msg, sender_client->unique_name->name, bufs, &header_ctx));
TRYST(writev(c->fd, bufs, sizeof(bufs) / sizeof(bufs[0])));
// TODO?
memset(reply_ctx->data, 0, reply_ctx->data_len);
}
@ -375,17 +382,17 @@ int bus_broadcast_signal(Bus *s, BusClient *client, WireCtx *ctx, WireMsg *msg)
int bus_unicast_message(Bus *s, WireMsg *msg, WireCtx *ctx, char *target_name, char *sender_unique_name, WireCtx *reply_ctx)
{
BusClient *target = TRYPTR(bus_name_find_client(s, target_name));
TRYST(wire_compose_unicast_reply(reply_ctx, ctx, msg, sender_unique_name, true));
struct iovec bufs[] = {
{ reply_ctx->data, reply_ctx->byte_cursor }, /* header made by wire_compose_unicast_reply */
{ ctx->data + reply_ctx->byte_cursor, msg->body_length } /* body */
struct iovec bufs[2] = {0};
uint8_t header_data[384];
WireCtx header_ctx = {
.byte_cursor = 0,
.data_len = 384,
.data = header_data
};
ctx->byte_cursor += msg->body_length;
reply_ctx->byte_cursor += msg->body_length;
TRYST(wire_compose_unicast_reply(ctx, msg, sender_unique_name, bufs, &header_ctx));
TRYST(writev(target->fd, bufs, sizeof(bufs) / sizeof(bufs[0])));
return 0;
}

146
wire.c
View file

@ -1,5 +1,6 @@
#include <string.h>
#include <stdio.h>
#include <sys/uio.h>
#include "try.h"
#include "util.h"
#include "wire.h"
@ -131,7 +132,13 @@ int wire_parse_message(WireCtx *c, WireMsg *msg)
msg->serial = *(uint32_t*)TRYPTR(wire_get_u32(c));
msg->header_fields_length = *(uint32_t*)TRYPTR(wire_get_u32(c));
TRYPTR(wire_write_align(c, 8));
msg->header_length = c->byte_cursor;
size_t header_fields_end = c->byte_cursor + msg->header_fields_length;
if (unlikely(header_fields_end >= c->data_len)) {
return -1;
}
VERBOSE("start parse message: type=%d, no_reply_expected=%d\n", msg->type, msg->flags & DBUS_FLAG_NO_REPLY_EXPECTED);
@ -412,134 +419,35 @@ int wire_compose_error(WireCtx *c, WireMsg *msg, const char *error_name)
return 0;
}
int wire_compose_unicast_reply(WireCtx *c, WireCtx *msg_c, WireMsg *msg, char *sender_unique_name, bool partial)
int wire_compose_unicast_reply(WireCtx *msg_c, WireMsg *msg, char *sender_unique_name, struct iovec bufs[2], WireCtx *header_ctx)
{
TRYPTR(wire_set_u8(c, msg->endianness)); /* endianness */
TRYPTR(wire_set_u8(c, msg->type)); /* type */
TRYPTR(wire_set_u8(c, msg->flags)); /* flags */
TRYPTR(wire_set_u8(c, DBUS_PROTOCOL_VERSION)); /* protocol_version */
TRYPTR(wire_set_u32(c, msg->body_length)); /* body length */
TRYPTR(wire_set_u32(c, msg->serial)); /* serial */
uint32_t *header_fields_length = TRYPTR(wire_set_u32(c, 0)); /* header_fields_length */
TRYPTR(wire_set_u8(header_ctx, msg->endianness)); /* endianness */
TRYPTR(wire_set_u8(header_ctx, msg->type)); /* type */
TRYPTR(wire_set_u8(header_ctx, msg->flags)); /* flags */
TRYPTR(wire_set_u8(header_ctx, DBUS_PROTOCOL_VERSION)); /* protocol_version */
TRYPTR(wire_set_u32(header_ctx, msg->body_length)); /* body length */
TRYPTR(wire_set_u32(header_ctx, msg->serial)); /* serial */
uint32_t *header_fields_length = TRYPTR(wire_set_u32(header_ctx, 0)); /* header_fields_length */
uint32_t header_fields_start = c->byte_cursor;
TRYPTR(wire_write_align(header_ctx, 8));
switch (msg->type) {
case DBUS_MESSAGE_SIGNAL: /* through */
case DBUS_MESSAGE_METHOD_CALL: {
// these fields are required for DBUS_MESSAGE_METHOD_CALL, so we must (hackily) check for their presence
// interface is not strictly required by the spec, however we require it here anyways
WireMsgField *path_field = &msg->fields[DBUS_HEADER_FIELD_PATH];
WireMsgField *interface_field = &msg->fields[DBUS_HEADER_FIELD_INTERFACE];
WireMsgField *member_field = &msg->fields[DBUS_HEADER_FIELD_MEMBER];
WireMsgField *signature_field = &msg->fields[DBUS_HEADER_FIELD_SIGNATURE];
if (!path_field->present || !interface_field->present || !interface_field->present) {
return -1;
}
uint32_t header_fields_start = header_ctx->byte_cursor;
TRYPTR(wire_set_u8(c, DBUS_HEADER_FIELD_PATH));
TRYPTR(wire_set_signature_single_char(c, 'o'));
TRYPTR(wire_set_string(c, path_field->t.str));
TRYPTR(wire_write_align(c, 8));
TRYPTR(wire_set_u8(header_ctx, DBUS_HEADER_FIELD_SENDER));
TRYPTR(wire_set_signature_single_char(header_ctx, 's'));
TRYPTR(wire_set_string(header_ctx, sender_unique_name));
TRYPTR(wire_write_align(header_ctx, 8));
TRYPTR(wire_set_u8(c, DBUS_HEADER_FIELD_INTERFACE));
TRYPTR(wire_set_signature_single_char(c, 's'));
TRYPTR(wire_set_string(c, interface_field->t.str));
TRYPTR(wire_write_align(c, 8));
*header_fields_length = header_ctx->byte_cursor - header_fields_start + msg->header_fields_length;
TRYPTR(wire_set_u8(c, DBUS_HEADER_FIELD_MEMBER));
TRYPTR(wire_set_signature_single_char(c, 's'));
TRYPTR(wire_set_string(c, member_field->t.str));
TRYPTR(wire_write_align(c, 8));
if (signature_field->present) {
TRYPTR(wire_set_u8(c, DBUS_HEADER_FIELD_SIGNATURE));
TRYPTR(wire_set_signature_single_char(c, 'g'));
TRYPTR(wire_set_signature(c, signature_field->t.str));
TRYPTR(wire_write_align(c, 8));
}
TRYPTR(wire_set_u8(c, DBUS_HEADER_FIELD_SENDER));
TRYPTR(wire_set_signature_single_char(c, 's'));
TRYPTR(wire_set_string(c, sender_unique_name));
// last element, don't align
} break;
case DBUS_MESSAGE_METHOD_RETURN: {
WireMsgField *reply_serial_field = &msg->fields[DBUS_HEADER_FIELD_REPLY_SERIAL];
if (!reply_serial_field->present) {
return -1;
}
TRYPTR(wire_set_u8(c, DBUS_HEADER_FIELD_REPLY_SERIAL));
TRYPTR(wire_set_signature_single_char(c, 'u'));
TRYPTR(wire_set_u32(c, reply_serial_field->t.u32));
TRYPTR(wire_write_align(c, 8));
WireMsgField *signature_field = &msg->fields[DBUS_HEADER_FIELD_SIGNATURE];
if (signature_field->present) {
TRYPTR(wire_set_u8(c, DBUS_HEADER_FIELD_SIGNATURE));
TRYPTR(wire_set_signature_single_char(c, 'g'));
TRYPTR(wire_set_signature(c, signature_field->t.str));
TRYPTR(wire_write_align(c, 8));
}
TRYPTR(wire_set_u8(c, DBUS_HEADER_FIELD_SENDER));
TRYPTR(wire_set_signature_single_char(c, 's'));
TRYPTR(wire_set_string(c, sender_unique_name));
// last element, don't align
} break;
case DBUS_MESSAGE_ERROR: {
WireMsgField *reply_serial_field = &msg->fields[DBUS_HEADER_FIELD_REPLY_SERIAL];
WireMsgField *error_name_field = &msg->fields[DBUS_HEADER_FIELD_ERROR_NAME];
if (!reply_serial_field->present || !error_name_field->present) {
return -1;
}
TRYPTR(wire_set_u8(c, DBUS_HEADER_FIELD_REPLY_SERIAL));
TRYPTR(wire_set_signature_single_char(c, 'u'));
TRYPTR(wire_set_u32(c, reply_serial_field->t.u32));
TRYPTR(wire_write_align(c, 8));
WireMsgField *signature_field = &msg->fields[DBUS_HEADER_FIELD_SIGNATURE];
if (signature_field->present) {
TRYPTR(wire_set_u8(c, DBUS_HEADER_FIELD_SIGNATURE));
TRYPTR(wire_set_signature_single_char(c, 'g'));
TRYPTR(wire_set_signature(c, signature_field->t.str));
TRYPTR(wire_write_align(c, 8));
}
TRYPTR(wire_set_u8(c, DBUS_HEADER_FIELD_ERROR_NAME));
TRYPTR(wire_set_signature_single_char(c, 's'));
TRYPTR(wire_set_string(c, error_name_field->t.str));
TRYPTR(wire_write_align(c, 8));
TRYPTR(wire_set_u8(c, DBUS_HEADER_FIELD_SENDER));
TRYPTR(wire_set_signature_single_char(c, 's'));
TRYPTR(wire_set_string(c, sender_unique_name));
// last element, don't align
} break;
default: {
return -1;
} break;
}
*header_fields_length = c->byte_cursor - header_fields_start;
// header ends on an 8 byte alignment
TRYPTR(wire_write_align(c, 8));
if (c->byte_cursor + msg->body_length >= c->data_len || msg_c->byte_cursor + msg->body_length >= msg_c->data_len) {
if (msg_c->byte_cursor + msg->body_length >= msg_c->data_len) {
return -1;
}
if (!partial) {
memcpy(&c->data[c->byte_cursor], &msg_c->data[msg_c->byte_cursor], msg->body_length);
c->byte_cursor += msg->body_length;
msg_c->byte_cursor += msg->body_length;
}
bufs[0] = (struct iovec){ header_ctx->data, header_ctx->byte_cursor };
bufs[1] = (struct iovec){ msg_c->data + msg->header_length, msg_c->byte_cursor + msg->body_length - msg->header_length };
msg_c->byte_cursor += msg->body_length;
return 0;
}

5
wire.h
View file

@ -4,6 +4,7 @@
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <sys/uio.h>
#include "util.h"
#include "try.h"
@ -57,7 +58,7 @@ typedef struct {
#define WIRE_MESSAGE_MAX_HEADER_FIELDS 9
typedef struct {
uint8_t endianness, type, flags, protocol_version;
uint32_t body_length, serial, header_fields_length;
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;
@ -128,7 +129,7 @@ char *wire_get_string_check(WireCtx *c, int min_length, int max_length);
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 *c, WireCtx *msg_c, WireMsg *msg, char *sender_unique_name, bool partial);
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);