summaryrefslogtreecommitdiffstats
path: root/src/encoder.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/encoder.c')
-rw-r--r--src/encoder.c172
1 files changed, 172 insertions, 0 deletions
diff --git a/src/encoder.c b/src/encoder.c
new file mode 100644
index 0000000..4b7ad27
--- /dev/null
+++ b/src/encoder.c
@@ -0,0 +1,172 @@
+/*
+ * Author Jerry Lundström <jerry@dns-oarc.net>
+ * Copyright (c) 2019, 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "dnswire/encoder.h"
+#include "dnswire/trace.h"
+
+#include <assert.h>
+
+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;
+}