From: David Goulet Date: Thu, 5 Oct 2023 14:49:59 +0000 (-0400) Subject: prop340: Add relay msg codec, encoder and decoder basics X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fae9eaaef577dc93d5011f4296a41f984d39b373;p=thirdparty%2Ftor.git prop340: Add relay msg codec, encoder and decoder basics Signed-off-by: David Goulet --- diff --git a/src/core/or/relay_msg.c b/src/core/or/relay_msg.c index 3dad5322fd..864a6066f2 100644 --- a/src/core/or/relay_msg.c +++ b/src/core/or/relay_msg.c @@ -36,6 +36,73 @@ get_param_enabled(const networkstatus_t *ns) RELAY_MSG_PARAM_ENABLED_MAX) != 0; } +/** Initialize the given encoder for the relay cell protocol version. */ +static void +encoder_relay_msg_init(relay_msg_encoder_t *encoder, uint8_t relay_cell_proto) +{ + tor_assert(encoder); + encoder->relay_cell_proto = relay_cell_proto; + encoder->ready_cells = smartlist_new(); +} + +/** Clear a given encoder which frees its ressources. */ +static void +encoder_relay_msg_clear(relay_msg_encoder_t *encoder) +{ + tor_assert(encoder); + SMARTLIST_FOREACH(encoder->ready_cells, cell_t *, c, tor_free(c)); + smartlist_free(encoder->ready_cells); +} + +/** Reset a given encoder that is set it back to its initial state. */ +#if 0 +static void +encoder_relay_msg_reset(relay_msg_encoder_t *encoder) +{ + tor_assert(encoder); + uint8_t relay_cell_proto = encoder->relay_cell_proto; + encoder_relay_msg_clear(encoder); + encoder_relay_msg_init(encoder, relay_cell_proto); +} +#endif + +/** Initialize a given decoder object for the relay cell protocol version. */ +static void +decoder_relay_msg_init(relay_msg_decoder_t *decoder, uint8_t relay_cell_proto) +{ + memset(decoder, 0, sizeof(relay_msg_decoder_t)); + decoder->relay_cell_proto = relay_cell_proto; + decoder->ready = smartlist_new(); +} + +/** Clear the inside of the given decoder object as in free any ressources. */ +static void +decoder_relay_msg_clear(relay_msg_decoder_t *decoder) +{ + if (!decoder) { + return; + } + relay_msg_free(decoder->pending); + SMARTLIST_FOREACH(decoder->ready, relay_msg_t *, m, relay_msg_free(m)); + smartlist_free(decoder->ready); +} + +/** Clear the given decoder as in free all its content and initialize it to + * factory default. */ +#if 0 +static void +decoder_relay_msg_reset(relay_msg_decoder_t *decoder) +{ + uint8_t relay_cell_proto = decoder->relay_cell_proto; + decoder_relay_msg_clear(decoder); + decoder_relay_msg_init(decoder, relay_cell_proto); +} +#endif + +/* + * Public API + */ + /** Return true iff the ability to use relay messages is enabled. */ bool relay_msg_is_enabled(void) @@ -50,3 +117,47 @@ relay_msg_consensus_has_changed(const networkstatus_t *ns) { relay_msg_enabled = get_param_enabled(ns); } + +/** Free the given relay message. */ +void +relay_msg_free(relay_msg_t *msg) +{ + if (!msg) { + return; + } + tor_free(msg->body); + tor_free(msg); +} + +/** Clear a relay message as in free its content and reset all fields to 0. + * This is useful for stack allocated memory. */ +void +relay_msg_clear(relay_msg_t *msg) +{ + tor_assert(msg); + tor_free(msg->body); + memset(msg, 0, sizeof(*msg)); +} + +/** Initialize a given codec pointer for the relay cell protocol version. */ +void +relay_msg_codec_init(relay_msg_codec_t *codec, uint8_t relay_cell_proto) +{ + tor_assert(codec); + codec->relay_cell_proto = relay_cell_proto; + decoder_relay_msg_init(&codec->decoder, relay_cell_proto); + encoder_relay_msg_init(&codec->encoder, relay_cell_proto); + codec->pending_packable_msg = smartlist_new(); +} + +/** Clear the content of the given codec object as in free the ressources. */ +void +relay_msg_codec_clear(relay_msg_codec_t *codec) +{ + tor_assert(codec); + decoder_relay_msg_clear(&codec->decoder); + encoder_relay_msg_clear(&codec->encoder); + SMARTLIST_FOREACH(codec->pending_packable_msg, relay_msg_t *, msg, + relay_msg_free(msg)); + smartlist_free(codec->pending_packable_msg); +} diff --git a/src/core/or/relay_msg.h b/src/core/or/relay_msg.h index 35b0990ba3..b265b8d459 100644 --- a/src/core/or/relay_msg.h +++ b/src/core/or/relay_msg.h @@ -11,10 +11,20 @@ #include "core/or/or.h" +#include "core/or/relay_msg_st.h" + bool relay_msg_is_enabled(void); void relay_msg_consensus_has_changed(const networkstatus_t *ns); +/* Relay message */ +void relay_msg_free(relay_msg_t *msg); +void relay_msg_clear(relay_msg_t *msg); + +/* Codec. */ +void relay_msg_codec_init(relay_msg_codec_t *codec, uint8_t relay_cell_proto); +void relay_msg_codec_clear(relay_msg_codec_t *codec); + #ifdef RELAY_MSG_PRIVATE #endif /* RELAY_MSG_PRIVATE */ diff --git a/src/core/or/relay_msg_st.h b/src/core/or/relay_msg_st.h new file mode 100644 index 0000000000..0da06734b3 --- /dev/null +++ b/src/core/or/relay_msg_st.h @@ -0,0 +1,75 @@ +/* Copyright (c) 2023, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file relay_msg_st.h + * @brief A relay message which contains a relay command and parameters, + * if any, that is from a relay cell. + **/ + +#ifndef TOR_RELAY_MSG_ST_H +#define TOR_RELAY_MSG_ST_H + +#include "core/or/or.h" + +/** A relay message object which contains pointers to the header and payload. + * + * One acquires a relay message through the use of an iterator. Once you get a + * reference, the getters MUST be used to access data. + * + * This CAN NOT be made opaque so to avoid heap allocation in the fast path. */ +typedef struct relay_msg_t { + /* Relay cell protocol version of this message. */ + uint8_t relay_cell_proto; + /* Relay command of a message. */ + uint8_t command; + /* Length of payload. */ + uint16_t length; + /* Optional routing header: stream ID of a message or 0. */ + streamid_t stream_id; + /* Indicate if this is a message from a relay early cell. */ + bool is_relay_early; + /* Message body of a relay message. */ + uint8_t *body; +} relay_msg_t; + +/** Decoder object for which cells (cell_t) are given and then unframed into + * relay message(s) kept in this object. */ +typedef struct relay_msg_decoder_t { + /* Version of the relay cell protocol to use for this decoder. */ + uint8_t relay_cell_proto; + /* The pending relay message meaning that it needs more cell to be completed. + * This happens when messages are fragmented over many cells. */ + relay_msg_t *pending; + /* The length of the pending data we are waiting for. In other words, how + * many bytes do we need more in more cells to complete the message body. */ + size_t pending_len; + /* The list of messages that are ready. Multiple messages can be in one + * single cell and so this list will have them once unframed. */ + smartlist_t *ready; +} relay_msg_decoder_t; + +/** Encoder object for which relay messages are given and then packed or/and + * fragmented yielding cell(s) to be sent on the wire. */ +typedef struct relay_msg_encoder_t { + /* Version of the relay cell protocol of this encoded. */ + uint8_t relay_cell_proto; + /* Cells that are ready to be sent on the wire. */ + smartlist_t *ready_cells; +} relay_msg_encoder_t; + +/** Codec object for relay message. This contains the decoder to be used for + * relay message. */ +typedef struct relay_msg_codec_t { + /* Version of the relay cell protocol of this codec. */ + uint8_t relay_cell_proto; + /* The decoder. */ + relay_msg_decoder_t decoder; + /* The encoded . */ + relay_msg_encoder_t encoder; + /* A list of relay message that are awaiting to be packed. A message is + * popped everytime a cell goes through the encoder. */ + smartlist_t *pending_packable_msg; +} relay_msg_codec_t; + +#endif /* !defined(TOR_RELAY_MSG_ST_H) */