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/connect.c b/src/sipsess/connect.c
new file mode 100644
index 0000000..5f6317e
--- /dev/null
+++ b/src/sipsess/connect.c
@@ -0,0 +1,245 @@
+/**
+ * @file connect.c  SIP Session Connect
+ *
+ * Copyright (C) 2010 Creytiv.com
+ */
+#include <string.h>
+#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 invite(struct sipsess *sess);
+
+
+static int send_handler(enum sip_transp tp, const struct sa *src,
+			const struct sa *dst, struct mbuf *mb, void *arg)
+{
+	struct sip_contact contact;
+	struct sipsess *sess = arg;
+	(void)dst;
+
+	sip_contact_set(&contact, sess->cuser, src, tp);
+
+	return mbuf_printf(mb, "%H", sip_contact_print, &contact);
+}
+
+
+static void invite_resp_handler(int err, const struct sip_msg *msg, void *arg)
+{
+	struct sipsess *sess = arg;
+	struct mbuf *desc = NULL;
+
+	if (err || sip_request_loops(&sess->ls, msg->scode))
+		goto out;
+
+	if (msg->scode < 200) {
+		sess->progrh(msg, sess->arg);
+		return;
+	}
+	else if (msg->scode < 300) {
+
+		sess->hdrs = mem_deref(sess->hdrs);
+
+		err = sip_dialog_create(sess->dlg, msg);
+		if (err)
+			goto out;
+
+		if (sess->sent_offer)
+			err = sess->answerh(msg, sess->arg);
+		else {
+			sess->modify_pending = false;
+			err = sess->offerh(&desc, msg, sess->arg);
+		}
+
+		err |= sipsess_ack(sess->sock, sess->dlg, msg->cseq.num,
+				   sess->auth, sess->ctype, desc);
+
+		sess->established = true;
+		mem_deref(desc);
+
+		if (err || sess->terminated)
+			goto out;
+
+		if (sess->modify_pending)
+			(void)sipsess_reinvite(sess, true);
+		else
+			sess->desc = mem_deref(sess->desc);
+
+		sess->estabh(msg, sess->arg);
+		return;
+	}
+	else if (msg->scode < 400) {
+
+		/* Redirect to first Contact */
+
+		if (sess->terminated)
+			goto out;
+
+		err = sip_dialog_update(sess->dlg, msg);
+		if (err)
+			goto out;
+
+		err = invite(sess);
+		if (err)
+			goto out;
+
+		return;
+	}
+	else {
+		if (sess->terminated)
+			goto out;
+
+		switch (msg->scode) {
+
+		case 401:
+		case 407:
+			err = sip_auth_authenticate(sess->auth, msg);
+			if (err) {
+				err = (err == EAUTH) ? 0 : err;
+				break;
+			}
+
+			err = invite(sess);
+			if (err)
+				break;
+
+			return;
+		}
+	}
+
+ out:
+	if (!sess->terminated)
+		sipsess_terminate(sess, err, msg);
+	else
+		mem_deref(sess);
+}
+
+
+static int invite(struct sipsess *sess)
+{
+	sess->sent_offer = sess->desc ? true : false;
+	sess->modify_pending = false;
+
+	return sip_drequestf(&sess->req, sess->sip, true, "INVITE",
+			     sess->dlg, 0, sess->auth,
+			     send_handler, invite_resp_handler, sess,
+			     "%b"
+			     "%s%s%s"
+			     "Content-Length: %zu\r\n"
+			     "\r\n"
+			     "%b",
+			     sess->hdrs ? mbuf_buf(sess->hdrs) : NULL,
+			     sess->hdrs ? mbuf_get_left(sess->hdrs) :(size_t)0,
+			     sess->desc ? "Content-Type: " : "",
+			     sess->desc ? sess->ctype : "",
+			     sess->desc ? "\r\n" : "",
+			     sess->desc ? mbuf_get_left(sess->desc) :(size_t)0,
+			     sess->desc ? mbuf_buf(sess->desc) : NULL,
+			     sess->desc ? mbuf_get_left(sess->desc):(size_t)0);
+}
+
+
+/**
+ * Connect to a remote SIP useragent
+ *
+ * @param sessp     Pointer to allocated SIP Session
+ * @param sock      SIP Session socket
+ * @param to_uri    To SIP uri
+ * @param from_name From display name
+ * @param from_uri  From SIP uri
+ * @param cuser     Contact username or URI
+ * @param routev    Outbound route vector
+ * @param routec    Outbound route vector count
+ * @param ctype     Session content-type
+ * @param desc      Content description (e.g. SDP)
+ * @param authh     SIP Authentication handler
+ * @param aarg      Authentication handler argument
+ * @param aref      True to mem_ref() aarg
+ * @param offerh    Session offer handler
+ * @param answerh   Session answer handler
+ * @param progrh    Session progress handler
+ * @param estabh    Session established handler
+ * @param infoh     Session info handler
+ * @param referh    Session refer handler
+ * @param closeh    Session close handler
+ * @param arg       Handler argument
+ * @param fmt       Formatted strings with extra SIP Headers
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int sipsess_connect(struct sipsess **sessp, struct sipsess_sock *sock,
+		    const char *to_uri, const char *from_name,
+		    const char *from_uri, const char *cuser,
+		    const char *routev[], uint32_t routec,
+		    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, const char *fmt, ...)
+{
+	struct sipsess *sess;
+	int err;
+
+	if (!sessp || !sock || !to_uri || !from_uri || !cuser || !ctype)
+		return EINVAL;
+
+	err = sipsess_alloc(&sess, sock, cuser, ctype, desc, authh, aarg, aref,
+			    offerh, answerh, progrh, estabh, infoh, referh,
+			    closeh, arg);
+	if (err)
+		return err;
+
+	/* Custom SIP headers */
+	if (fmt) {
+		va_list ap;
+
+		sess->hdrs = mbuf_alloc(256);
+		if (!sess->hdrs) {
+			err = ENOMEM;
+			goto out;
+		}
+
+		va_start(ap, fmt);
+		err = mbuf_vprintf(sess->hdrs, fmt, ap);
+		sess->hdrs->pos = 0;
+		va_end(ap);
+
+		if (err)
+			goto out;
+	}
+
+	sess->owner = true;
+
+	err = sip_dialog_alloc(&sess->dlg, to_uri, to_uri, from_name,
+			       from_uri, routev, routec);
+	if (err)
+		goto out;
+
+	hash_append(sock->ht_sess,
+		    hash_joaat_str(sip_dialog_callid(sess->dlg)),
+		    &sess->he, sess);
+
+	err = invite(sess);
+	if (err)
+		goto out;
+
+ out:
+	if (err)
+		mem_deref(sess);
+	else
+		*sessp = sess;
+
+	return err;
+}