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);
+}