1 /*
2 * Copyright (C) 2001-2003 FhG Fokus
3 *
4 * This file is part of Kamailio, a free SIP server.
5 *
6 * Kamailio is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version
10 *
11 * Kamailio is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 *
20 */
21
22 /*!
23 * \file
24 * \brief TM ::
25 * \ingroup tm
26 */
27
28
29 #include <string.h>
30 #include "../../core/mem/shm_mem.h"
31 #include "../../core/dprint.h"
32 #include "../../core/parser/contact/parse_contact.h"
33 #include "../../core/parser/parse_to.h"
34 #include "../../core/parser/parse_from.h"
35 #include "../../core/parser/parse_uri.h"
36 #include "../../core/trim.h"
37 #include "../../core/ut.h"
38 #include "../../core/config.h"
39 #include "dlg.h"
40 #include "t_reply.h"
41 #include "../../core/parser/parser_f.h"
42
43 /* next added to allow automatical tag generation */
44 #include "callid.h"
45 #include "uac.h"
46
47 #define NORMAL_ORDER 0 /* Create route set in normal order - UAS */
48 #define REVERSE_ORDER 1 /* Create route set in reverse order - UAC */
49
50
51 #ifdef DIALOG_CALLBACKS
52
53 struct new_dlg_cb
54 {
55 int types;
56 struct new_dlg_cb *next;
57 dialog_cb *callback;
58 void *param;
59 };
60
61 static struct new_dlg_cb *new_dlg_cb_list = 0;
62 /* callbacks for new dialogs (called each time a new dialog (uas or uac) is
63 * created)
64 * params: type - DLG_CB_UAC or DLG_CB_UAS
65 * f - callback function
66 * param - parameter passed to the callback; if allocated it must
67 * be allocated in shared mem.
68 * returns < 0 on error
69 * WARNING: this callbacks can be registered only before forking (in mod_init)
70 */
register_new_dlg_cb(int type,dialog_cb f,void * param)71 int register_new_dlg_cb(int type, dialog_cb f, void *param)
72 {
73 struct new_dlg_cb *dlg_cb;
74
75 dlg_cb = shm_malloc(sizeof(struct new_dlg_cb));
76 if(dlg_cb == 0) {
77 SHM_MEM_ERROR;
78 return E_OUT_OF_MEM;
79 }
80 dlg_cb->types = type;
81 dlg_cb->callback = f;
82 dlg_cb->param = param;
83 dlg_cb->next = new_dlg_cb_list;
84 new_dlg_cb_list = dlg_cb;
85 return 0;
86 }
87
88
destroy_new_dlg_cbs()89 void destroy_new_dlg_cbs()
90 {
91 struct new_dlg_cb *c;
92 struct new_dlg_cb *n;
93
94 c = new_dlg_cb_list;
95 while(c) {
96 n = c->next;
97 shm_free(c);
98 c = n;
99 }
100 new_dlg_cb_list = 0;
101 }
102
103
run_new_dlg_callbacks(int type,dlg_t * dlg,struct sip_msg * msg)104 static void run_new_dlg_callbacks(int type, dlg_t *dlg, struct sip_msg *msg)
105 {
106 struct new_dlg_cb *c;
107 for(c = new_dlg_cb_list; c; c = c->next) {
108 if(c->types & type)
109 c->callback(type, dlg, msg);
110 }
111 }
112
113
register_dlg_tmcb(int types,dlg_t * dlg,transaction_cb f,void * param)114 int register_dlg_tmcb(int types, dlg_t *dlg, transaction_cb f, void *param)
115 {
116 /* only TMCB_DLG bad TMCB_DESTROY allowed */
117 if((types & (TMCB_DLG | TMCB_DESTROY)) != types) {
118 LM_CRIT("bad types %d\n", types);
119 return E_BUG;
120 }
121 if(f == 0) {
122 LM_CRIT("null callback function\n");
123 return E_BUG;
124 }
125 return insert_tmcb(&dlg->dlg_callbacks, types, f, param, NULL);
126 }
127
128
129 /* per dialog callbacks receive only the transaction, send buffer, destination
130 * and the retr. buff */
run_trans_dlg_callbacks(dlg_t * dlg,struct cell * trans,struct retr_buf * rbuf)131 void run_trans_dlg_callbacks(
132 dlg_t *dlg, struct cell *trans, struct retr_buf *rbuf)
133 {
134 struct tmcb_params params;
135
136 if(dlg->dlg_callbacks.first == 0)
137 return;
138 memset(¶ms, 0, sizeof(params));
139 if(rbuf) {
140 params.t_rbuf = rbuf;
141 params.dst = &rbuf->dst;
142 params.send_buf.s = rbuf->buffer;
143 params.send_buf.len = rbuf->buffer_len;
144 }
145
146 run_trans_callbacks_internal(&dlg->dlg_callbacks, TMCB_DLG, trans, ¶ms);
147 }
148
149 /* TMCB_DESTROY per dialog callbacks */
destroy_trans_dlg_callbacks(dlg_t * dlg)150 static void destroy_trans_dlg_callbacks(dlg_t *dlg)
151 {
152 struct tmcb_params params;
153 struct tm_callback *cbp;
154
155 if((dlg->dlg_callbacks.first == 0)
156 || ((dlg->dlg_callbacks.reg_types & TMCB_DESTROY) == 0))
157 return;
158 memset(¶ms, 0, sizeof(params));
159 for(cbp = (struct tm_callback *)dlg->dlg_callbacks.first; cbp;
160 cbp = cbp->next) {
161 if(cbp->types & TMCB_DESTROY) {
162 params.param = &(cbp->param);
163 cbp->callback(0, 0, ¶ms);
164 }
165 }
166 }
167 #endif /* DIALOG_CALLBACKS */
168
169 /*** Temporary hack ! */
170 /*
171 * This function skips name part
172 * uri parsed by parse_contact must be used
173 * (the uri must not contain any leading or
174 * trailing part and if angle bracket were
175 * used, right angle bracket must be the
176 * last character in the string)
177 *
178 * _s will be modified so it should be a tmp
179 * copy
180 */
get_raw_uri(str * _s)181 void get_raw_uri(str *_s)
182 {
183 char *aq;
184
185 if(_s->s[_s->len - 1] == '>') {
186 aq = find_not_quoted(_s, '<');
187 _s->len -= aq - _s->s + 2;
188 _s->s = aq + 1;
189 }
190 }
191
192
193 /*
194 * Make a copy of a str structure using shm_malloc
195 */
str_duplicate(str * _d,str * _s)196 static inline int str_duplicate(str *_d, str *_s)
197 {
198 _d->s = shm_malloc(_s->len);
199 if(!_d->s) {
200 SHM_MEM_ERROR;
201 return -1;
202 }
203
204 memcpy(_d->s, _s->s, _s->len);
205 _d->len = _s->len;
206 return 0;
207 }
208
209
210 /*
211 * Calculate dialog hooks
212 * @return:
213 * negative : error
214 * 0 : no routes present
215 * F_RB_NH_LOOSE : routes present, next hop is loose router
216 * F_RB_NH_STRICT: next hop is strict.
217 */
calculate_hooks(dlg_t * _d)218 static inline int calculate_hooks(dlg_t *_d)
219 {
220 str *uri;
221 struct sip_uri puri;
222 int nhop;
223
224 /* we might re-calc. some existing hooks =>
225 * reset all the hooks to 0 */
226 memset(&_d->hooks, 0, sizeof(_d->hooks));
227 if(_d->route_set) {
228 uri = &_d->route_set->nameaddr.uri;
229 if(parse_uri(uri->s, uri->len, &puri) < 0) {
230 LM_ERR("error while parsing URI\n");
231 return -1;
232 }
233
234 if(puri.lr.s) {
235 if(_d->rem_target.s)
236 _d->hooks.request_uri = &_d->rem_target;
237 else
238 _d->hooks.request_uri = &_d->rem_uri;
239 _d->hooks.next_hop = &_d->route_set->nameaddr.uri;
240 _d->hooks.first_route = _d->route_set;
241 nhop = F_RB_NH_LOOSE;
242 } else {
243 _d->hooks.request_uri = &_d->route_set->nameaddr.uri;
244 _d->hooks.next_hop = _d->hooks.request_uri;
245 _d->hooks.first_route = _d->route_set->next;
246 if(_d->rem_target.len > 0)
247 _d->hooks.last_route = &_d->rem_target;
248 else
249 _d->hooks.last_route = NULL; /* ? */
250 nhop = F_RB_NH_STRICT;
251 }
252 } else {
253 if(_d->rem_target.s)
254 _d->hooks.request_uri = &_d->rem_target;
255 else
256 _d->hooks.request_uri = &_d->rem_uri;
257
258 if(_d->dst_uri.s)
259 _d->hooks.next_hop = &_d->dst_uri;
260 else
261 _d->hooks.next_hop = _d->hooks.request_uri;
262
263 nhop = 0;
264 /*
265 * the routes in the hooks need to be reset because if the route_set
266 * was dropped somewhere else then these will remain set without the
267 * actual routes existing any more
268 */
269 _d->hooks.first_route = 0;
270 _d->hooks.last_route = 0;
271 }
272
273 if((_d->hooks.request_uri) && (_d->hooks.request_uri->s)
274 && (_d->hooks.request_uri->len)) {
275 _d->hooks.ru.s = _d->hooks.request_uri->s;
276 _d->hooks.ru.len = _d->hooks.request_uri->len;
277 _d->hooks.request_uri = &_d->hooks.ru;
278 get_raw_uri(_d->hooks.request_uri);
279 }
280 if((_d->hooks.next_hop) && (_d->hooks.next_hop->s)
281 && (_d->hooks.next_hop->len)) {
282 _d->hooks.nh.s = _d->hooks.next_hop->s;
283 _d->hooks.nh.len = _d->hooks.next_hop->len;
284 _d->hooks.next_hop = &_d->hooks.nh;
285 get_raw_uri(_d->hooks.next_hop);
286 }
287
288 return nhop;
289 }
290
291 /*
292 * wrapper to calculate_hooks
293 * added by dcm
294 */
w_calculate_hooks(dlg_t * _d)295 int w_calculate_hooks(dlg_t *_d)
296 {
297 return calculate_hooks(_d);
298 }
299
300 /*
301 * Create a new dialog
302 */
new_dlg_uac(str * _cid,str * _ltag,unsigned int _lseq,str * _luri,str * _ruri,dlg_t ** _d)303 int new_dlg_uac(str *_cid, str *_ltag, unsigned int _lseq, str *_luri,
304 str *_ruri, dlg_t **_d)
305 {
306 dlg_t *res;
307 str generated_cid;
308 str generated_ltag;
309
310 if(!_cid) { /* if not given, compute new one */
311 generate_callid(&generated_cid);
312 _cid = &generated_cid;
313 }
314 if(_cid && (!_ltag)) { /* if not given, compute new one */
315 generate_fromtag(&generated_ltag, _cid, _ruri);
316 _ltag = &generated_ltag;
317 }
318 if(_lseq == 0)
319 _lseq = DEFAULT_CSEQ;
320
321 if(!_cid || !_ltag || !_luri || !_ruri || !_d) {
322 LM_ERR("invalid parameter value\n");
323 return -1;
324 }
325
326 res = (dlg_t *)shm_malloc(sizeof(dlg_t));
327 if(res == 0) {
328 SHM_MEM_ERROR;
329 return -2;
330 }
331
332 /* Clear everything */
333 memset(res, 0, sizeof(dlg_t));
334
335 /* Make a copy of Call-ID */
336 if(str_duplicate(&res->id.call_id, _cid) < 0)
337 return -3;
338 /* Make a copy of local tag (usually From tag) */
339 if(str_duplicate(&res->id.loc_tag, _ltag) < 0)
340 return -4;
341 /* Make a copy of local URI (usually From) */
342 if(str_duplicate(&res->loc_uri, _luri) < 0)
343 return -5;
344 /* Make a copy of remote URI (usually To) */
345 if(str_duplicate(&res->rem_uri, _ruri) < 0)
346 return -6;
347 /* Make a copy of local sequence (usually CSeq) */
348 res->loc_seq.value = _lseq;
349 /* And mark it as set */
350 res->loc_seq.is_set = 1;
351
352 *_d = res;
353
354 if(calculate_hooks(*_d) < 0) {
355 LM_ERR("error while calculating hooks\n");
356 /* FIXME: free everything here */
357 shm_free(res);
358 return -2;
359 }
360 #ifdef DIALOG_CALLBACKS
361 run_new_dlg_callbacks(DLG_CB_UAC, res, 0);
362 #endif
363
364 return 0;
365 }
366
367 /**
368 * @brief Store display names into a dialog
369 * @param _d - dialog structure
370 * @param _ldname - local party display name
371 * @param _rdname - remote party dispaly name
372 * @return 0 on success; negative on error
373 */
374
dlg_add_extra(dlg_t * _d,str * _ldname,str * _rdname)375 int dlg_add_extra(dlg_t *_d, str *_ldname, str *_rdname)
376 {
377 if(!_d || !_ldname || !_rdname) {
378 LM_ERR("Invalid parameters\n");
379 return -1;
380 }
381
382 /* Make a copy of local Display Name */
383 if(shm_str_dup(&_d->loc_dname, _ldname) < 0)
384 return -2;
385 /* Make a copy of remote Display Name */
386 if(shm_str_dup(&_d->rem_dname, _rdname) < 0)
387 return -3;
388
389 return 0;
390 }
391
392 /*
393 * Parse Contact header field body and extract URI
394 * Does not parse headers !!
395 */
get_contact_uri(struct sip_msg * _m,str * _uri)396 static inline int get_contact_uri(struct sip_msg *_m, str *_uri)
397 {
398 contact_t *c;
399
400 _uri->len = 0;
401 _uri->s = 0;
402
403 if(!_m->contact)
404 return 1;
405
406 if(parse_contact(_m->contact) < 0) {
407 LM_ERR("error while parsing Contact body\n");
408 return -2;
409 }
410
411 c = ((contact_body_t *)_m->contact->parsed)->contacts;
412
413 if(!c) {
414 LM_ERR("empty body or * contact\n");
415 return -3;
416 }
417
418 _uri->s = c->uri.s;
419 _uri->len = c->uri.len;
420 return 0;
421 }
422
423
424 /*
425 * Extract tag from To header field of a response
426 * Doesn't parse message headers !!
427 */
get_to_tag(struct sip_msg * _m,str * _tag)428 static inline int get_to_tag(struct sip_msg *_m, str *_tag)
429 {
430 if(!_m->to) {
431 LM_ERR("To header field missing\n");
432 return -1;
433 }
434
435 if(get_to(_m)->tag_value.len) {
436 _tag->s = get_to(_m)->tag_value.s;
437 _tag->len = get_to(_m)->tag_value.len;
438 } else {
439 _tag->len = 0;
440 }
441
442 return 0;
443 }
444
445
446 /*
447 * Extract tag from From header field of a request
448 */
get_from_tag(struct sip_msg * _m,str * _tag)449 static inline int get_from_tag(struct sip_msg *_m, str *_tag)
450 {
451 if(parse_from_header(_m) == -1) {
452 LM_ERR("error while parsing From header\n");
453 return -1;
454 }
455
456 if(get_from(_m)->tag_value.len) {
457 _tag->s = get_from(_m)->tag_value.s;
458 _tag->len = get_from(_m)->tag_value.len;
459 } else {
460 _tag->len = 0;
461 }
462
463 return 0;
464 }
465
466
467 /*
468 * Extract Call-ID value
469 * Doesn't parse headers !!
470 */
get_callid(struct sip_msg * _m,str * _cid)471 static inline int get_callid(struct sip_msg *_m, str *_cid)
472 {
473 if(_m->callid == 0) {
474 LM_ERR("Call-ID not found\n");
475 return -1;
476 }
477
478 _cid->s = _m->callid->body.s;
479 _cid->len = _m->callid->body.len;
480 trim(_cid);
481 return 0;
482 }
483
revert_route(rr_t * r)484 static rr_t *revert_route(rr_t *r)
485 {
486 rr_t *a, *b;
487
488 a = NULL;
489
490 while(r) {
491 b = r->next;
492 r->next = a;
493 a = r;
494 r = b;
495 }
496
497 return a;
498 }
499
500 /*
501 * Create a copy of route set either in normal or reverse order
502 */
get_route_set(struct sip_msg * _m,rr_t ** _rs,unsigned char _order)503 static inline int get_route_set(
504 struct sip_msg *_m, rr_t **_rs, unsigned char _order)
505 {
506 struct hdr_field *ptr;
507 rr_t *last, *p, *t;
508
509 last = 0;
510
511 ptr = _m->record_route;
512 while(ptr) {
513 if(ptr->type == HDR_RECORDROUTE_T) {
514 if(parse_rr(ptr) < 0) {
515 LM_ERR("error while parsing Record-Route body\n");
516 goto error;
517 }
518
519 p = (rr_t *)ptr->parsed;
520 if(shm_duplicate_rr(&t, p) < 0) {
521 LM_ERR("error while duplicating rr_t\n");
522 goto error;
523 }
524 if(!*_rs)
525 *_rs = t;
526 if(last)
527 last->next = t;
528 last = t;
529 while(last->next)
530 last = last->next; /* !!! there may be more routes in one hdr field !!! */
531 }
532 ptr = ptr->next;
533 }
534 if((*_rs) && (_order != NORMAL_ORDER)) {
535 /* better to revert the route outside of cycle above */
536 *_rs = revert_route(*_rs);
537 }
538
539 return 0;
540
541 error:
542 shm_free_rr(_rs);
543 return -1;
544 }
545
546 /*
547 * Extract method from CSeq header field
548 */
get_cseq_method(struct sip_msg * _m,str * _method)549 static inline int get_cseq_method(struct sip_msg *_m, str *_method)
550 {
551 if(!_m->cseq && ((parse_headers(_m, HDR_CSEQ_F, 0) == -1) || !_m->cseq)) {
552 LM_ERR("error while parsing CSeq\n");
553 return -1;
554 }
555
556 _method->s = get_cseq(_m)->method.s;
557 _method->len = get_cseq(_m)->method.len;
558 return 0;
559 }
560
561
refresh_dialog_resp(struct sip_msg * _m,target_refresh_t is_target_refresh)562 static inline int refresh_dialog_resp(
563 struct sip_msg *_m, target_refresh_t is_target_refresh)
564 {
565 str method;
566
567 switch(is_target_refresh) {
568 case IS_NOT_TARGET_REFRESH:
569 return 0;
570 case IS_TARGET_REFRESH:
571 return 1;
572 case TARGET_REFRESH_UNKNOWN:
573 if(get_cseq_method(_m, &method) < 0)
574 return 0; /* error */
575 if((method.len == 6) && !memcmp("INVITE", method.s, 6))
576 return 1;
577 else
578 return 0;
579 }
580 return 0;
581 }
582
refresh_dialog_req(struct sip_msg * _m,target_refresh_t is_target_refresh)583 static inline int refresh_dialog_req(
584 struct sip_msg *_m, target_refresh_t is_target_refresh)
585 {
586 switch(is_target_refresh) {
587 case IS_NOT_TARGET_REFRESH:
588 return 0;
589 case IS_TARGET_REFRESH:
590 return 1;
591 case TARGET_REFRESH_UNKNOWN:
592 return (_m->first_line.u.request.method_value == METHOD_INVITE);
593 break;
594 }
595 return 0;
596 }
597
598 /*
599 * Extract all necessary information from a response and put it
600 * in a dialog structure
601 */
response2dlg(struct sip_msg * _m,dlg_t * _d)602 static inline int response2dlg(struct sip_msg *_m, dlg_t *_d)
603 {
604 str contact, rtag;
605
606 /* Parse the whole message, we will need all Record-Route headers */
607 if(parse_headers(_m, HDR_EOH_F, 0) == -1) {
608 LM_ERR("error while parsing headers\n");
609 return -1;
610 }
611
612 if(get_contact_uri(_m, &contact) < 0)
613 return -2;
614 if(_d->rem_target.s) {
615 shm_free(_d->rem_target.s);
616 _d->rem_target.s = 0;
617 _d->rem_target.len = 0;
618 }
619 if(_d->dst_uri.s) {
620 shm_free(_d->dst_uri.s);
621 _d->dst_uri.s = 0;
622 _d->dst_uri.len = 0;
623 }
624 if(contact.len && str_duplicate(&_d->rem_target, &contact) < 0)
625 return -3;
626
627 if(get_to_tag(_m, &rtag) < 0)
628 goto err1;
629 if(rtag.len && str_duplicate(&_d->id.rem_tag, &rtag) < 0)
630 goto err1;
631
632 if(get_route_set(_m, &_d->route_set, REVERSE_ORDER) < 0)
633 goto err2;
634
635 return 0;
636 err2:
637 if(_d->id.rem_tag.s)
638 shm_free(_d->id.rem_tag.s);
639 _d->id.rem_tag.s = 0;
640 _d->id.rem_tag.len = 0;
641
642 err1:
643 if(_d->rem_target.s)
644 shm_free(_d->rem_target.s);
645 _d->rem_target.s = 0;
646 _d->rem_target.len = 0;
647 return -4;
648 }
649
650
651 /*
652 * Handle dialog in DLG_NEW state, we will be processing the
653 * first response
654 */
dlg_new_resp_uac(dlg_t * _d,struct sip_msg * _m)655 static inline int dlg_new_resp_uac(dlg_t *_d, struct sip_msg *_m)
656 {
657 int code;
658 /*
659 * Dialog is in DLG_NEW state, we will copy remote
660 * target URI, remote tag if present, and route-set
661 * if present. And we will transit into DLG_CONFIRMED
662 * if the response was 2xx and to DLG_DESTROYED if the
663 * request was a negative final response.
664 */
665
666 code = _m->first_line.u.reply.statuscode;
667
668 if(code < 200) {
669 /* A provisional response, do nothing, we could
670 * update remote tag and route set but we will do that
671 * for a positive final response anyway and I don't want
672 * bet on presence of these fields in provisional responses
673 *
674 * Send a request to jan@iptel.org if you need to update
675 * the structures here
676 */
677 } else if((code >= 200) && (code < 299)) {
678 /* A final response, update the structures and transit
679 * into DLG_CONFIRMED
680 */
681 if(response2dlg(_m, _d) < 0)
682 return -1;
683 _d->state = DLG_CONFIRMED;
684
685 if(calculate_hooks(_d) < 0) {
686 LM_ERR("error while calculating hooks\n");
687 return -2;
688 }
689 } else {
690 /* A negative final response, mark the dialog as destroyed
691 * Again, I do not update the structures here because it
692 * makes no sense to me, a dialog shouldn't be used after
693 * it is destroyed
694 */
695 _d->state = DLG_DESTROYED;
696 /* Signalize the termination with positive return value */
697 return 1;
698 }
699
700 return 0;
701 }
702
703
704 /*
705 * Handle dialog in DLG_EARLY state, we will be processing either
706 * next provisional response or a final response
707 */
dlg_early_resp_uac(dlg_t * _d,struct sip_msg * _m)708 static inline int dlg_early_resp_uac(dlg_t *_d, struct sip_msg *_m)
709 {
710 int code;
711 code = _m->first_line.u.reply.statuscode;
712
713 if(code < 200) {
714 /* We are in early state already, do nothing */
715 } else if((code >= 200) && (code <= 299)) {
716 /* Warning - we can handle here response for non-initial request (for
717 * example UPDATE within early INVITE/BYE dialog) and move into
718 * confirmed state may be error! But this depends on dialog type... */
719
720 /* Same as in dlg_new_resp_uac */
721 /* A final response, update the structures and transit
722 * into DLG_CONFIRMED
723 */
724 if(response2dlg(_m, _d) < 0)
725 return -1;
726 _d->state = DLG_CONFIRMED;
727
728 if(calculate_hooks(_d) < 0) {
729 LM_ERR("error while calculating hooks\n");
730 return -2;
731 }
732 } else {
733 /* Else terminate the dialog */
734 _d->state = DLG_DESTROYED;
735 /* Signalize the termination with positive return value */
736 return 1;
737 }
738
739 return 0;
740 }
741
742
743 /*
744 * Handle dialog in DLG_CONFIRMED state, we will be processing
745 * a response to a request sent within a dialog
746 */
dlg_confirmed_resp_uac(dlg_t * _d,struct sip_msg * _m,target_refresh_t is_target_refresh)747 static inline int dlg_confirmed_resp_uac(
748 dlg_t *_d, struct sip_msg *_m, target_refresh_t is_target_refresh)
749 {
750 int code;
751 str contact;
752
753 code = _m->first_line.u.reply.statuscode;
754
755 /* Dialog has been already confirmed, that means we received
756 * a response to a request sent within the dialog. We will
757 * update remote target URI if and only if the message sent was
758 * a target refresher.
759 */
760
761 /* IF we receive a 481 response, terminate the dialog because
762 * the remote peer indicated that it didn't have the dialog
763 * state anymore, signal this termination with a positive return
764 * value
765 */
766 if(code == 481) {
767 _d->state = DLG_DESTROYED;
768 return 1;
769 }
770
771 /* Do nothing if not 2xx */
772 if((code < 200) || (code >= 300))
773 return 0;
774
775 if(refresh_dialog_resp(_m, is_target_refresh)) {
776 /* Get contact if any and update remote target */
777 if(parse_headers(_m, HDR_CONTACT_F, 0) == -1) {
778 LM_ERR("error while parsing headers\n");
779 return -2;
780 }
781
782 /* Try to extract contact URI */
783 if(get_contact_uri(_m, &contact) < 0)
784 return -3;
785 /* If there is a contact URI */
786 if(contact.len) {
787 /* Free old remote target and destination uri if any */
788 if(_d->rem_target.s)
789 shm_free(_d->rem_target.s);
790 if(_d->dst_uri.s) {
791 shm_free(_d->dst_uri.s);
792 _d->dst_uri.s = 0;
793 _d->dst_uri.len = 0;
794 }
795
796 /* Duplicate new remote target */
797 if(str_duplicate(&_d->rem_target, &contact) < 0)
798 return -4;
799 }
800
801 if(calculate_hooks(_d) < 0)
802 return -1;
803 }
804
805 return 0;
806 }
807
808
809 /*
810 * A response arrived, update dialog
811 */
dlg_response_uac(dlg_t * _d,struct sip_msg * _m,target_refresh_t is_target_refresh)812 int dlg_response_uac(
813 dlg_t *_d, struct sip_msg *_m, target_refresh_t is_target_refresh)
814 {
815 if(!_d || !_m) {
816 LM_ERR("invalid parameter value\n");
817 return -1;
818 }
819
820 /* The main dispatcher */
821 switch(_d->state) {
822 case DLG_NEW:
823 return dlg_new_resp_uac(_d, _m);
824
825 case DLG_EARLY:
826 return dlg_early_resp_uac(_d, _m);
827
828 case DLG_CONFIRMED:
829 return dlg_confirmed_resp_uac(_d, _m, is_target_refresh);
830
831 case DLG_DESTROYED:
832 LM_DBG("cannot handle destroyed dialog\n");
833 return -2;
834 }
835
836 LM_ERR("Error in switch statement\n");
837 return -3;
838 }
839
840
841 /*
842 * Get CSeq number
843 * Does not parse headers !!
844 */
get_cseq_value(struct sip_msg * _m,unsigned int * _cs)845 static inline int get_cseq_value(struct sip_msg *_m, unsigned int *_cs)
846 {
847 str num;
848
849 if(_m->cseq == 0) {
850 LM_ERR("CSeq header not found\n");
851 return -1;
852 }
853
854 num.s = get_cseq(_m)->number.s;
855 num.len = get_cseq(_m)->number.len;
856
857 trim_leading(&num);
858 if(str2int(&num, _cs) < 0) {
859 LM_ERR("error while converting cseq number\n");
860 return -2;
861 }
862 return 0;
863 }
864
865
866 /*
867 * Copy To or From URI without tag parameter
868 */
get_dlg_uri(struct hdr_field * _h,str * _s)869 static inline int get_dlg_uri(struct hdr_field *_h, str *_s)
870 {
871 struct to_param *ptr, *prev;
872 struct to_body *body;
873 char *tag = 0; /* Makes gcc happy */
874 int tag_len = 0, len;
875
876 if(!_h) {
877 LM_ERR("header field not found\n");
878 return -1;
879 }
880
881 /* From was already parsed when extracting tag
882 * and To is parsed by default
883 */
884
885 body = (struct to_body *)_h->parsed;
886
887 ptr = body->param_lst;
888 prev = 0;
889 while(ptr) {
890 if(ptr->type == TAG_PARAM)
891 break;
892 prev = ptr;
893 ptr = ptr->next;
894 }
895
896 if(ptr) {
897 /* Tag param found */
898 if(prev) {
899 tag = prev->value.s + prev->value.len;
900 } else {
901 tag = body->body.s + body->body.len;
902 }
903
904 if(ptr->next) {
905 tag_len = ptr->value.s + ptr->value.len - tag;
906 } else {
907 tag_len = _h->body.s + _h->body.len - tag;
908 }
909 }
910
911 _s->s = shm_malloc(_h->body.len - tag_len);
912 if(!_s->s) {
913 SHM_MEM_ERROR;
914 return -1;
915 }
916
917 if(tag_len) {
918 len = tag - _h->body.s;
919 memcpy(_s->s, _h->body.s, len);
920 memcpy(_s->s + len, tag + tag_len, _h->body.len - len - tag_len);
921 _s->len = _h->body.len - tag_len;
922 } else {
923 memcpy(_s->s, _h->body.s, _h->body.len);
924 _s->len = _h->body.len;
925 }
926
927 return 0;
928 }
929
930
931 /*
932 * Extract all information from a request
933 * and update a dialog structure
934 */
request2dlg(struct sip_msg * _m,dlg_t * _d)935 static inline int request2dlg(struct sip_msg *_m, dlg_t *_d)
936 {
937 str contact, rtag, callid;
938
939 if(parse_headers(_m, HDR_EOH_F, 0) == -1) {
940 LM_ERR("error while parsing headers\n");
941 return -1;
942 }
943
944 if(get_contact_uri(_m, &contact) < 0)
945 return -2;
946 if(contact.len) {
947 if(_d->rem_target.s)
948 shm_free(_d->rem_target.s);
949 if(_d->dst_uri.s) {
950 shm_free(_d->dst_uri.s);
951 _d->dst_uri.s = 0;
952 _d->dst_uri.len = 0;
953 }
954 if(str_duplicate(&_d->rem_target, &contact) < 0)
955 return -3;
956 }
957
958 if(get_from_tag(_m, &rtag) < 0)
959 goto err1;
960 if(rtag.len && str_duplicate(&_d->id.rem_tag, &rtag) < 0)
961 goto err1;
962
963 if(get_callid(_m, &callid) < 0)
964 goto err2;
965 if(callid.len && str_duplicate(&_d->id.call_id, &callid) < 0)
966 goto err2;
967
968 if(get_cseq_value(_m, &_d->rem_seq.value) < 0)
969 goto err3;
970 _d->rem_seq.is_set = 1;
971
972 if(get_dlg_uri(_m->from, &_d->rem_uri) < 0)
973 goto err3;
974 if(get_dlg_uri(_m->to, &_d->loc_uri) < 0)
975 goto err4;
976
977 if(get_route_set(_m, &_d->route_set, NORMAL_ORDER) < 0)
978 goto err5;
979
980 return 0;
981 err5:
982 if(_d->loc_uri.s)
983 shm_free(_d->loc_uri.s);
984 _d->loc_uri.s = 0;
985 _d->loc_uri.len = 0;
986 err4:
987 if(_d->rem_uri.s)
988 shm_free(_d->rem_uri.s);
989 _d->rem_uri.s = 0;
990 _d->rem_uri.len = 0;
991 err3:
992 if(_d->id.call_id.s)
993 shm_free(_d->id.call_id.s);
994 _d->id.call_id.s = 0;
995 _d->id.call_id.len = 0;
996 err2:
997 if(_d->id.rem_tag.s)
998 shm_free(_d->id.rem_tag.s);
999 _d->id.rem_tag.s = 0;
1000 _d->id.rem_tag.len = 0;
1001 err1:
1002 if(_d->rem_target.s)
1003 shm_free(_d->rem_target.s);
1004 _d->rem_target.s = 0;
1005 _d->rem_target.len = 0;
1006 return -4;
1007 }
1008
1009
1010 /*
1011 * Establishing a new dialog, UAS side
1012 */
new_dlg_uas(struct sip_msg * _req,int _code,dlg_t ** _d)1013 int new_dlg_uas(struct sip_msg *_req, int _code, /*str* _tag,*/ dlg_t **_d)
1014 {
1015 dlg_t *res;
1016 str tag;
1017
1018 if(!_req || /*!_tag ||*/ !_d) {
1019 LM_ERR("invalid parameter value\n");
1020 return -1;
1021 }
1022
1023 if(_code > 299) {
1024 LM_DBG("status code >= 300, no dialog created\n");
1025 }
1026
1027 res = (dlg_t *)shm_malloc(sizeof(dlg_t));
1028 if(res == 0) {
1029 SHM_MEM_ERROR;
1030 return -3;
1031 }
1032 /* Clear everything */
1033 memset(res, 0, sizeof(dlg_t));
1034
1035 if(request2dlg(_req, res) < 0) {
1036 LM_ERR("error while converting request to dialog\n");
1037 free_dlg(res);
1038 return -4;
1039 }
1040
1041 if(_code > 100) {
1042 tag.s = tm_tags;
1043 tag.len = TOTAG_VALUE_LEN;
1044 calc_crc_suffix(_req, tm_tag_suffix);
1045 if(str_duplicate(&res->id.loc_tag, &tag) < 0) {
1046 free_dlg(res);
1047 return -5;
1048 }
1049 }
1050
1051 *_d = res;
1052
1053 if(_code < 100)
1054 (*_d)->state = DLG_NEW;
1055 else if(_code < 200)
1056 (*_d)->state = DLG_EARLY;
1057 else
1058 (*_d)->state = DLG_CONFIRMED;
1059
1060 if(calculate_hooks(*_d) < 0) {
1061 LM_ERR("error while calculating hooks\n");
1062 free_dlg(res);
1063 return -6;
1064 }
1065 #ifdef DIALOG_CALLBACKS
1066 run_new_dlg_callbacks(DLG_CB_UAS, res, _req);
1067 #endif
1068
1069 return 0;
1070 }
1071
1072 /*
1073 * UAS side - update dialog state and to tag
1074 */
update_dlg_uas(dlg_t * _d,int _code,str * _tag)1075 int update_dlg_uas(dlg_t *_d, int _code, str *_tag)
1076 {
1077 if(_d->state == DLG_CONFIRMED) {
1078 LM_ERR("dialog is already confirmed\n");
1079 return -1;
1080 } else if(_d->state == DLG_DESTROYED) {
1081 LM_ERR("dialog is already destroyed\n");
1082 return -2;
1083 }
1084
1085 if(_tag && _tag->s) {
1086 if(_d->id.loc_tag.s) {
1087 if((_tag->len == _d->id.loc_tag.len)
1088 && (!memcmp(_tag->s, _d->id.loc_tag.s, _tag->len))) {
1089 LM_DBG("local tag is already set\n");
1090 } else {
1091 LM_ERR("error trying to rewrite local tag\n");
1092 return -3;
1093 }
1094 } else {
1095 if(str_duplicate(&_d->id.loc_tag, _tag) < 0) {
1096 LM_ERR("not enough memory\n");
1097 return -4;
1098 }
1099 }
1100 }
1101
1102 if((100 < _code) && (_code < 200))
1103 _d->state = DLG_EARLY;
1104 else if(_code < 300)
1105 _d->state = DLG_CONFIRMED;
1106 else
1107 _d->state = DLG_DESTROYED;
1108
1109 return 0;
1110 }
1111
1112 /*
1113 * UAS side - update a dialog from a request
1114 */
dlg_request_uas(dlg_t * _d,struct sip_msg * _m,target_refresh_t is_target_refresh)1115 int dlg_request_uas(
1116 dlg_t *_d, struct sip_msg *_m, target_refresh_t is_target_refresh)
1117 {
1118 str contact;
1119 int cseq;
1120
1121 if(!_d || !_m) {
1122 LM_ERR("invalid parameter value\n");
1123 return -1;
1124 }
1125
1126 /* We must check if the request is not out of order or retransmission
1127 * first, if so then we will not update anything
1128 */
1129 if(parse_headers(_m, HDR_CSEQ_F, 0) == -1) {
1130 LM_ERR("error while parsing headers\n");
1131 return -2;
1132 }
1133 if(get_cseq_value(_m, (unsigned int *)&cseq) < 0)
1134 return -3;
1135 if(_d->rem_seq.is_set && (cseq <= _d->rem_seq.value))
1136 return 0;
1137
1138 /* Neither out of order nor retransmission -> update */
1139 _d->rem_seq.value = cseq;
1140 _d->rem_seq.is_set = 1;
1141
1142 /* We will als update remote target URI if the message
1143 * is target refresher
1144 */
1145 if(refresh_dialog_req(_m, is_target_refresh)) { /* target refresher */
1146 if(parse_headers(_m, HDR_CONTACT_F, 0) == -1) {
1147 LM_ERR("error while parsing headers\n");
1148 return -4;
1149 }
1150
1151 if(get_contact_uri(_m, &contact) < 0)
1152 return -5;
1153 if(contact.len) {
1154 if(_d->rem_target.s)
1155 shm_free(_d->rem_target.s);
1156 if(_d->dst_uri.s) {
1157 shm_free(_d->dst_uri.s);
1158 _d->dst_uri.s = 0;
1159 _d->dst_uri.len = 0;
1160 }
1161 if(str_duplicate(&_d->rem_target, &contact) < 0)
1162 return -6;
1163 }
1164
1165 if(calculate_hooks(_d) < 0)
1166 return -1;
1167 }
1168
1169 return 0;
1170 }
1171
1172
1173 /*
1174 * Calculate length of the route set
1175 */
calculate_routeset_length(dlg_t * _d)1176 int calculate_routeset_length(dlg_t *_d)
1177 {
1178 int len;
1179 rr_t *ptr;
1180
1181 if(!_d->route_set)
1182 return 0;
1183
1184 len = ROUTE_PREFIX_LEN;
1185
1186 for(ptr = _d->hooks.first_route; ptr; ptr = ptr->next) {
1187 len += ptr->len;
1188 len += ROUTE_SEPARATOR_LEN;
1189 }
1190 if(_d->hooks.last_route) {
1191 if(_d->hooks.first_route)
1192 len += ROUTE_SEPARATOR_LEN;
1193 len += _d->hooks.last_route->len + 2; /* < > */
1194 } else {
1195 len -= ROUTE_SEPARATOR_LEN;
1196 }
1197
1198 len += CRLF_LEN;
1199
1200 return len;
1201 }
1202
1203 /*
1204 *
1205 * Print the route set
1206 */
print_routeset(char * buf,dlg_t * _d)1207 char *print_routeset(char *buf, dlg_t *_d)
1208 {
1209 rr_t *ptr;
1210
1211 ptr = _d->hooks.first_route;
1212
1213 if(ptr || _d->hooks.last_route) {
1214 memcpy(buf, ROUTE_PREFIX, ROUTE_PREFIX_LEN);
1215 buf += ROUTE_PREFIX_LEN;
1216 }
1217
1218 while(ptr) {
1219 memcpy(buf, ptr->nameaddr.name.s, ptr->len);
1220 buf += ptr->len;
1221
1222 ptr = ptr->next;
1223 if(ptr) {
1224 memcpy(buf, ROUTE_SEPARATOR, ROUTE_SEPARATOR_LEN);
1225 buf += ROUTE_SEPARATOR_LEN;
1226 }
1227 }
1228
1229 if(_d->hooks.last_route) {
1230 if(_d->hooks.first_route) {
1231 memcpy(buf, ROUTE_SEPARATOR, ROUTE_SEPARATOR_LEN);
1232 buf += ROUTE_SEPARATOR_LEN;
1233 }
1234 memcpy(buf, "<", 1);
1235 buf++;
1236 memcpy(buf, _d->hooks.last_route->s, _d->hooks.last_route->len);
1237 buf += _d->hooks.last_route->len;
1238 *buf = '>';
1239 buf++;
1240 }
1241
1242 if(_d->hooks.first_route || _d->hooks.last_route) {
1243 memcpy(buf, CRLF, CRLF_LEN);
1244 buf += CRLF_LEN;
1245 }
1246
1247 return buf;
1248 }
1249
1250
1251 /*
1252 * Destroy a dialog state
1253 */
free_dlg(dlg_t * _d)1254 void free_dlg(dlg_t *_d)
1255 {
1256 if(!_d)
1257 return;
1258 #ifdef DIALOG_CALLBACKS
1259 destroy_trans_dlg_callbacks(_d);
1260 #endif
1261 if(_d->id.call_id.s)
1262 shm_free(_d->id.call_id.s);
1263 if(_d->id.rem_tag.s)
1264 shm_free(_d->id.rem_tag.s);
1265 if(_d->id.loc_tag.s)
1266 shm_free(_d->id.loc_tag.s);
1267
1268 if(_d->loc_uri.s)
1269 shm_free(_d->loc_uri.s);
1270 if(_d->rem_uri.s)
1271 shm_free(_d->rem_uri.s);
1272 if(_d->rem_target.s)
1273 shm_free(_d->rem_target.s);
1274 if(_d->dst_uri.s)
1275 shm_free(_d->dst_uri.s);
1276
1277 if(_d->loc_dname.s)
1278 shm_free(_d->loc_dname.s);
1279 if(_d->rem_dname.s)
1280 shm_free(_d->rem_dname.s);
1281
1282 /* Free all routes in the route set */
1283 shm_free_rr(&_d->route_set);
1284 shm_free(_d);
1285 }
1286
1287
1288 /*
1289 * Print a dialog structure, just for debugging
1290 */
print_dlg(FILE * out,dlg_t * _d)1291 void print_dlg(FILE *out, dlg_t *_d)
1292 {
1293 fprintf(out, "====dlg_t===\n");
1294 fprintf(out, "id.call_id : '%.*s'\n", _d->id.call_id.len,
1295 _d->id.call_id.s);
1296 fprintf(out, "id.rem_tag : '%.*s'\n", _d->id.rem_tag.len,
1297 _d->id.rem_tag.s);
1298 fprintf(out, "id.loc_tag : '%.*s'\n", _d->id.loc_tag.len,
1299 _d->id.loc_tag.s);
1300 fprintf(out, "loc_seq.value : %d\n", _d->loc_seq.value);
1301 fprintf(out, "loc_seq.is_set: %s\n", _d->loc_seq.is_set ? "YES" : "NO");
1302 fprintf(out, "rem_seq.value : %d\n", _d->rem_seq.value);
1303 fprintf(out, "rem_seq.is_set: %s\n", _d->rem_seq.is_set ? "YES" : "NO");
1304 fprintf(out, "loc_uri : '%.*s'\n", _d->loc_uri.len, _d->loc_uri.s);
1305 fprintf(out, "rem_uri : '%.*s'\n", _d->rem_uri.len, _d->rem_uri.s);
1306 fprintf(out, "rem_target : '%.*s'\n", _d->rem_target.len,
1307 _d->rem_target.s);
1308 fprintf(out, "dst_uri : '%.*s'\n", _d->dst_uri.len, _d->dst_uri.s);
1309 fprintf(out, "secure: : %d\n", _d->secure);
1310 fprintf(out, "state : ");
1311 switch(_d->state) {
1312 case DLG_NEW:
1313 fprintf(out, "DLG_NEW\n");
1314 break;
1315 case DLG_EARLY:
1316 fprintf(out, "DLG_EARLY\n");
1317 break;
1318 case DLG_CONFIRMED:
1319 fprintf(out, "DLG_CONFIRMED\n");
1320 break;
1321 case DLG_DESTROYED:
1322 fprintf(out, "DLG_DESTROYED\n");
1323 break;
1324 }
1325 print_rr(out, _d->route_set);
1326 if(_d->hooks.request_uri)
1327 fprintf(out, "hooks.request_uri: '%.*s'\n", _d->hooks.request_uri->len,
1328 _d->hooks.request_uri->s);
1329 if(_d->hooks.next_hop)
1330 fprintf(out, "hooks.next_hop : '%.*s'\n", _d->hooks.next_hop->len,
1331 _d->hooks.next_hop->s);
1332 if(_d->hooks.first_route)
1333 fprintf(out, "hooks.first_route: '%.*s'\n", _d->hooks.first_route->len,
1334 _d->hooks.first_route->nameaddr.name.s);
1335 if(_d->hooks.last_route)
1336 fprintf(out, "hooks.last_route : '%.*s'\n", _d->hooks.last_route->len,
1337 _d->hooks.last_route->s);
1338
1339 fprintf(out, "====dlg_t====\n");
1340 }
1341
1342 /*
1343 * set dialog's request uri and destination uri (optional)
1344 */
set_dlg_target(dlg_t * _d,str * _ruri,str * _duri)1345 int set_dlg_target(dlg_t *_d, str *_ruri, str *_duri)
1346 {
1347
1348 if(!_d || !_ruri) {
1349 LM_ERR("invalid parameter value\n");
1350 return -1;
1351 }
1352
1353 if(_d->rem_target.s)
1354 shm_free(_d->rem_target.s);
1355 if(_d->dst_uri.s) {
1356 shm_free(_d->dst_uri.s);
1357 _d->dst_uri.s = 0;
1358 _d->dst_uri.len = 0;
1359 }
1360
1361 if(str_duplicate(&_d->rem_target, _ruri))
1362 return -1;
1363 if(_duri && _duri->len) {
1364 if(str_duplicate(&_d->dst_uri, _duri))
1365 return -1;
1366 }
1367
1368 if(calculate_hooks(_d) < 0) {
1369 LM_ERR("error while calculating hooks\n");
1370 return -1;
1371 }
1372
1373 return 0;
1374 }
1375