Squashed 'third_party/rawrtc/re/' content from commit f3163ce8b

Change-Id: I6a235e6ac0f03269d951026f9d195da05c40fdab
git-subtree-dir: third_party/rawrtc/re
git-subtree-split: f3163ce8b526a13b35ef71ce4dd6f43585064d8a
diff --git a/src/sip/sip.c b/src/sip/sip.c
new file mode 100644
index 0000000..651628c
--- /dev/null
+++ b/src/sip/sip.c
@@ -0,0 +1,238 @@
+/**
+ * @file sip.c  SIP Core
+ *
+ * Copyright (C) 2010 Creytiv.com
+ */
+#include <re_types.h>
+#include <re_mem.h>
+#include <re_mbuf.h>
+#include <re_sa.h>
+#include <re_list.h>
+#include <re_hash.h>
+#include <re_fmt.h>
+#include <re_uri.h>
+#include <re_sys.h>
+#include <re_tmr.h>
+#include <re_udp.h>
+#include <re_stun.h>
+#include <re_msg.h>
+#include <re_sip.h>
+#include "sip.h"
+
+
+static void destructor(void *arg)
+{
+	struct sip *sip = arg;
+
+	if (sip->closing) {
+		sip->closing = false;
+		mem_ref(sip);
+		if (sip->exith)
+			sip->exith(sip->arg);
+		return;
+	}
+
+	sip_request_close(sip);
+	sip_request_close(sip);
+
+	hash_flush(sip->ht_ctrans);
+	mem_deref(sip->ht_ctrans);
+
+	hash_flush(sip->ht_strans);
+	hash_clear(sip->ht_strans_mrg);
+	mem_deref(sip->ht_strans);
+	mem_deref(sip->ht_strans_mrg);
+
+	hash_flush(sip->ht_conn);
+	mem_deref(sip->ht_conn);
+
+	hash_flush(sip->ht_udpconn);
+	mem_deref(sip->ht_udpconn);
+
+	list_flush(&sip->transpl);
+	list_flush(&sip->lsnrl);
+
+	mem_deref(sip->software);
+	mem_deref(sip->dnsc);
+	mem_deref(sip->stun);
+}
+
+
+static void lsnr_destructor(void *arg)
+{
+	struct sip_lsnr *lsnr = arg;
+
+	if (lsnr->lsnrp)
+		*lsnr->lsnrp = NULL;
+
+	list_unlink(&lsnr->le);
+}
+
+
+/**
+ * Allocate a SIP stack instance
+ *
+ * @param sipp     Pointer to allocated SIP stack
+ * @param dnsc     DNS Client (optional)
+ * @param ctsz     Size of client transactions hashtable (power of 2)
+ * @param stsz     Size of server transactions hashtable (power of 2)
+ * @param tcsz     Size of SIP transport hashtable (power of 2)
+ * @param software Software identifier
+ * @param exith    SIP-stack exit handler
+ * @param arg      Handler argument
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int sip_alloc(struct sip **sipp, struct dnsc *dnsc, uint32_t ctsz,
+	      uint32_t stsz, uint32_t tcsz, const char *software,
+	      sip_exit_h *exith, void *arg)
+{
+	struct sip *sip;
+	int err;
+
+	if (!sipp)
+		return EINVAL;
+
+	sip = mem_zalloc(sizeof(*sip), destructor);
+	if (!sip)
+		return ENOMEM;
+
+	err = sip_transp_init(sip, tcsz);
+	if (err)
+		goto out;
+
+	err = sip_ctrans_init(sip, ctsz);
+	if (err)
+		goto out;
+
+	err = sip_strans_init(sip, stsz);
+	if (err)
+		goto out;
+
+	err = hash_alloc(&sip->ht_udpconn, tcsz);
+	if (err)
+		goto out;
+
+	err = stun_alloc(&sip->stun, NULL, NULL, NULL);
+	if (err)
+		goto out;
+
+	if (software) {
+		err = str_dup(&sip->software, software);
+		if (err)
+			goto out;
+	}
+
+	sip->dnsc  = mem_ref(dnsc);
+	sip->exith = exith;
+	sip->arg   = arg;
+
+ out:
+	if (err)
+		mem_deref(sip);
+	else
+		*sipp = sip;
+
+	return err;
+}
+
+
+/**
+ * Close the SIP stack instance
+ *
+ * @param sip   SIP stack instance
+ * @param force Don't wait for transactions to complete
+ */
+void sip_close(struct sip *sip, bool force)
+{
+	if (!sip)
+		return;
+
+	if (force) {
+		sip_request_close(sip);
+		sip_request_close(sip);
+	}
+	else if (!sip->closing) {
+		sip->closing = true;
+		mem_deref(sip);
+	}
+}
+
+
+/**
+ * Send a SIP message
+ *
+ * @param sip  SIP stack instance
+ * @param sock Optional socket to send from
+ * @param tp   SIP transport
+ * @param dst  Destination network address
+ * @param mb   Buffer containing SIP message
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int sip_send(struct sip *sip, void *sock, enum sip_transp tp,
+	     const struct sa *dst, struct mbuf *mb)
+{
+	return sip_transp_send(NULL, sip, sock, tp, dst, mb, NULL, NULL);
+}
+
+
+/**
+ * Listen for incoming SIP Requests and SIP Responses
+ *
+ * @param lsnrp Pointer to allocated listener
+ * @param sip   SIP stack instance
+ * @param req   True for Request, false for Response
+ * @param msgh  SIP message handler
+ * @param arg   Handler argument
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int sip_listen(struct sip_lsnr **lsnrp, struct sip *sip, bool req,
+	       sip_msg_h *msgh, void *arg)
+{
+	struct sip_lsnr *lsnr;
+
+	if (!sip || !msgh)
+		return EINVAL;
+
+	lsnr = mem_zalloc(sizeof(*lsnr), lsnr_destructor);
+	if (!lsnr)
+		return ENOMEM;
+
+	list_append(&sip->lsnrl, &lsnr->le, lsnr);
+
+	lsnr->msgh = msgh;
+	lsnr->arg = arg;
+	lsnr->req = req;
+
+	if (lsnrp) {
+		lsnr->lsnrp = lsnrp;
+		*lsnrp = lsnr;
+	}
+
+	return 0;
+}
+
+
+/**
+ * Print debug information about the SIP stack
+ *
+ * @param pf  Print function for debug output
+ * @param sip SIP stack instance
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int sip_debug(struct re_printf *pf, const struct sip *sip)
+{
+	int err;
+
+	if (!sip)
+		return 0;
+
+	err  = sip_transp_debug(pf, sip);
+	err |= sip_ctrans_debug(pf, sip);
+	err |= sip_strans_debug(pf, sip);
+
+	return err;
+}