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/sipsess/ack.c b/src/sipsess/ack.c
new file mode 100644
index 0000000..4a9be68
--- /dev/null
+++ b/src/sipsess/ack.c
@@ -0,0 +1,147 @@
+/**
+ * @file ack.c  SIP Session ACK
+ *
+ * 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_tmr.h>
+#include <re_msg.h>
+#include <re_sip.h>
+#include <re_sipsess.h>
+#include "sipsess.h"
+
+
+struct sipsess_ack {
+	struct le he;
+	struct tmr tmr;
+	struct sa dst;
+	struct sip_request *req;
+	struct sip_dialog *dlg;
+	struct mbuf *mb;
+	enum sip_transp tp;
+	uint32_t cseq;
+};
+
+
+static void destructor(void *arg)
+{
+	struct sipsess_ack *ack = arg;
+
+	hash_unlink(&ack->he);
+	tmr_cancel(&ack->tmr);
+	mem_deref(ack->req);
+	mem_deref(ack->dlg);
+	mem_deref(ack->mb);
+}
+
+
+static void tmr_handler(void *arg)
+{
+	struct sipsess_ack *ack = arg;
+
+	mem_deref(ack);
+}
+
+
+static int send_handler(enum sip_transp tp, const struct sa *src,
+			const struct sa *dst, struct mbuf *mb, void *arg)
+{
+	struct sipsess_ack *ack = arg;
+	(void)src;
+
+	mem_deref(ack->mb);
+	ack->mb = mem_ref(mb);
+	ack->dst = *dst;
+	ack->tp  = tp;
+
+	tmr_start(&ack->tmr, 64 * SIP_T1, tmr_handler, ack);
+
+	return 0;
+}
+
+
+static void resp_handler(int err, const struct sip_msg *msg, void *arg)
+{
+	struct sipsess_ack *ack = arg;
+	(void)err;
+	(void)msg;
+
+	mem_deref(ack);
+}
+
+
+int sipsess_ack(struct sipsess_sock *sock, struct sip_dialog *dlg,
+		uint32_t cseq, struct sip_auth *auth,
+		const char *ctype, struct mbuf *desc)
+{
+	struct sipsess_ack *ack;
+	int err;
+
+	ack = mem_zalloc(sizeof(*ack), destructor);
+	if (!ack)
+		return ENOMEM;
+
+	hash_append(sock->ht_ack,
+		    hash_joaat_str(sip_dialog_callid(dlg)),
+		    &ack->he, ack);
+
+	ack->dlg  = mem_ref(dlg);
+	ack->cseq = cseq;
+
+	err = sip_drequestf(&ack->req, sock->sip, false, "ACK", dlg, cseq,
+			    auth, send_handler, resp_handler, ack,
+			    "%s%s%s"
+			    "Content-Length: %zu\r\n"
+			    "\r\n"
+			    "%b",
+			    desc ? "Content-Type: " : "",
+			    desc ? ctype : "",
+			    desc ? "\r\n" : "",
+			    desc ? mbuf_get_left(desc) : (size_t)0,
+			    desc ? mbuf_buf(desc) : NULL,
+			    desc ? mbuf_get_left(desc) : (size_t)0);
+	if (err)
+		goto out;
+
+ out:
+	if (err)
+		mem_deref(ack);
+
+	return err;
+}
+
+
+static bool cmp_handler(struct le *le, void *arg)
+{
+	struct sipsess_ack *ack = le->data;
+	const struct sip_msg *msg = arg;
+
+	if (!sip_dialog_cmp(ack->dlg, msg))
+		return false;
+
+	if (ack->cseq != msg->cseq.num)
+		return false;
+
+	return true;
+}
+
+
+int sipsess_ack_again(struct sipsess_sock *sock, const struct sip_msg *msg)
+{
+	struct sipsess_ack *ack;
+
+	ack = list_ledata(hash_lookup(sock->ht_ack,
+				      hash_joaat_pl(&msg->callid),
+				      cmp_handler, (void *)msg));
+	if (!ack)
+		return ENOENT;
+
+	return sip_send(sock->sip, NULL, ack->tp, &ack->dst, ack->mb);
+}