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/trice/tcpconn.c b/src/trice/tcpconn.c
new file mode 100644
index 0000000..5159ee7
--- /dev/null
+++ b/src/trice/tcpconn.c
@@ -0,0 +1,286 @@
+/**
+ * @file tcpconn.c ICE handling of TCP-connections
+ *
+ * Copyright (C) 2010 Creytiv.com
+ */
+#include <string.h>
+#include <re_types.h>
+#include <re_fmt.h>
+#include <re_mem.h>
+#include <re_mbuf.h>
+#include <re_list.h>
+#include <re_tmr.h>
+#include <re_sa.h>
+#include <re_tcp.h>
+#include <re_udp.h>
+#include <re_stun.h>
+#include <re_ice.h>
+#include <re_shim.h>
+#include <re_trice.h>
+#include "trice.h"
+
+
+#define DEBUG_MODULE "tcpconn"
+#define DEBUG_LEVEL 5
+#include <re_dbg.h>
+
+
+/* `mb' contains a complete frame */
+static bool shim_frame_handler(struct mbuf *mb, void *arg)
+{
+ struct ice_tcpconn *conn = arg;
+
+ return conn->frameh(conn->icem, conn->tc, &conn->paddr, mb, conn->arg);
+}
+
+
+static void tcp_estab_handler(void *arg)
+{
+ struct ice_tcpconn *conn = arg;
+ struct trice *icem = conn->icem;
+ struct le *le;
+ int err;
+
+ conn->estab = true;
+
+ trice_printf(icem, "TCP established (local=%J <---> peer=%J)\n",
+ &conn->laddr, &conn->paddr);
+
+ err = shim_insert(&conn->shim, conn->tc, conn->layer,
+ shim_frame_handler, conn);
+ if (err)
+ goto out;
+
+ if (!icem->checklist)
+ goto out;
+
+ /* check all pending CONNCHECKs for TCP */
+ le = icem->checklist->conncheckl.head;
+ while (le) {
+ struct ice_conncheck *cc = le->data;
+ struct ice_candpair *pair = cc->pair;
+ le = le->next;
+
+ if (pair->state == ICE_CANDPAIR_INPROGRESS &&
+ pair->lcand->attr.compid == conn->compid &&
+ pair->lcand->attr.proto == IPPROTO_TCP &&
+ sa_cmp(&pair->lcand->attr.addr, &conn->laddr, SA_ADDR) &&
+ sa_cmp(&pair->rcand->attr.addr, &conn->paddr, SA_ALL)) {
+
+ trice_printf(icem,
+ " estab: sending pending check"
+ " from %j to %J\n",
+ &pair->lcand->attr.addr,
+ &pair->rcand->attr.addr);
+
+ /* todo: */
+ pair->conn = mem_ref(conn);
+
+ err = trice_conncheck_stun_request(icem->checklist, cc,
+ pair, conn->tc,
+ cc->use_cand);
+ if (err) {
+ DEBUG_WARNING("stun_request error (%m)\n",
+ err);
+ }
+ }
+ }
+
+ out:
+ if (err) {
+ DEBUG_WARNING("estab: errors (%m)\n", err);
+ }
+}
+
+
+/* todo: re-connect if estab and active (with a timer) */
+static void tcp_close_handler(int err, void *arg)
+{
+ struct ice_tcpconn *conn = arg;
+ struct trice *icem = conn->icem;
+ struct le *le;
+
+ trice_printf(conn->icem, "TCP-connection [%J -> %J] closed (%m)\n",
+ &conn->laddr, &conn->paddr, err);
+
+ err = err ? err : ECONNRESET;
+
+ /* note: helper must be closed before tc */
+ conn->shim = mem_deref(conn->shim);
+ conn->tc = mem_deref(conn->tc);
+
+ /* todo: iterate through conncheckl and cancel all checks
+ * that are using this conn
+ */
+
+ le = conn->icem->checkl.head;
+ while (le) {
+ struct ice_candpair *pair = le->data;
+
+ le = le->next;
+
+ if (pair->lcand->attr.compid == conn->compid &&
+ pair->lcand->attr.proto == IPPROTO_TCP &&
+ sa_cmp(&pair->rcand->attr.addr, &conn->paddr, SA_ALL)) {
+
+ trice_candpair_failed(pair, err, 0);
+
+ if (icem->checklist) {
+ icem->checklist->failh(err, 0,
+ pair,
+ icem->checklist->arg);
+ }
+ }
+ }
+
+ mem_deref(conn);
+}
+
+
+static void conn_destructor(void *arg)
+{
+ struct ice_tcpconn *conn = arg;
+
+ list_unlink(&conn->le);
+ mem_deref(conn->shim);
+ mem_deref(conn->tc);
+}
+
+
+/* ts: only for accept */
+int trice_conn_alloc(struct list *connl, struct trice *icem, unsigned compid,
+ bool active, const struct sa *laddr, const struct sa *peer,
+ struct tcp_sock *ts, int layer,
+ tcpconn_frame_h *frameh, void *arg)
+{
+ struct ice_tcpconn *conn;
+ int err = 0;
+
+ if (!connl || !icem || !laddr || !peer || !frameh)
+ return EINVAL;
+
+ conn = mem_zalloc(sizeof(*conn), conn_destructor);
+ if (!conn)
+ return ENOMEM;
+
+ conn->icem = icem;
+ conn->active = active;
+ conn->paddr = *peer;
+ conn->compid = compid;
+ conn->layer = layer;
+ conn->frameh = frameh;
+ conn->arg = arg;
+
+ if (active) {
+
+ trice_printf(conn->icem, "<%p> TCP connecting"
+ " [laddr=%J paddr=%J] ..\n",
+ icem, laddr, peer);
+
+ /* This connection is opened from the local candidate of the
+ pair to the remote candidate of the pair.
+ */
+ err = tcp_conn_alloc(&conn->tc, peer, tcp_estab_handler,
+ NULL, tcp_close_handler,
+ conn);
+ if (err) {
+ DEBUG_WARNING("tcp_conn_alloc [peer=%J] (%m)\n",
+ peer, err);
+ goto out;
+ }
+
+ err = tcp_conn_bind(conn->tc, laddr);
+ if (err) {
+ DEBUG_WARNING("tcp_conn_bind [laddr=%J paddr=%J]"
+ " (%m)\n",
+ laddr, peer, err);
+ goto out;
+ }
+
+ err = tcp_conn_connect(conn->tc, peer);
+ if (err) {
+ /* NOTE: this happens sometimes on OSX when
+ * setting up two S-O connections
+ */
+ if (err == EADDRINUSE) {
+ re_printf("EADDRINUSE\n");
+ err = 0;
+ }
+ else {
+ DEBUG_NOTICE("tcp_conn_connect [peer=%J]"
+ " (%d/%m)\n",
+ peer, err, err);
+ goto out;
+ }
+ }
+ }
+ else {
+ err = tcp_accept(&conn->tc, ts, tcp_estab_handler,
+ NULL, tcp_close_handler, conn);
+ if (err) {
+ tcp_reject(ts);
+ goto out;
+ }
+ }
+
+ err = tcp_conn_local_get(conn->tc, &conn->laddr);
+ if (err)
+ goto out;
+
+ list_append(connl, &conn->le, conn);
+
+ out:
+ if (err)
+ mem_deref(conn);
+
+ return err;
+}
+
+
+/* NOTE: laddr matching is SA_ADDR only */
+struct ice_tcpconn *trice_conn_find(struct list *connl, unsigned compid,
+ const struct sa *laddr,
+ const struct sa *peer)
+{
+ struct le *le;
+
+ for (le = list_head(connl); le; le = le->next) {
+
+ struct ice_tcpconn *conn = le->data;
+
+ if (compid != conn->compid)
+ continue;
+
+ /* NOTE: only for established */
+ if (!conn->estab)
+ continue;
+
+ if (sa_cmp(laddr, &conn->laddr, SA_ADDR) &&
+ sa_cmp(peer, &conn->paddr, SA_ALL))
+ return conn;
+ }
+
+ return NULL;
+}
+
+
+int trice_conn_debug(struct re_printf *pf, const struct ice_tcpconn *conn)
+{
+ int err;
+
+ if (!conn)
+ return 0;
+
+ err = re_hprintf(pf, "... {%u} [%s|%5s] %J - %J "
+ " (usage = %u) ",
+ conn->compid,
+ conn->active ? "Active" : "Passive",
+ conn->estab ? "ESTAB" : " ",
+ &conn->laddr, &conn->paddr,
+ mem_nrefs(conn)-1);
+
+ if (conn->shim)
+ err |= shim_debug(pf, conn->shim);
+
+ return err;
+}