Squashed 'third_party/rawrtc/rew/' content from commit 24c91fd83

Change-Id: Ica2fcc790472ecd5b195d20da982c4e84139cbdd
git-subtree-dir: third_party/rawrtc/rew
git-subtree-split: 24c91fd839b40b11f727c902fa46d20874da33fb
diff --git a/src/shim/shim.c b/src/shim/shim.c
new file mode 100644
index 0000000..07e3b9c
--- /dev/null
+++ b/src/shim/shim.c
@@ -0,0 +1,200 @@
+
+#include <re_types.h>
+#include <re_fmt.h>
+#include <re_mem.h>
+#include <re_mbuf.h>
+#include <re_tcp.h>
+#include <re_net.h>
+#include <re_shim.h>
+
+
+#define DEBUG_MODULE "shim"
+#define DEBUG_LEVEL 5
+#include <re_dbg.h>
+
+
+struct shim {
+	struct tcp_conn *tc;
+	struct tcp_helper *th;
+	struct mbuf *mb;
+	shim_frame_h *frameh;
+	void *arg;
+
+	uint64_t n_tx;
+	uint64_t n_rx;
+};
+
+
+/* responsible for adding the SHIM header
+   - assumes that the sent MBUF contains a complete packet
+ */
+static bool shim_send_handler(int *err, struct mbuf *mb, void *arg)
+{
+	struct shim *shim = arg;
+	size_t len;
+	(void)shim;
+
+	if (mb->pos < SHIM_HDR_SIZE) {
+		DEBUG_WARNING("send: not enough space for SHIM header\n");
+		*err = ENOMEM;
+		return true;
+	}
+
+	len = mbuf_get_left(mb);
+
+	mb->pos -= SHIM_HDR_SIZE;
+	*err = mbuf_write_u16(mb, htons(len));
+	mb->pos -= SHIM_HDR_SIZE;
+
+	++shim->n_tx;
+
+	return false;
+}
+
+
+static bool shim_recv_handler(int *errp, struct mbuf *mbx, bool *estab,
+			      void *arg)
+{
+	struct shim *shim = arg;
+	int err = 0;
+	(void)estab;
+
+	/* handle re-assembly */
+	if (!shim->mb) {
+		shim->mb = mbuf_alloc(1024);
+		if (!shim->mb) {
+			*errp = ENOMEM;
+			return true;
+		}
+	}
+
+	if (shim->mb) {
+		size_t pos;
+
+		pos = shim->mb->pos;
+
+		shim->mb->pos = shim->mb->end;
+
+		err = mbuf_write_mem(shim->mb, mbuf_buf(mbx),
+				     mbuf_get_left(mbx));
+		if (err)
+			goto out;
+
+		shim->mb->pos = pos;
+	}
+
+	/* extract all SHIM-frames in the TCP-stream */
+	for (;;) {
+
+		size_t start, len, pos, end;
+		bool hdld;
+
+		start = shim->mb->pos;
+
+		if (mbuf_get_left(shim->mb) < (SHIM_HDR_SIZE))
+			break;
+
+		len = ntohs(mbuf_read_u16(shim->mb));
+
+		if (mbuf_get_left(shim->mb) < len)
+			goto rewind;
+
+		pos = shim->mb->pos;
+		end = shim->mb->end;
+
+		shim->mb->end = pos + len;
+
+		++shim->n_rx;
+
+		hdld = shim->frameh(shim->mb, shim->arg);
+		if (!hdld) {
+			/* XXX: handle multiple frames per segment */
+
+			shim->mb->pos = pos;
+			shim->mb->end = pos + len;
+
+			mbx->pos = mbx->end = 2;
+			err = mbuf_write_mem(mbx, mbuf_buf(shim->mb), len);
+			if (err)
+				goto out;
+			mbx->pos = 2;
+
+			shim->mb->pos = pos + len;
+			shim->mb->end = end;
+
+			return false;  /* continue recv-handlers */
+		}
+
+		shim->mb->pos = pos + len;
+		shim->mb->end = end;
+
+		if (shim->mb->pos >= shim->mb->end) {
+			shim->mb = mem_deref(shim->mb);
+			break;
+		}
+
+		continue;
+
+	rewind:
+		shim->mb->pos = start;
+		break;
+	}
+
+ out:
+	if (err)
+		*errp = err;
+
+	return true;  /* always handled */
+}
+
+
+static void destructor(void *arg)
+{
+	struct shim *shim = arg;
+
+	mem_deref(shim->th);
+	mem_deref(shim->tc);
+	mem_deref(shim->mb);
+}
+
+
+int shim_insert(struct shim **shimp, struct tcp_conn *tc, int layer,
+		shim_frame_h *frameh, void *arg)
+{
+	struct shim *shim;
+	int err;
+
+	if (!shimp || !tc || !frameh)
+		return EINVAL;
+
+	shim = mem_zalloc(sizeof(*shim), destructor);
+	if (!shim)
+		return ENOMEM;
+
+	shim->tc = mem_ref(tc);
+	err = tcp_register_helper(&shim->th, tc, layer, NULL,
+				  shim_send_handler,
+				  shim_recv_handler, shim);
+	if (err)
+		goto out;
+
+	shim->frameh = frameh;
+	shim->arg = arg;
+
+ out:
+	if (err)
+		mem_deref(shim);
+	else
+		*shimp = shim;
+
+	return err;
+}
+
+
+int shim_debug(struct re_printf *pf, const struct shim *shim)
+{
+	if (!shim)
+		return 0;
+
+	return re_hprintf(pf, "tx=%llu, rx=%llu", shim->n_tx, shim->n_rx);
+}