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