static void handle_getbuf(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf)
{
struct session2 *s = handle->data;
- buf->base = wire_buf_free_space(&s->layers->wire_buf);
- buf->len = wire_buf_free_space_length(&s->layers->wire_buf);
+ struct wire_buf *wb = &s->layers->wire_buf;
+
+ buf->base = wire_buf_free_space(wb);
+ buf->len = wire_buf_free_space_length(wb);
}
static void udp_on_unwrapped(int status, struct session2 *session,
return NULL;
size_t wire_buf_length = 0;
+ size_t wire_buf_max_length = 0;
ssize_t offsets[2 * num_layers];
manager_size += sizeof(offsets);
iter_offsets[i] = g->iter_size ? total_iter_data_size : -1;
total_iter_data_size += ALIGN_TO(g->iter_size, CPU_STRUCT_ALIGN);
- wire_buf_length += g->wire_buf_overhead;
+ size_t wire_buf_overhead = (g->wire_buf_overhead_cb)
+ ? g->wire_buf_overhead_cb(s->outgoing)
+ : g->wire_buf_overhead;
+ wire_buf_length += wire_buf_overhead;
+ wire_buf_max_length += MAX(g->wire_buf_max_overhead, wire_buf_overhead);
}
manager_size += total_sess_data_size;
cb_ctx_size += total_iter_data_size;
m->cb_ctx_size = cb_ctx_size;
memcpy(m->data, offsets, sizeof(offsets));
+ m->wire_buf_max_length = wire_buf_max_length;
int ret = wire_buf_init(&m->wire_buf, wire_buf_length);
kr_require(!ret);
/** Gets a pointer to the free space after the valid data of the wire buffer. */
static inline void *wire_buf_free_space(const struct wire_buf *wb)
{
- return &wb->buf[wb->end];
+ return (wb->buf) ? &wb->buf[wb->end] : NULL;
}
/** Gets the length of the free space after the valid data of the wire buffer. */
static inline size_t wire_buf_free_space_length(const struct wire_buf *wb)
{
- return wb->size - wb->end;
+ if (kr_fails_assert(wb->end <= wb->size))
+ return 0;
+ return (wb->buf) ? wb->size - wb->end : 0;
}
void *data,
void *param);
+/** Function type for determining the size of a layer's wire buffer overhead. */
+typedef size_t (*protolayer_wire_buf_overhead_cb)(bool outgoing);
+
/** Function type for (de)initialization callback of layer iteration data.
*
* `ctx` points to the iteration context that `data` belongs to.
struct protolayer_manager {
enum protolayer_grp grp;
struct wire_buf wire_buf;
+ size_t wire_buf_max_length;
struct session2 *session;
size_t num_layers;
size_t cb_ctx_size; /**< Size of a single callback context, including
* no iteration struct is used by the layer, the value may be zero. */
size_t iter_size;
- /** Number of bytes that this layer adds onto the session's wire
- * buffer. All overheads in a group are summed together to form the
- * resulting wire buffer length. */
+ /** Number of bytes that this layer adds onto the session's wire buffer
+ * by default. All overheads in a group are summed together to form the
+ * resulting default wire buffer length.
+ *
+ * Ignored when `wire_buf_overhead_cb` is non-NULL. */
size_t wire_buf_overhead;
+ /** Called during session initialization to determine the number of
+ * bytes that this layer adds onto the session's wire buffer.
+ *
+ * It is the dynamic version of `wire_buf_overhead`, which is ignored
+ * when this is non-NULL. */
+ protolayer_wire_buf_overhead_cb wire_buf_overhead_cb;
+
+ /** Number of bytes that this layer adds onto the session's wire buffer
+ * at most. All overheads in a group are summed together to form the
+ * resulting default wire buffer length.
+ *
+ * If this is less than the default overhead, the default is used
+ * instead. */
+ size_t wire_buf_max_overhead;
+
/** Called during session creation to initialize
* layer-specific session data. The data is always provided
* zero-initialized to this function. */
return PROTOLAYER_EVENT_PROPAGATE;
}
+static size_t pl_dns_dgram_wire_buf_overhead(bool outgoing)
+{
+ if (outgoing) {
+ if (the_resolver->upstream_opt_rr)
+ return knot_edns_get_payload(the_resolver->upstream_opt_rr);
+ } else {
+ if (the_resolver->downstream_opt_rr)
+ return knot_edns_get_payload(the_resolver->downstream_opt_rr);
+ }
+ return KNOT_WIRE_MAX_PKTSIZE;
+}
+
static enum protolayer_iter_cb_result pl_dns_dgram_unwrap(
void *sess_data, void *iter_data, struct protolayer_iter_ctx *ctx)
{
/* DNS protocol layers */
protolayer_globals[PROTOLAYER_PROTOCOL_DNS_DGRAM] = (struct protolayer_globals){
- .wire_buf_overhead = KNOT_WIRE_MAX_PKTSIZE,
+ .wire_buf_overhead_cb = pl_dns_dgram_wire_buf_overhead,
+ .wire_buf_max_overhead = KNOT_WIRE_MAX_PKTSIZE,
.unwrap = pl_dns_dgram_unwrap,
.event_unwrap = pl_dns_dgram_event_unwrap
};