1 /**
2  * @file reg.c  SIP Registration
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_hash.h>
12 #include <re_fmt.h>
13 #include <re_uri.h>
14 #include <re_sys.h>
15 #include <re_tmr.h>
16 #include <re_msg.h>
17 #include <re_sip.h>
18 #include <re_sipreg.h>
19 
20 
21 enum {
22 	DEFAULT_EXPIRES = 3600,
23 };
24 
25 
26 /** Defines a SIP Registration client */
27 struct sipreg {
28 	struct sip_loopstate ls;
29 	struct sa laddr;
30 	struct tmr tmr;
31 	struct sip *sip;
32 	struct sip_keepalive *ka;
33 	struct sip_request *req;
34 	struct sip_dialog *dlg;
35 	struct sip_auth *auth;
36 	struct mbuf *hdrs;
37 	char *cuser;
38 	sip_resp_h *resph;
39 	void *arg;
40 	uint32_t expires;
41 	uint32_t failc;
42 	uint32_t wait;
43 	enum sip_transp tp;
44 	bool registered;
45 	bool terminated;
46 	char *params;
47 	int regid;
48 };
49 
50 
51 static int request(struct sipreg *reg, bool reset_ls);
52 
53 
dummy_handler(int err,const struct sip_msg * msg,void * arg)54 static void dummy_handler(int err, const struct sip_msg *msg, void *arg)
55 {
56 	(void)err;
57 	(void)msg;
58 	(void)arg;
59 }
60 
61 
destructor(void * arg)62 static void destructor(void *arg)
63 {
64 	struct sipreg *reg = arg;
65 
66 	tmr_cancel(&reg->tmr);
67 
68 	if (!reg->terminated) {
69 
70 		reg->resph = dummy_handler;
71 		reg->terminated = true;
72 
73 		if (reg->req) {
74 			mem_ref(reg);
75 			return;
76 		}
77 
78 		if (reg->registered && !request(reg, true)) {
79 			mem_ref(reg);
80 			return;
81 		}
82 	}
83 
84 	mem_deref(reg->ka);
85 	mem_deref(reg->dlg);
86 	mem_deref(reg->auth);
87 	mem_deref(reg->cuser);
88 	mem_deref(reg->sip);
89 	mem_deref(reg->hdrs);
90 	mem_deref(reg->params);
91 }
92 
93 
failwait(uint32_t failc)94 static uint32_t failwait(uint32_t failc)
95 {
96 	return min(1800, (30 * (1<<min(failc, 6)))) * (500 + rand_u16() % 501);
97 }
98 
99 
tmr_handler(void * arg)100 static void tmr_handler(void *arg)
101 {
102 	struct sipreg *reg = arg;
103 	int err;
104 
105 	err = request(reg, true);
106 	if (err) {
107 		tmr_start(&reg->tmr, failwait(++reg->failc), tmr_handler, reg);
108 		reg->resph(err, NULL, reg->arg);
109 	}
110 }
111 
112 
keepalive_handler(int err,void * arg)113 static void keepalive_handler(int err, void *arg)
114 {
115 	struct sipreg *reg = arg;
116 
117 	/* failure will be handled in response handler */
118 	if (reg->req || reg->terminated)
119 		return;
120 
121 	tmr_start(&reg->tmr, failwait(++reg->failc), tmr_handler, reg);
122 	reg->resph(err, NULL, reg->arg);
123 }
124 
125 
start_outbound(struct sipreg * reg,const struct sip_msg * msg)126 static void start_outbound(struct sipreg *reg, const struct sip_msg *msg)
127 {
128 	const struct sip_hdr *flowtimer;
129 
130 	if (!sip_msg_hdr_has_value(msg, SIP_HDR_REQUIRE, "outbound"))
131 		return;
132 
133 	flowtimer = sip_msg_hdr(msg, SIP_HDR_FLOW_TIMER);
134 
135 	(void)sip_keepalive_start(&reg->ka, reg->sip, msg,
136 				  flowtimer ? pl_u32(&flowtimer->val) : 0,
137 				  keepalive_handler, reg);
138 }
139 
140 
contact_handler(const struct sip_hdr * hdr,const struct sip_msg * msg,void * arg)141 static bool contact_handler(const struct sip_hdr *hdr,
142 			    const struct sip_msg *msg, void *arg)
143 {
144 	struct sipreg *reg = arg;
145 	struct sip_addr c;
146 	struct pl pval;
147 	char uri[256];
148 
149 	if (sip_addr_decode(&c, &hdr->val))
150 		return false;
151 
152 	if (re_snprintf(uri, sizeof(uri), "sip:%s@%J%s", reg->cuser,
153 			&reg->laddr, sip_transp_param(reg->tp)) < 0)
154 		return false;
155 
156 	if (pl_strcmp(&c.auri, uri))
157 		return false;
158 
159 	if (!msg_param_decode(&c.params, "expires", &pval)) {
160 	        reg->wait = pl_u32(&pval);
161 	}
162 	else if (pl_isset(&msg->expires))
163 	        reg->wait = pl_u32(&msg->expires);
164 	else
165 	        reg->wait = DEFAULT_EXPIRES;
166 
167 	return true;
168 }
169 
170 
response_handler(int err,const struct sip_msg * msg,void * arg)171 static void response_handler(int err, const struct sip_msg *msg, void *arg)
172 {
173 	const struct sip_hdr *minexp;
174 	struct sipreg *reg = arg;
175 
176 	reg->wait = failwait(reg->failc + 1);
177 
178 	if (err || sip_request_loops(&reg->ls, msg->scode)) {
179 		reg->failc++;
180 		goto out;
181 	}
182 
183 	if (msg->scode < 200) {
184 		return;
185 	}
186 	else if (msg->scode < 300) {
187 		reg->registered = true;
188 		reg->wait = reg->expires;
189 		sip_msg_hdr_apply(msg, true, SIP_HDR_CONTACT, contact_handler,
190 				  reg);
191 		reg->wait *= 900;
192 		reg->failc = 0;
193 
194 		if (reg->regid > 0 && !reg->terminated && !reg->ka)
195 			start_outbound(reg, msg);
196 	}
197 	else {
198 		if (reg->terminated && !reg->registered)
199 			goto out;
200 
201 		switch (msg->scode) {
202 
203 		case 401:
204 		case 407:
205 			err = sip_auth_authenticate(reg->auth, msg);
206 			if (err) {
207 				err = (err == EAUTH) ? 0 : err;
208 				break;
209 			}
210 
211 			err = request(reg, false);
212 			if (err)
213 				break;
214 
215 			return;
216 
217 		case 403:
218 			sip_auth_reset(reg->auth);
219 			break;
220 
221 		case 423:
222 			minexp = sip_msg_hdr(msg, SIP_HDR_MIN_EXPIRES);
223 			if (!minexp || !pl_u32(&minexp->val) || !reg->expires)
224 				break;
225 
226 			reg->expires = pl_u32(&minexp->val);
227 
228 			err = request(reg, false);
229 			if (err)
230 				break;
231 
232 			return;
233 		}
234 
235 		++reg->failc;
236 	}
237 
238  out:
239 	if (!reg->expires) {
240 		mem_deref(reg);
241 	}
242 	else if (reg->terminated) {
243 		if (!reg->registered || request(reg, true))
244 			mem_deref(reg);
245 	}
246 	else {
247 		tmr_start(&reg->tmr, reg->wait, tmr_handler, reg);
248 		reg->resph(err, msg, reg->arg);
249 	}
250 }
251 
252 
send_handler(enum sip_transp tp,const struct sa * src,const struct sa * dst,struct mbuf * mb,void * arg)253 static int send_handler(enum sip_transp tp, const struct sa *src,
254 			const struct sa *dst, struct mbuf *mb, void *arg)
255 {
256 	struct sipreg *reg = arg;
257 	int err;
258 
259 	(void)dst;
260 
261 	if (reg->expires > 0) {
262 		reg->laddr = *src;
263 		reg->tp = tp;
264 	}
265 
266 	err = mbuf_printf(mb, "Contact: <sip:%s@%J%s>;expires=%u%s%s",
267 			  reg->cuser, &reg->laddr, sip_transp_param(reg->tp),
268 			  reg->expires,
269 			  reg->params ? ";" : "",
270 			  reg->params ? reg->params : "");
271 
272 	if (reg->regid > 0)
273 		err |= mbuf_printf(mb, ";reg-id=%d", reg->regid);
274 
275 	err |= mbuf_printf(mb, "\r\n");
276 
277 	return err;
278 }
279 
280 
request(struct sipreg * reg,bool reset_ls)281 static int request(struct sipreg *reg, bool reset_ls)
282 {
283 	if (reg->terminated)
284 		reg->expires = 0;
285 
286 	if (reset_ls)
287 		sip_loopstate_reset(&reg->ls);
288 
289 	return sip_drequestf(&reg->req, reg->sip, true, "REGISTER", reg->dlg,
290 			     0, reg->auth, send_handler, response_handler, reg,
291 			     "%s"
292 			     "%b"
293 			     "Content-Length: 0\r\n"
294 			     "\r\n",
295 			     reg->regid > 0
296 			     ? "Supported: gruu, outbound, path\r\n" : "",
297 			     reg->hdrs ? mbuf_buf(reg->hdrs) : NULL,
298 			     reg->hdrs ? mbuf_get_left(reg->hdrs) : (size_t)0);
299 }
300 
301 
302 /**
303  * Allocate a SIP Registration client
304  *
305  * @param regp     Pointer to allocated SIP Registration client
306  * @param sip      SIP Stack instance
307  * @param reg_uri  SIP Request URI
308  * @param to_uri   SIP To-header URI
309  * @param from_name  SIP From-header display name (optional)
310  * @param from_uri SIP From-header URI
311  * @param expires  Registration interval in [seconds]
312  * @param cuser    Contact username
313  * @param routev   Optional route vector
314  * @param routec   Number of routes
315  * @param regid    Register identification
316  * @param authh    Authentication handler
317  * @param aarg     Authentication handler argument
318  * @param aref     True to ref argument
319  * @param resph    Response handler
320  * @param arg      Response handler argument
321  * @param params   Optional Contact-header parameters
322  * @param fmt      Formatted strings with extra SIP Headers
323  *
324  * @return 0 if success, otherwise errorcode
325  */
sipreg_register(struct sipreg ** regp,struct sip * sip,const char * reg_uri,const char * to_uri,const char * from_name,const char * from_uri,uint32_t expires,const char * cuser,const char * routev[],uint32_t routec,int regid,sip_auth_h * authh,void * aarg,bool aref,sip_resp_h * resph,void * arg,const char * params,const char * fmt,...)326 int sipreg_register(struct sipreg **regp, struct sip *sip, const char *reg_uri,
327 		    const char *to_uri, const char *from_name,
328 		    const char *from_uri, uint32_t expires,
329 		    const char *cuser, const char *routev[], uint32_t routec,
330 		    int regid, sip_auth_h *authh, void *aarg, bool aref,
331 		    sip_resp_h *resph, void *arg,
332 		    const char *params, const char *fmt, ...)
333 {
334 	struct sipreg *reg;
335 	int err;
336 
337 	if (!regp || !sip || !reg_uri || !to_uri || !from_uri ||
338 	    !expires || !cuser)
339 		return EINVAL;
340 
341 	reg = mem_zalloc(sizeof(*reg), destructor);
342 	if (!reg)
343 		return ENOMEM;
344 
345 	err = sip_dialog_alloc(&reg->dlg, reg_uri, to_uri, from_name, from_uri,
346 			       routev, routec);
347 	if (err)
348 		goto out;
349 
350 	err = sip_auth_alloc(&reg->auth, authh, aarg, aref);
351 	if (err)
352 		goto out;
353 
354 	err = str_dup(&reg->cuser, cuser);
355 	if (params)
356 		err |= str_dup(&reg->params, params);
357 	if (err)
358 		goto out;
359 
360 	/* Custom SIP headers */
361 	if (fmt) {
362 		va_list ap;
363 
364 		reg->hdrs = mbuf_alloc(256);
365 		if (!reg->hdrs) {
366 			err = ENOMEM;
367 			goto out;
368 		}
369 
370 		va_start(ap, fmt);
371 		err = mbuf_vprintf(reg->hdrs, fmt, ap);
372 		reg->hdrs->pos = 0;
373 		va_end(ap);
374 
375 		if (err)
376 			goto out;
377 	}
378 
379 	reg->sip     = mem_ref(sip);
380 	reg->expires = expires;
381 	reg->resph   = resph ? resph : dummy_handler;
382 	reg->arg     = arg;
383 	reg->regid   = regid;
384 
385 	err = request(reg, true);
386 	if (err)
387 		goto out;
388 
389  out:
390 	if (err)
391 		mem_deref(reg);
392 	else
393 		*regp = reg;
394 
395 	return err;
396 }
397 
398 
399 /**
400  * Get the local socket address for a SIP Registration client
401  *
402  * @param reg SIP Registration client
403  *
404  * @return Local socket address
405  */
sipreg_laddr(const struct sipreg * reg)406 const struct sa *sipreg_laddr(const struct sipreg *reg)
407 {
408 	return reg ? &reg->laddr : NULL;
409 }
410