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/reply.c b/src/sip/reply.c
new file mode 100644
index 0000000..eb2e26f
--- /dev/null
+++ b/src/sip/reply.c
@@ -0,0 +1,268 @@
+/**
+ * @file sip/reply.c  SIP Reply
+ *
+ * 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_fmt.h>
+#include <re_uri.h>
+#include <re_udp.h>
+#include <re_msg.h>
+#include <re_sip.h>
+#include "sip.h"
+
+
+static int vreplyf(struct sip_strans **stp, struct mbuf **mbp, bool trans,
+		   struct sip *sip, const struct sip_msg *msg, bool rec_route,
+		   uint16_t scode, const char *reason,
+		   const char *fmt, va_list ap)
+{
+	bool rport = false;
+	uint32_t viac = 0;
+	struct mbuf *mb;
+	struct sa dst;
+	struct le *le;
+	int err;
+
+	if (!sip || !msg || !reason)
+		return EINVAL;
+
+	if (!pl_strcmp(&msg->met, "ACK"))
+		return 0;
+
+	mb = mbuf_alloc(1024);
+	if (!mb) {
+		err = ENOMEM;
+		goto out;
+	}
+
+	err = mbuf_printf(mb, "SIP/2.0 %u %s\r\n", scode, reason);
+
+	for (le = msg->hdrl.head; le; le = le->next) {
+
+		struct sip_hdr *hdr = le->data;
+		struct pl rp;
+
+		switch (hdr->id) {
+
+		case SIP_HDR_VIA:
+			err |= mbuf_printf(mb, "%r: ", &hdr->name);
+			if (viac++) {
+				err |= mbuf_printf(mb, "%r\r\n", &hdr->val);
+				break;
+			}
+
+			if (!msg_param_exists(&msg->via.params, "rport", &rp)){
+				err |= mbuf_write_pl_skip(mb, &hdr->val, &rp);
+				err |= mbuf_printf(mb, ";rport=%u",
+						   sa_port(&msg->src));
+				rport = true;
+			}
+			else
+				err |= mbuf_write_pl(mb, &hdr->val);
+
+			if (rport || !sa_cmp(&msg->src, &msg->via.addr,
+					     SA_ADDR))
+				err |= mbuf_printf(mb, ";received=%j",
+						   &msg->src);
+
+			err |= mbuf_write_str(mb, "\r\n");
+			break;
+
+		case SIP_HDR_TO:
+			err |= mbuf_printf(mb, "%r: %r", &hdr->name,
+					   &hdr->val);
+			if (!pl_isset(&msg->to.tag) && scode > 100)
+				err |= mbuf_printf(mb, ";tag=%016llx",
+						   msg->tag);
+			err |= mbuf_write_str(mb, "\r\n");
+			break;
+
+		case SIP_HDR_RECORD_ROUTE:
+			if (!rec_route)
+				break;
+
+			/*@fallthrough@*/
+
+		case SIP_HDR_FROM:
+		case SIP_HDR_CALL_ID:
+		case SIP_HDR_CSEQ:
+			err |= mbuf_printf(mb, "%r: %r\r\n",
+					   &hdr->name, &hdr->val);
+			break;
+
+		default:
+			break;
+		}
+	}
+
+	if (sip->software)
+		err |= mbuf_printf(mb, "Server: %s\r\n", sip->software);
+
+	if (fmt)
+		err |= mbuf_vprintf(mb, fmt, ap);
+	else
+		err |= mbuf_printf(mb, "Content-Length: 0\r\n\r\n");
+
+	if (err)
+		goto out;
+
+	mb->pos = 0;
+
+	sip_reply_addr(&dst, msg, rport);
+
+	if (trans) {
+		err = sip_strans_reply(stp, sip, msg, &dst, scode, mb);
+	}
+	else {
+		err = sip_send(sip, msg->sock, msg->tp, &dst, mb);
+	}
+
+ out:
+	if (err && stp)
+		*stp = mem_deref(*stp);
+
+	if (!err && mbp)
+		*mbp = mb;
+	else
+		mem_deref(mb);
+
+	return err;
+}
+
+
+/**
+ * Formatted reply using Server Transaction
+ *
+ * @param stp       Pointer to allocated SIP Server Transaction (optional)
+ * @param mbp       Pointer to allocated SIP message buffer (optional)
+ * @param sip       SIP Stack instance
+ * @param msg       Incoming SIP message
+ * @param rec_route True to copy Record-Route headers
+ * @param scode     Response status code
+ * @param reason    Response reason phrase
+ * @param fmt       Additional formatted SIP headers and body, otherwise NULL
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int sip_treplyf(struct sip_strans **stp, struct mbuf **mbp, struct sip *sip,
+		const struct sip_msg *msg, bool rec_route, uint16_t scode,
+		const char *reason, const char *fmt, ...)
+{
+	va_list ap;
+	int err;
+
+	va_start(ap, fmt);
+	err = vreplyf(stp, mbp, true, sip, msg, rec_route, scode, reason,
+		      fmt, ap);
+	va_end(ap);
+
+	return err;
+}
+
+
+/**
+ * Reply using Server Transaction
+ *
+ * @param stp    Pointer to allocated SIP Server Transaction (optional)
+ * @param sip    SIP Stack instance
+ * @param msg    Incoming SIP message
+ * @param scode  Response status code
+ * @param reason Response reason phrase
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int sip_treply(struct sip_strans **stp, struct sip *sip,
+	       const struct sip_msg *msg, uint16_t scode, const char *reason)
+{
+	return sip_treplyf(stp, NULL, sip, msg, false, scode, reason, NULL);
+}
+
+
+/**
+ * Stateless formatted reply
+ *
+ * @param sip    SIP Stack instance
+ * @param msg    Incoming SIP message
+ * @param scode  Response status code
+ * @param reason Response reason phrase
+ * @param fmt    Additional formatted SIP headers and body, otherwise NULL
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int sip_replyf(struct sip *sip, const struct sip_msg *msg, uint16_t scode,
+	       const char *reason, const char *fmt, ...)
+{
+	va_list ap;
+	int err;
+
+	va_start(ap, fmt);
+	err = vreplyf(NULL, NULL, false, sip, msg, false, scode, reason,
+		      fmt, ap);
+	va_end(ap);
+
+	return err;
+}
+
+
+/**
+ * Stateless reply
+ *
+ * @param sip    SIP Stack instance
+ * @param msg    Incoming SIP message
+ * @param scode  Response status code
+ * @param reason Response reason phrase
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int sip_reply(struct sip *sip, const struct sip_msg *msg, uint16_t scode,
+	      const char *reason)
+{
+	return sip_replyf(sip, msg, scode, reason, NULL);
+}
+
+
+/**
+ * Get the reply address from a SIP message
+ *
+ * @param addr  Network address, set on return
+ * @param msg   SIP message
+ * @param rport Rport value
+ */
+void sip_reply_addr(struct sa *addr, const struct sip_msg *msg, bool rport)
+{
+	uint16_t port;
+	struct pl pl;
+
+	if (!addr || !msg)
+		return;
+
+	port = sa_port(&msg->via.addr);
+	*addr = msg->src;
+
+	switch (msg->tp) {
+
+	case SIP_TRANSP_UDP:
+		if (!msg_param_decode(&msg->via.params, "maddr", &pl)) {
+			(void)sa_set(addr, &pl,sip_transp_port(msg->tp, port));
+			break;
+		}
+
+		if (rport)
+			break;
+
+		/*@fallthrough@*/
+
+	case SIP_TRANSP_TCP:
+	case SIP_TRANSP_TLS:
+		sa_set_port(addr, sip_transp_port(msg->tp, port));
+		break;
+
+	default:
+		break;
+	}
+}