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/sess.c b/src/sipsess/sess.c
new file mode 100644
index 0000000..ff505eb
--- /dev/null
+++ b/src/sipsess/sess.c
@@ -0,0 +1,264 @@
+/**
+ * @file sipsess/sess.c SIP Session 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_tmr.h>
+#include <re_msg.h>
+#include <re_sip.h>
+#include <re_sipsess.h>
+#include "sipsess.h"
+
+
+static int internal_offer_handler(struct mbuf **descp,
+ const struct sip_msg *msg, void *arg)
+{
+ (void)descp;
+ (void)msg;
+ (void)arg;
+
+ return ENOSYS;
+}
+
+
+static int internal_answer_handler(const struct sip_msg *msg, void *arg)
+{
+ (void)msg;
+ (void)arg;
+
+ return ENOSYS;
+}
+
+
+static void internal_progress_handler(const struct sip_msg *msg, void *arg)
+{
+ (void)msg;
+ (void)arg;
+}
+
+
+static void internal_establish_handler(const struct sip_msg *msg, void *arg)
+{
+ (void)msg;
+ (void)arg;
+}
+
+
+static void internal_close_handler(int err, const struct sip_msg *msg,
+ void *arg)
+{
+ (void)err;
+ (void)msg;
+ (void)arg;
+}
+
+
+static bool termwait(struct sipsess *sess)
+{
+ bool wait = false;
+
+ sess->terminated = 1;
+ sess->offerh = internal_offer_handler;
+ sess->answerh = internal_answer_handler;
+ sess->progrh = internal_progress_handler;
+ sess->estabh = internal_establish_handler;
+ sess->infoh = NULL;
+ sess->referh = NULL;
+ sess->closeh = internal_close_handler;
+ sess->arg = sess;
+
+ tmr_cancel(&sess->tmr);
+
+ if (sess->st) {
+ (void)sip_treply(&sess->st, sess->sip, sess->msg,
+ 486, "Busy Here");
+ }
+
+ if (sess->req) {
+ sip_request_cancel(sess->req);
+ mem_ref(sess);
+ wait = true;
+ }
+
+ if (sess->replyl.head) {
+ mem_ref(sess);
+ wait = true;
+ }
+
+ if (sess->requestl.head) {
+ mem_ref(sess);
+ wait = true;
+ }
+
+ return wait;
+}
+
+
+static bool terminate(struct sipsess *sess)
+{
+ sess->terminated = 2;
+
+ if (!sess->established || sess->peerterm)
+ return false;
+
+ if (sipsess_bye(sess, true))
+ return false;
+
+ mem_ref(sess);
+ return true;
+}
+
+
+static void destructor(void *arg)
+{
+ struct sipsess *sess = arg;
+
+ switch (sess->terminated) {
+
+ case 0:
+ if (termwait(sess))
+ return;
+
+ /*@fallthrough@*/
+
+ case 1:
+ if (terminate(sess))
+ return;
+ break;
+ }
+
+ hash_unlink(&sess->he);
+ tmr_cancel(&sess->tmr);
+ list_flush(&sess->replyl);
+ list_flush(&sess->requestl);
+ mem_deref((void *)sess->msg);
+ mem_deref(sess->req);
+ mem_deref(sess->dlg);
+ mem_deref(sess->auth);
+ mem_deref(sess->cuser);
+ mem_deref(sess->ctype);
+ mem_deref(sess->close_hdrs);
+ mem_deref(sess->hdrs);
+ mem_deref(sess->desc);
+ mem_deref(sess->sock);
+ mem_deref(sess->sip);
+ mem_deref(sess->st);
+}
+
+
+int sipsess_alloc(struct sipsess **sessp, struct sipsess_sock *sock,
+ const char *cuser, const char *ctype, struct mbuf *desc,
+ sip_auth_h *authh, void *aarg, bool aref,
+ sipsess_offer_h *offerh, sipsess_answer_h *answerh,
+ sipsess_progr_h *progrh, sipsess_estab_h *estabh,
+ sipsess_info_h *infoh, sipsess_refer_h *referh,
+ sipsess_close_h *closeh, void *arg)
+{
+ struct sipsess *sess;
+ int err;
+
+ sess = mem_zalloc(sizeof(*sess), destructor);
+ if (!sess)
+ return ENOMEM;
+
+ err = sip_auth_alloc(&sess->auth, authh, aarg, aref);
+ if (err)
+ goto out;
+
+ err = str_dup(&sess->cuser, cuser);
+ if (err)
+ goto out;
+
+ err = str_dup(&sess->ctype, ctype);
+ if (err)
+ goto out;
+
+ sess->sock = mem_ref(sock);
+ sess->desc = mem_ref(desc);
+ sess->sip = mem_ref(sock->sip);
+ sess->offerh = offerh ? offerh : internal_offer_handler;
+ sess->answerh = answerh ? answerh : internal_answer_handler;
+ sess->progrh = progrh ? progrh : internal_progress_handler;
+ sess->estabh = estabh ? estabh : internal_establish_handler;
+ sess->infoh = infoh;
+ sess->referh = referh;
+ sess->closeh = closeh ? closeh : internal_close_handler;
+ sess->arg = arg;
+
+ out:
+ if (err)
+ mem_deref(sess);
+ else
+ *sessp = sess;
+
+ return err;
+}
+
+
+void sipsess_terminate(struct sipsess *sess, int err,
+ const struct sip_msg *msg)
+{
+ sipsess_close_h *closeh;
+ void *arg;
+
+ if (sess->terminated)
+ return;
+
+ closeh = sess->closeh;
+ arg = sess->arg;
+
+ if (!termwait(sess))
+ (void)terminate(sess);
+
+ closeh(err, msg, arg);
+}
+
+
+/**
+ * Get the SIP dialog from a SIP Session
+ *
+ * @param sess SIP Session
+ *
+ * @return SIP Dialog object
+ */
+struct sip_dialog *sipsess_dialog(const struct sipsess *sess)
+{
+ return sess ? sess->dlg : NULL;
+}
+
+
+/**
+ * Set extra SIP headers for inclusion in Session "close" messages
+ * like BYE and 200 OK. Multiple headers can be included.
+ *
+ * @param sess SIP Session
+ * @param hdrs Formatted strings with extra SIP Headers
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int sipsess_set_close_headers(struct sipsess *sess, const char *hdrs, ...)
+{
+ int err = 0;
+ va_list ap;
+
+ if (!sess)
+ return EINVAL;
+
+ sess->close_hdrs = mem_deref(sess->close_hdrs);
+
+ if (hdrs) {
+ va_start(ap, hdrs);
+ err = re_vsdprintf(&sess->close_hdrs, hdrs, ap);
+ va_end(ap);
+ }
+
+ return err;
+}