1 /**
2  * @file sip/reply.c  SIP Reply
3  *
4  * Copyright (C) 2010 Creytiv.com
5  */
6 #include <re_types.h>
7 #include <re_mem.h>
8 #include <re_mbuf.h>
9 #include <re_sa.h>
10 #include <re_list.h>
11 #include <re_fmt.h>
12 #include <re_uri.h>
13 #include <re_udp.h>
14 #include <re_msg.h>
15 #include <re_sip.h>
16 #include "sip.h"
17 
18 
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)19 static int vreplyf(struct sip_strans **stp, struct mbuf **mbp, bool trans,
20 		   struct sip *sip, const struct sip_msg *msg, bool rec_route,
21 		   uint16_t scode, const char *reason,
22 		   const char *fmt, va_list ap)
23 {
24 	bool rport = false;
25 	uint32_t viac = 0;
26 	struct mbuf *mb;
27 	struct sa dst;
28 	struct le *le;
29 	int err;
30 
31 	if (!sip || !msg || !reason)
32 		return EINVAL;
33 
34 	if (!pl_strcmp(&msg->met, "ACK"))
35 		return 0;
36 
37 	mb = mbuf_alloc(1024);
38 	if (!mb) {
39 		err = ENOMEM;
40 		goto out;
41 	}
42 
43 	err = mbuf_printf(mb, "SIP/2.0 %u %s\r\n", scode, reason);
44 
45 	for (le = msg->hdrl.head; le; le = le->next) {
46 
47 		struct sip_hdr *hdr = le->data;
48 		struct pl rp;
49 
50 		switch (hdr->id) {
51 
52 		case SIP_HDR_VIA:
53 			err |= mbuf_printf(mb, "%r: ", &hdr->name);
54 			if (viac++) {
55 				err |= mbuf_printf(mb, "%r\r\n", &hdr->val);
56 				break;
57 			}
58 
59 			if (!msg_param_exists(&msg->via.params, "rport", &rp)){
60 				err |= mbuf_write_pl_skip(mb, &hdr->val, &rp);
61 				err |= mbuf_printf(mb, ";rport=%u",
62 						   sa_port(&msg->src));
63 				rport = true;
64 			}
65 			else
66 				err |= mbuf_write_pl(mb, &hdr->val);
67 
68 			if (rport || !sa_cmp(&msg->src, &msg->via.addr,
69 					     SA_ADDR))
70 				err |= mbuf_printf(mb, ";received=%j",
71 						   &msg->src);
72 
73 			err |= mbuf_write_str(mb, "\r\n");
74 			break;
75 
76 		case SIP_HDR_TO:
77 			err |= mbuf_printf(mb, "%r: %r", &hdr->name,
78 					   &hdr->val);
79 			if (!pl_isset(&msg->to.tag) && scode > 100)
80 				err |= mbuf_printf(mb, ";tag=%016llx",
81 						   msg->tag);
82 			err |= mbuf_write_str(mb, "\r\n");
83 			break;
84 
85 		case SIP_HDR_RECORD_ROUTE:
86 			if (!rec_route)
87 				break;
88 
89 			/*@fallthrough@*/
90 
91 		case SIP_HDR_FROM:
92 		case SIP_HDR_CALL_ID:
93 		case SIP_HDR_CSEQ:
94 			err |= mbuf_printf(mb, "%r: %r\r\n",
95 					   &hdr->name, &hdr->val);
96 			break;
97 
98 		default:
99 			break;
100 		}
101 	}
102 
103 	if (sip->software)
104 		err |= mbuf_printf(mb, "Server: %s\r\n", sip->software);
105 
106 	if (fmt)
107 		err |= mbuf_vprintf(mb, fmt, ap);
108 	else
109 		err |= mbuf_printf(mb, "Content-Length: 0\r\n\r\n");
110 
111 	if (err)
112 		goto out;
113 
114 	mb->pos = 0;
115 
116 	sip_reply_addr(&dst, msg, rport);
117 
118 	if (trans) {
119 		err = sip_strans_reply(stp, sip, msg, &dst, scode, mb);
120 	}
121 	else {
122 		err = sip_send(sip, msg->sock, msg->tp, &dst, mb);
123 	}
124 
125  out:
126 	if (err && stp)
127 		*stp = mem_deref(*stp);
128 
129 	if (!err && mbp)
130 		*mbp = mb;
131 	else
132 		mem_deref(mb);
133 
134 	return err;
135 }
136 
137 
138 /**
139  * Formatted reply using Server Transaction
140  *
141  * @param stp       Pointer to allocated SIP Server Transaction (optional)
142  * @param mbp       Pointer to allocated SIP message buffer (optional)
143  * @param sip       SIP Stack instance
144  * @param msg       Incoming SIP message
145  * @param rec_route True to copy Record-Route headers
146  * @param scode     Response status code
147  * @param reason    Response reason phrase
148  * @param fmt       Additional formatted SIP headers and body, otherwise NULL
149  *
150  * @return 0 if success, otherwise errorcode
151  */
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,...)152 int sip_treplyf(struct sip_strans **stp, struct mbuf **mbp, struct sip *sip,
153 		const struct sip_msg *msg, bool rec_route, uint16_t scode,
154 		const char *reason, const char *fmt, ...)
155 {
156 	va_list ap;
157 	int err;
158 
159 	va_start(ap, fmt);
160 	err = vreplyf(stp, mbp, true, sip, msg, rec_route, scode, reason,
161 		      fmt, ap);
162 	va_end(ap);
163 
164 	return err;
165 }
166 
167 
168 /**
169  * Reply using Server Transaction
170  *
171  * @param stp    Pointer to allocated SIP Server Transaction (optional)
172  * @param sip    SIP Stack instance
173  * @param msg    Incoming SIP message
174  * @param scode  Response status code
175  * @param reason Response reason phrase
176  *
177  * @return 0 if success, otherwise errorcode
178  */
sip_treply(struct sip_strans ** stp,struct sip * sip,const struct sip_msg * msg,uint16_t scode,const char * reason)179 int sip_treply(struct sip_strans **stp, struct sip *sip,
180 	       const struct sip_msg *msg, uint16_t scode, const char *reason)
181 {
182 	return sip_treplyf(stp, NULL, sip, msg, false, scode, reason, NULL);
183 }
184 
185 
186 /**
187  * Stateless formatted reply
188  *
189  * @param sip    SIP Stack instance
190  * @param msg    Incoming SIP message
191  * @param scode  Response status code
192  * @param reason Response reason phrase
193  * @param fmt    Additional formatted SIP headers and body, otherwise NULL
194  *
195  * @return 0 if success, otherwise errorcode
196  */
sip_replyf(struct sip * sip,const struct sip_msg * msg,uint16_t scode,const char * reason,const char * fmt,...)197 int sip_replyf(struct sip *sip, const struct sip_msg *msg, uint16_t scode,
198 	       const char *reason, const char *fmt, ...)
199 {
200 	va_list ap;
201 	int err;
202 
203 	va_start(ap, fmt);
204 	err = vreplyf(NULL, NULL, false, sip, msg, false, scode, reason,
205 		      fmt, ap);
206 	va_end(ap);
207 
208 	return err;
209 }
210 
211 
212 /**
213  * Stateless reply
214  *
215  * @param sip    SIP Stack instance
216  * @param msg    Incoming SIP message
217  * @param scode  Response status code
218  * @param reason Response reason phrase
219  *
220  * @return 0 if success, otherwise errorcode
221  */
sip_reply(struct sip * sip,const struct sip_msg * msg,uint16_t scode,const char * reason)222 int sip_reply(struct sip *sip, const struct sip_msg *msg, uint16_t scode,
223 	      const char *reason)
224 {
225 	return sip_replyf(sip, msg, scode, reason, NULL);
226 }
227 
228 
229 /**
230  * Get the reply address from a SIP message
231  *
232  * @param addr  Network address, set on return
233  * @param msg   SIP message
234  * @param rport Rport value
235  */
sip_reply_addr(struct sa * addr,const struct sip_msg * msg,bool rport)236 void sip_reply_addr(struct sa *addr, const struct sip_msg *msg, bool rport)
237 {
238 	uint16_t port;
239 	struct pl pl;
240 
241 	if (!addr || !msg)
242 		return;
243 
244 	port = sa_port(&msg->via.addr);
245 	*addr = msg->src;
246 
247 	switch (msg->tp) {
248 
249 	case SIP_TRANSP_UDP:
250 		if (!msg_param_decode(&msg->via.params, "maddr", &pl)) {
251 			(void)sa_set(addr, &pl,sip_transp_port(msg->tp, port));
252 			break;
253 		}
254 
255 		if (rport)
256 			break;
257 
258 		/*@fallthrough@*/
259 
260 	case SIP_TRANSP_TCP:
261 	case SIP_TRANSP_TLS:
262 		sa_set_port(addr, sip_transp_port(msg->tp, port));
263 		break;
264 
265 	default:
266 		break;
267 	}
268 }
269