1 /**
2  * @file dialog.c  SIP Dialog
3  *
4  * Copyright (C) 2010 Creytiv.com
5  */
6 #include <string.h>
7 #include <re_types.h>
8 #include <re_mem.h>
9 #include <re_mbuf.h>
10 #include <re_sa.h>
11 #include <re_list.h>
12 #include <re_hash.h>
13 #include <re_fmt.h>
14 #include <re_uri.h>
15 #include <re_sys.h>
16 #include <re_tmr.h>
17 #include <re_udp.h>
18 #include <re_msg.h>
19 #include <re_sip.h>
20 #include "sip.h"
21 
22 
23 enum {
24 	ROUTE_OFFSET = 7,
25 	X64_STRSIZE = 17,
26 };
27 
28 struct sip_dialog {
29 	struct uri route;
30 	struct mbuf *mb;
31 	char *callid;
32 	char *ltag;
33 	char *rtag;
34 	char *uri;
35 	uint32_t hash;
36 	uint32_t lseq;
37 	uint32_t rseq;
38 	size_t cpos;
39 };
40 
41 
42 struct route_enc {
43 	struct mbuf *mb;
44 	size_t end;
45 };
46 
47 
x64_strdup(char ** strp,uint64_t val)48 static int x64_strdup(char **strp, uint64_t val)
49 {
50 	char *str;
51 
52 	str = mem_alloc(X64_STRSIZE, NULL);
53 	if (!str)
54 		return ENOMEM;
55 
56 	(void)re_snprintf(str, X64_STRSIZE, "%016llx", val);
57 
58 	*strp = str;
59 
60 	return 0;
61 }
62 
63 
destructor(void * arg)64 static void destructor(void *arg)
65 {
66 	struct sip_dialog *dlg = arg;
67 
68 	mem_deref(dlg->callid);
69 	mem_deref(dlg->ltag);
70 	mem_deref(dlg->rtag);
71 	mem_deref(dlg->uri);
72 	mem_deref(dlg->mb);
73 }
74 
75 
76 /**
77  * Allocate a SIP Dialog
78  *
79  * @param dlgp      Pointer to allocated SIP Dialog
80  * @param uri       Target URI
81  * @param to_uri    To URI
82  * @param from_name From displayname (optional)
83  * @param from_uri  From URI
84  * @param routev    Route vector
85  * @param routec    Route count
86  *
87  * @return 0 if success, otherwise errorcode
88  */
sip_dialog_alloc(struct sip_dialog ** dlgp,const char * uri,const char * to_uri,const char * from_name,const char * from_uri,const char * routev[],uint32_t routec)89 int sip_dialog_alloc(struct sip_dialog **dlgp,
90 		     const char *uri, const char *to_uri,
91 		     const char *from_name, const char *from_uri,
92 		     const char *routev[], uint32_t routec)
93 {
94 	const uint64_t ltag = rand_u64();
95 	struct sip_dialog *dlg;
96 	struct sip_addr addr;
97 	size_t rend = 0;
98 	struct pl pl;
99 	uint32_t i;
100 	int err;
101 
102 	if (!dlgp || !uri || !to_uri || !from_uri)
103 		return EINVAL;
104 
105 	dlg = mem_zalloc(sizeof(*dlg), destructor);
106 	if (!dlg)
107 		return ENOMEM;
108 
109 	dlg->hash = hash_fast_str(from_uri);
110 	dlg->lseq = rand_u16();
111 
112 	err = str_dup(&dlg->uri, uri);
113 	if (err)
114 		goto out;
115 
116 	err = x64_strdup(&dlg->callid, rand_u64());
117 	if (err)
118 		goto out;
119 
120 	err = x64_strdup(&dlg->ltag, ltag);
121 	if (err)
122 		goto out;
123 
124 	dlg->mb = mbuf_alloc(512);
125 	if (!dlg->mb) {
126 		err = ENOMEM;
127 		goto out;
128 	}
129 
130 	for (i=0; i<routec; i++) {
131 		err |= mbuf_printf(dlg->mb, "Route: <%s;lr>\r\n", routev[i]);
132 		if (i == 0)
133 			rend = dlg->mb->pos - 2;
134 	}
135 	err |= mbuf_printf(dlg->mb, "To: <%s>\r\n", to_uri);
136 	dlg->cpos = dlg->mb->pos;
137 	err |= mbuf_printf(dlg->mb, "From: %s%s%s<%s>;tag=%016llx\r\n",
138 			   from_name ? "\"" : "", from_name,
139 			   from_name ? "\" " : "",
140 			   from_uri, ltag);
141 	if (err)
142 		goto out;
143 
144 	dlg->mb->pos = 0;
145 
146 	if (rend) {
147 		pl.p = (const char *)mbuf_buf(dlg->mb) + ROUTE_OFFSET;
148 		pl.l = rend - ROUTE_OFFSET;
149 		err = sip_addr_decode(&addr, &pl);
150 		dlg->route = addr.uri;
151 	}
152 	else {
153 		pl_set_str(&pl, dlg->uri);
154 		err = uri_decode(&dlg->route, &pl);
155 	}
156 
157  out:
158 	if (err)
159 		mem_deref(dlg);
160 	else
161 		*dlgp = dlg;
162 
163 	return err;
164 }
165 
166 
record_route_handler(const struct sip_hdr * hdr,const struct sip_msg * msg,void * arg)167 static bool record_route_handler(const struct sip_hdr *hdr,
168 				 const struct sip_msg *msg,
169 				 void *arg)
170 {
171 	struct route_enc *renc = arg;
172 	(void)msg;
173 
174 	if (mbuf_printf(renc->mb, "Route: %r\r\n", &hdr->val))
175 		return true;
176 
177 	if (!renc->end)
178 	        renc->end = renc->mb->pos - 2;
179 
180 	return false;
181 }
182 
183 
184 /**
185  * Accept and create a SIP Dialog from an incoming SIP Message
186  *
187  * @param dlgp Pointer to allocated SIP Dialog
188  * @param msg  SIP Message
189  *
190  * @return 0 if success, otherwise errorcode
191  */
sip_dialog_accept(struct sip_dialog ** dlgp,const struct sip_msg * msg)192 int sip_dialog_accept(struct sip_dialog **dlgp, const struct sip_msg *msg)
193 {
194 	const struct sip_hdr *contact;
195 	struct sip_dialog *dlg;
196 	struct route_enc renc;
197 	struct sip_addr addr;
198 	struct pl pl;
199 	int err;
200 
201 	if (!dlgp || !msg || !msg->req)
202 		return EINVAL;
203 
204 	contact = sip_msg_hdr(msg, SIP_HDR_CONTACT);
205 
206 	if (!contact || !msg->callid.p)
207 		return EBADMSG;
208 
209 	if (sip_addr_decode(&addr, &contact->val))
210 		return EBADMSG;
211 
212 	dlg = mem_zalloc(sizeof(*dlg), destructor);
213 	if (!dlg)
214 		return ENOMEM;
215 
216 	dlg->hash = rand_u32();
217 	dlg->lseq = rand_u16();
218 	dlg->rseq = msg->cseq.num;
219 
220 	err = pl_strdup(&dlg->uri, &addr.auri);
221 	if (err)
222 		goto out;
223 
224 	err = pl_strdup(&dlg->callid, &msg->callid);
225 	if (err)
226 		goto out;
227 
228 	err = x64_strdup(&dlg->ltag, msg->tag);
229 	if (err)
230 		goto out;
231 
232 	err = pl_strdup(&dlg->rtag, &msg->from.tag);
233 	if (err)
234 		goto out;
235 
236 	dlg->mb = mbuf_alloc(512);
237 	if (!dlg->mb) {
238 		err = ENOMEM;
239 		goto out;
240 	}
241 
242 	renc.mb  = dlg->mb;
243 	renc.end = 0;
244 
245 	err |= sip_msg_hdr_apply(msg, true, SIP_HDR_RECORD_ROUTE,
246 				 record_route_handler, &renc) ? ENOMEM : 0;
247 	err |= mbuf_printf(dlg->mb, "To: %r\r\n", &msg->from.val);
248 	err |= mbuf_printf(dlg->mb, "From: %r;tag=%016llx\r\n", &msg->to.val,
249 			   msg->tag);
250 	if (err)
251 		goto out;
252 
253 	dlg->mb->pos = 0;
254 
255 	if (renc.end) {
256 		pl.p = (const char *)mbuf_buf(dlg->mb) + ROUTE_OFFSET;
257 		pl.l = renc.end - ROUTE_OFFSET;
258 		err = sip_addr_decode(&addr, &pl);
259 		dlg->route = addr.uri;
260 	}
261 	else {
262 		pl_set_str(&pl, dlg->uri);
263 		err = uri_decode(&dlg->route, &pl);
264 	}
265 
266  out:
267 	if (err)
268 		mem_deref(dlg);
269 	else
270 		*dlgp = dlg;
271 
272 	return err;
273 }
274 
275 
276 /**
277  * Initialize a SIP Dialog from an incoming SIP Message
278  *
279  * @param dlg SIP Dialog to initialize
280  * @param msg SIP Message
281  *
282  * @return 0 if success, otherwise errorcode
283  */
sip_dialog_create(struct sip_dialog * dlg,const struct sip_msg * msg)284 int sip_dialog_create(struct sip_dialog *dlg, const struct sip_msg *msg)
285 {
286 	char *uri = NULL, *rtag = NULL;
287 	const struct sip_hdr *contact;
288 	struct route_enc renc;
289 	struct sip_addr addr;
290 	struct pl pl;
291 	int err;
292 
293 	if (!dlg || dlg->rtag || !dlg->cpos || !msg)
294 		return EINVAL;
295 
296 	contact = sip_msg_hdr(msg, SIP_HDR_CONTACT);
297 
298 	if (!contact)
299 		return EBADMSG;
300 
301 	if (sip_addr_decode(&addr, &contact->val))
302 		return EBADMSG;
303 
304 	renc.mb = mbuf_alloc(512);
305 	if (!renc.mb)
306 		return ENOMEM;
307 
308 	err = pl_strdup(&uri, &addr.auri);
309 	if (err)
310 		goto out;
311 
312 	err = pl_strdup(&rtag, msg->req ? &msg->from.tag : &msg->to.tag);
313 	if (err)
314 		goto out;
315 
316 	renc.end = 0;
317 
318 	err |= sip_msg_hdr_apply(msg, msg->req, SIP_HDR_RECORD_ROUTE,
319 				 record_route_handler, &renc) ? ENOMEM : 0;
320 	err |= mbuf_printf(renc.mb, "To: %r\r\n",
321 			   msg->req ? &msg->from.val : &msg->to.val);
322 
323 	dlg->mb->pos = dlg->cpos;
324 	err |= mbuf_write_mem(renc.mb, mbuf_buf(dlg->mb),
325 			      mbuf_get_left(dlg->mb));
326 	dlg->mb->pos = 0;
327 
328 	if (err)
329 		goto out;
330 
331 	renc.mb->pos = 0;
332 
333 	if (renc.end) {
334 		pl.p = (const char *)mbuf_buf(renc.mb) + ROUTE_OFFSET;
335 		pl.l = renc.end - ROUTE_OFFSET;
336 		err = sip_addr_decode(&addr, &pl);
337 		if (err)
338 			goto out;
339 
340 		dlg->route = addr.uri;
341 	}
342 	else {
343 		struct uri tmp;
344 
345 		pl_set_str(&pl, uri);
346 		err = uri_decode(&tmp, &pl);
347 		if (err)
348 			goto out;
349 
350 		dlg->route = tmp;
351 	}
352 
353 	mem_deref(dlg->mb);
354 	mem_deref(dlg->uri);
355 
356 	dlg->mb   = mem_ref(renc.mb);
357 	dlg->rtag = mem_ref(rtag);
358 	dlg->uri  = mem_ref(uri);
359 	dlg->rseq = msg->req ? msg->cseq.num : 0;
360 	dlg->cpos = 0;
361 
362  out:
363 	mem_deref(renc.mb);
364 	mem_deref(rtag);
365 	mem_deref(uri);
366 
367 	return err;
368 }
369 
370 
371 /**
372  * Fork a SIP Dialog from an incoming SIP Message
373  *
374  * @param dlgp Pointer to allocated SIP Dialog
375  * @param odlg Original SIP Dialog
376  * @param msg  SIP Message
377  *
378  * @return 0 if success, otherwise errorcode
379  */
sip_dialog_fork(struct sip_dialog ** dlgp,struct sip_dialog * odlg,const struct sip_msg * msg)380 int sip_dialog_fork(struct sip_dialog **dlgp, struct sip_dialog *odlg,
381 		    const struct sip_msg *msg)
382 {
383 	const struct sip_hdr *contact;
384 	struct sip_dialog *dlg;
385 	struct route_enc renc;
386 	struct sip_addr addr;
387 	struct pl pl;
388 	int err;
389 
390 	if (!dlgp || !odlg || !odlg->cpos || !msg)
391 		return EINVAL;
392 
393 	contact = sip_msg_hdr(msg, SIP_HDR_CONTACT);
394 
395 	if (!contact || !msg->callid.p)
396 		return EBADMSG;
397 
398 	if (sip_addr_decode(&addr, &contact->val))
399 		return EBADMSG;
400 
401 	dlg = mem_zalloc(sizeof(*dlg), destructor);
402 	if (!dlg)
403 		return ENOMEM;
404 
405 	dlg->callid = mem_ref(odlg->callid);
406 	dlg->ltag   = mem_ref(odlg->ltag);
407 	dlg->hash   = odlg->hash;
408 	dlg->lseq   = odlg->lseq;
409 	dlg->rseq   = msg->req ? msg->cseq.num : 0;
410 
411 	err = pl_strdup(&dlg->uri, &addr.auri);
412 	if (err)
413 		goto out;
414 
415 	err = pl_strdup(&dlg->rtag, msg->req ? &msg->from.tag : &msg->to.tag);
416 	if (err)
417 		goto out;
418 
419 	dlg->mb = mbuf_alloc(512);
420 	if (!dlg->mb) {
421 		err = ENOMEM;
422 		goto out;
423 	}
424 
425 	renc.mb  = dlg->mb;
426 	renc.end = 0;
427 
428 	err |= sip_msg_hdr_apply(msg, msg->req, SIP_HDR_RECORD_ROUTE,
429 				 record_route_handler, &renc) ? ENOMEM : 0;
430 	err |= mbuf_printf(dlg->mb, "To: %r\r\n",
431 			   msg->req ? &msg->from.val : &msg->to.val);
432 
433 	odlg->mb->pos = odlg->cpos;
434 	err |= mbuf_write_mem(dlg->mb, mbuf_buf(odlg->mb),
435 			      mbuf_get_left(odlg->mb));
436 	odlg->mb->pos = 0;
437 
438 	if (err)
439 		goto out;
440 
441 	dlg->mb->pos = 0;
442 
443 	if (renc.end) {
444 		pl.p = (const char *)mbuf_buf(dlg->mb) + ROUTE_OFFSET;
445 		pl.l = renc.end - ROUTE_OFFSET;
446 		err = sip_addr_decode(&addr, &pl);
447 		dlg->route = addr.uri;
448 	}
449 	else {
450 		pl_set_str(&pl, dlg->uri);
451 		err = uri_decode(&dlg->route, &pl);
452 	}
453 
454  out:
455 	if (err)
456 		mem_deref(dlg);
457 	else
458 		*dlgp = dlg;
459 
460 	return err;
461 }
462 
463 
464 /**
465  * Update an existing SIP Dialog from a SIP Message
466  *
467  * @param dlg SIP Dialog to update
468  * @param msg SIP Message
469  *
470  * @return 0 if success, otherwise errorcode
471  */
sip_dialog_update(struct sip_dialog * dlg,const struct sip_msg * msg)472 int sip_dialog_update(struct sip_dialog *dlg, const struct sip_msg *msg)
473 {
474 	const struct sip_hdr *contact;
475 	struct sip_addr addr;
476 	char *uri;
477 	int err;
478 
479 	if (!dlg || !msg)
480 		return EINVAL;
481 
482 	contact = sip_msg_hdr(msg, SIP_HDR_CONTACT);
483 	if (!contact)
484 		return EBADMSG;
485 
486 	if (sip_addr_decode(&addr, &contact->val))
487 		return EBADMSG;
488 
489 	err = pl_strdup(&uri, &addr.auri);
490 	if (err)
491 		return err;
492 
493 	if (dlg->route.scheme.p == dlg->uri) {
494 
495 		struct uri tmp;
496 		struct pl pl;
497 
498 		pl_set_str(&pl, uri);
499 		err = uri_decode(&tmp, &pl);
500 		if (err)
501 			goto out;
502 
503 		dlg->route = tmp;
504 	}
505 
506 	mem_deref(dlg->uri);
507 	dlg->uri = mem_ref(uri);
508 
509  out:
510 	mem_deref(uri);
511 
512 	return err;
513 }
514 
515 
516 /**
517  * Check if a remote sequence number is valid
518  *
519  * @param dlg SIP Dialog
520  * @param msg SIP Message
521  *
522  * @return True if valid, False if invalid
523  */
sip_dialog_rseq_valid(struct sip_dialog * dlg,const struct sip_msg * msg)524 bool sip_dialog_rseq_valid(struct sip_dialog *dlg, const struct sip_msg *msg)
525 {
526 	if (!dlg || !msg || !msg->req)
527 		return false;
528 
529 	if (msg->cseq.num < dlg->rseq)
530 		return false;
531 
532 	dlg->rseq = msg->cseq.num;
533 
534 	return true;
535 }
536 
537 
sip_dialog_encode(struct mbuf * mb,struct sip_dialog * dlg,uint32_t cseq,const char * met)538 int sip_dialog_encode(struct mbuf *mb, struct sip_dialog *dlg, uint32_t cseq,
539 		      const char *met)
540 {
541 	int err = 0;
542 
543 	if (!mb || !dlg || !met)
544 		return EINVAL;
545 
546 	err |= mbuf_write_mem(mb, mbuf_buf(dlg->mb), mbuf_get_left(dlg->mb));
547 	err |= mbuf_printf(mb, "Call-ID: %s\r\n", dlg->callid);
548 	err |= mbuf_printf(mb, "CSeq: %u %s\r\n", strcmp(met, "ACK") ?
549 			   dlg->lseq++ : cseq, met);
550 
551 	return err;
552 }
553 
554 
sip_dialog_uri(const struct sip_dialog * dlg)555 const char *sip_dialog_uri(const struct sip_dialog *dlg)
556 {
557 	return dlg ? dlg->uri : NULL;
558 }
559 
560 
sip_dialog_route(const struct sip_dialog * dlg)561 const struct uri *sip_dialog_route(const struct sip_dialog *dlg)
562 {
563 	return dlg ? &dlg->route : NULL;
564 }
565 
566 
sip_dialog_hash(const struct sip_dialog * dlg)567 uint32_t sip_dialog_hash(const struct sip_dialog *dlg)
568 {
569 	return dlg ? dlg->hash : 0;
570 }
571 
572 
573 /**
574  * Get the Call-ID from a SIP Dialog
575  *
576  * @param dlg SIP Dialog
577  *
578  * @return Call-ID string
579  */
sip_dialog_callid(const struct sip_dialog * dlg)580 const char *sip_dialog_callid(const struct sip_dialog *dlg)
581 {
582 	return dlg ? dlg->callid : NULL;
583 }
584 
585 
586 /**
587  * Get the local sequence number from a SIP Dialog
588  *
589  * @param dlg SIP Dialog
590  *
591  * @return Local sequence number
592  */
sip_dialog_lseq(const struct sip_dialog * dlg)593 uint32_t sip_dialog_lseq(const struct sip_dialog *dlg)
594 {
595 	return dlg ? dlg->lseq : 0;
596 }
597 
598 
599 /**
600  * Check if a SIP Dialog is established
601  *
602  * @param dlg SIP Dialog
603  *
604  * @return True if established, False if not
605  */
sip_dialog_established(const struct sip_dialog * dlg)606 bool sip_dialog_established(const struct sip_dialog *dlg)
607 {
608 	return dlg && dlg->rtag;
609 }
610 
611 
612 /**
613  * Compare a SIP Dialog against a SIP Message
614  *
615  * @param dlg SIP Dialog
616  * @param msg SIP Message
617  *
618  * @return True if match, False if no match
619  */
sip_dialog_cmp(const struct sip_dialog * dlg,const struct sip_msg * msg)620 bool sip_dialog_cmp(const struct sip_dialog *dlg, const struct sip_msg *msg)
621 {
622 	if (!dlg || !msg)
623 		return false;
624 
625 	if (pl_strcmp(&msg->callid, dlg->callid))
626 		return false;
627 
628 	if (pl_strcmp(msg->req ? &msg->to.tag : &msg->from.tag, dlg->ltag))
629 		return false;
630 
631 	if (pl_strcmp(msg->req ? &msg->from.tag : &msg->to.tag, dlg->rtag))
632 		return false;
633 
634 	return true;
635 }
636 
637 
638 /**
639  * Compare a half SIP Dialog against a SIP Message
640  *
641  * @param dlg SIP Dialog
642  * @param msg SIP Message
643  *
644  * @return True if match, False if no match
645  */
sip_dialog_cmp_half(const struct sip_dialog * dlg,const struct sip_msg * msg)646 bool sip_dialog_cmp_half(const struct sip_dialog *dlg,
647 			 const struct sip_msg *msg)
648 {
649 	if (!dlg || !msg)
650 		return false;
651 
652 	if (pl_strcmp(&msg->callid, dlg->callid))
653 		return false;
654 
655 	if (pl_strcmp(msg->req ? &msg->to.tag : &msg->from.tag, dlg->ltag))
656 		return false;
657 
658 	return true;
659 }
660