/* * Author Jerry Lundström * Copyright (c) 2019-2023, OARC, Inc. * All rights reserved. * * This file is part of the dnswire library. * * dnswire library is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * dnswire library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with dnswire library. If not, see . */ #include "config.h" #include "dnswire/encoder.h" #include "dnswire/trace.h" #include const char* const dnswire_encoder_state_string[] = { "control_ready", "control_start", "control_accept", "control_finish", "frames", "control_stop", "done", }; #define __state(h, s) \ __trace("state %s => %s", dnswire_encoder_state_string[(h)->state], dnswire_encoder_state_string[s]); \ (h)->state = s; static struct tinyframe_control_field _content_type = { TINYFRAME_CONTROL_FIELD_CONTENT_TYPE, DNSTAP_PROTOBUF_CONTENT_TYPE_LENGTH, (uint8_t*)DNSTAP_PROTOBUF_CONTENT_TYPE, }; enum dnswire_result dnswire_encoder_encode(struct dnswire_encoder* handle, uint8_t* out, size_t len) { assert(handle); assert(out); assert(len); switch (handle->state) { case dnswire_encoder_control_ready: switch (tinyframe_write_control(&handle->writer, out, len, TINYFRAME_CONTROL_READY, &_content_type, 1)) { case tinyframe_ok: __state(handle, dnswire_encoder_control_start); return dnswire_again; case tinyframe_need_more: return dnswire_need_more; default: break; } return dnswire_error; case dnswire_encoder_control_start: switch (tinyframe_write_control_start(&handle->writer, out, len, DNSTAP_PROTOBUF_CONTENT_TYPE, DNSTAP_PROTOBUF_CONTENT_TYPE_LENGTH)) { case tinyframe_ok: __state(handle, dnswire_encoder_frames); return dnswire_again; case tinyframe_need_more: return dnswire_need_more; default: break; } return dnswire_error; case dnswire_encoder_control_accept: switch (tinyframe_write_control(&handle->writer, out, len, TINYFRAME_CONTROL_ACCEPT, &_content_type, 1)) { case tinyframe_ok: __state(handle, dnswire_encoder_control_finish); return dnswire_again; case tinyframe_need_more: return dnswire_need_more; default: break; } return dnswire_error; case dnswire_encoder_control_finish: switch (tinyframe_write_control(&handle->writer, out, len, TINYFRAME_CONTROL_FINISH, 0, 0)) { case tinyframe_ok: __state(handle, dnswire_encoder_done); return dnswire_endofdata; case tinyframe_need_more: return dnswire_need_more; default: break; } return dnswire_error; case dnswire_encoder_frames: { if (!handle->dnstap) { return dnswire_error; } size_t frame_len = dnstap_encode_protobuf_size(handle->dnstap); if (len < tinyframe_frame_size(frame_len)) { return dnswire_need_more; } uint8_t frame[frame_len]; dnstap_encode_protobuf(handle->dnstap, frame); switch (tinyframe_write_frame(&handle->writer, out, len, frame, sizeof(frame))) { case tinyframe_ok: return dnswire_ok; case tinyframe_need_more: return dnswire_need_more; default: break; } return dnswire_error; } case dnswire_encoder_control_stop: switch (tinyframe_write_control_stop(&handle->writer, out, len)) { case tinyframe_ok: __state(handle, dnswire_encoder_done); return dnswire_endofdata; case tinyframe_need_more: return dnswire_need_more; default: break; } return dnswire_error; case dnswire_encoder_done: break; } return dnswire_error; } enum dnswire_result dnswire_encoder_stop(struct dnswire_encoder* handle) { assert(handle); switch (handle->state) { case dnswire_encoder_frames: __state(handle, dnswire_encoder_control_stop); return dnswire_ok; default: break; } return dnswire_error; }