- dialog support added
[sip-router] / modules / tm / dlg.c
1 /*
2  * $Id$
3  *
4  * Copyright (C) 2001-2003 Fhg Fokus
5  *
6  * This file is part of ser, a free SIP server.
7  *
8  * ser is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version
12  *
13  * For a license to use the ser software under conditions
14  * other than those described here, or to purchase support for this
15  * software, please contact iptel.org by e-mail at the following addresses:
16  *   info@iptel.org
17  *
18  * ser is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26  *
27  * History:
28  * -------
29  * 2003-03-29 Created by janakj
30  */
31
32
33 #include <string.h>
34 #include "../../mem/shm_mem.h"
35 #include "../../dprint.h"
36 #include "../../parser/contact/parse_contact.h"
37 #include "../../parser/parse_to.h"
38 #include "../../parser/parse_from.h"
39 #include "../../parser/parse_uri.h"
40 #include "../../trim.h"
41 #include "../../ut.h"
42 #include "../../config.h"
43 #include "dlg.h"
44 #include "t_reply.h"
45 #include "../../parser/parser_f.h"
46
47
48 #define NORMAL_ORDER 0  /* Create route set in normal order - UAS */
49 #define REVERSE_ORDER 1 /* Create route set in reverse order - UAC */
50
51 #define ROUTE_PREFIX "Route: "
52 #define ROUTE_PREFIX_LEN (sizeof(ROUTE_PREFIX) - 1)
53
54 #define ROUTE_SEPARATOR "," CRLF "       "
55 #define ROUTE_SEPARATOR_LEN (sizeof(ROUTE_SEPARATOR) - 1)
56
57
58 /*** Temporary hack ! */
59 /*
60  * This function skips name part
61  * uri parsed by parse_contact must be used
62  * (the uri must not contain any leading or
63  *  trailing part and if angle bracket were
64  *  used, right angle bracket must be the
65  *  last character in the string)
66  *
67  * _s will be modified so it should be a tmp
68  * copy
69  */
70 void get_raw_uri(str* _s)
71 {
72         char* aq;
73         
74         if (_s->s[_s->len - 1] == '>') {
75                 aq = find_not_quoted(_s, '<');
76                 _s->len -= aq - _s->s + 2;
77                 _s->s = aq + 1;
78         }
79 }
80
81
82
83 /*
84  * Make a copy of a str structure using shm_malloc
85  */
86 static inline int str_duplicate(str* _d, str* _s)
87 {
88         _d->s = shm_malloc(_s->len);
89         if (!_d->s) {
90                 LOG(L_ERR, "str_duplicate(): No memory left\n");
91                 return -1;
92         }
93         
94         memcpy(_d->s, _s->s, _s->len);
95         _d->len = _s->len;
96         return 0;
97 }
98
99
100 /*
101  * Calculate dialog hooks
102  */
103 static inline int calculate_hooks(dlg_t* _d)
104 {
105         str* uri;
106         struct sip_uri puri;
107         param_hooks_t hooks;
108         param_t* params;
109
110         if (_d->route_set) {
111                 uri = &_d->route_set->nameaddr.uri;
112                 if (parse_uri(uri->s, uri->len, &puri) < 0) {
113                         LOG(L_ERR, "calculate_hooks(): Error while parsing URI\n");
114                         return -1;
115                 }
116
117                 if (parse_params(&puri.params, CLASS_URI, &hooks, &params) < 0) {
118                         LOG(L_ERR, "calculate_hooks(): Error while parsing parameters\n");
119                         return -2;
120                 }
121                 free_params(params);
122                 
123                 if (hooks.uri.lr) {
124                         if (_d->rem_target.s) _d->hooks.request_uri = &_d->rem_target;
125                         else _d->hooks.request_uri = &_d->rem_uri;
126                         _d->hooks.next_hop = &_d->route_set->nameaddr.uri;
127                         _d->hooks.first_route = _d->route_set;
128                 } else {
129                         _d->hooks.request_uri = &_d->route_set->nameaddr.uri;
130                         _d->hooks.next_hop = _d->hooks.request_uri;
131                         _d->hooks.first_route = _d->route_set->next;
132                         _d->hooks.last_route = &_d->rem_target;
133                 }
134         } else {
135                 if (_d->rem_target.s) _d->hooks.request_uri = &_d->rem_target;
136                 else _d->hooks.request_uri = &_d->rem_uri;
137                 _d->hooks.next_hop = _d->hooks.request_uri;
138         }
139
140         if ((_d->hooks.request_uri) && (_d->hooks.request_uri->s) && (_d->hooks.request_uri->len)) {
141                 _d->hooks.ru.s = _d->hooks.request_uri->s;
142                 _d->hooks.ru.len = _d->hooks.request_uri->len;
143                 _d->hooks.request_uri = &_d->hooks.ru;
144                 get_raw_uri(_d->hooks.request_uri);
145         }
146         if ((_d->hooks.next_hop) && (_d->hooks.next_hop->s) && (_d->hooks.next_hop->len)) {
147                 _d->hooks.nh.s = _d->hooks.next_hop->s;
148                 _d->hooks.nh.len = _d->hooks.next_hop->len;
149                 _d->hooks.next_hop = &_d->hooks.nh;
150                 get_raw_uri(_d->hooks.next_hop);
151         }
152
153         return 0;
154 }
155
156
157 /*
158  * Create a new dialog
159  */
160 int new_dlg_uac(str* _cid, str* _ltag, unsigned int _lseq, str* _luri, str* _ruri, dlg_t** _d)
161 {
162         dlg_t* res;
163
164         if (!_cid || !_ltag || !_luri || !_ruri || !_d) {
165                 LOG(L_ERR, "new_dlg_uac(): Invalid parameter value\n");
166                 return -1;
167         }
168
169         res = (dlg_t*)shm_malloc(sizeof(dlg_t));
170         if (res == 0) {
171                 LOG(L_ERR, "new_dlg_uac(): No memory left\n");
172                 return -2;
173         }
174              /* Clear everything */
175         memset(res, 0, sizeof(dlg_t));
176         
177              /* Make a copy of Call-ID */
178         if (str_duplicate(&res->id.call_id, _cid) < 0) return -3;
179              /* Make a copy of local tag (usually From tag) */
180         if (str_duplicate(&res->id.loc_tag, _ltag) < 0) return -4;
181              /* Make a copy of local URI (usually From) */
182         if (str_duplicate(&res->loc_uri, _luri) < 0) return -5;
183              /* Make a copy of remote URI (usually To) */
184         if (str_duplicate(&res->rem_uri, _ruri) < 0) return -6;
185              /* Make a copy of local sequence (usually CSeq) */
186         res->loc_seq.value = _lseq;
187              /* And mark it as set */
188         res->loc_seq.is_set = 1;
189
190         *_d = res;
191
192         if (calculate_hooks(*_d) < 0) {
193                 LOG(L_ERR, "new_dlg_uac(): Error while calculating hooks\n");
194                 shm_free(res);
195                 return -2;
196         }
197
198         return 0;
199 }
200
201
202 /*
203  * Parse Contact header field body and extract URI
204  * Does not parse headers !!
205  */
206 static inline int get_contact_uri(struct sip_msg* _m, str* _uri)
207 {
208         contact_t* c;
209
210         _uri->len = 0;
211
212         if (!_m->contact) return 0;
213
214         if (parse_contact(_m->contact) < 0) {
215                 LOG(L_ERR, "get_contact_uri(): Error while parsing Contact body\n");
216                 return -2;
217         }
218
219         c = ((contact_body_t*)_m->contact->parsed)->contacts;
220
221         if (!c) {
222                 LOG(L_ERR, "get_contact_uri(): Empty body or * contact\n");
223                 return -3;
224         }
225
226              /* FIXME: c->uri may contain name-addr !! */
227         _uri->s = c->uri.s;
228         _uri->len = c->uri.len;
229         return 0;
230 }
231
232
233 /*
234  * Extract tag from To header field of a response
235  * Doesn't parse message headers !!
236  */
237 static inline int get_to_tag(struct sip_msg* _m, str* _tag)
238 {
239         if (!_m->to) {
240                 LOG(L_ERR, "get_to_tag(): To header field missing\n");
241                 return -1;
242         }
243
244         if (get_to(_m)->tag_value.len) {
245                 _tag->s = get_to(_m)->tag_value.s;
246                 _tag->len = get_to(_m)->tag_value.len;
247         } else {
248                 _tag->len = 0;
249         }
250
251         return 0;
252 }
253
254
255 /*
256  * Extract tag from From header field of a request
257  */
258 static inline int get_from_tag(struct sip_msg* _m, str* _tag)
259 {
260         if (parse_from_header(_m) == -1) {
261                 LOG(L_ERR, "get_from_tag(): Error while parsing From header\n");
262                 return -1;
263         }
264
265         if (get_from(_m)->tag_value.len) {
266                 _tag->s = get_from(_m)->tag_value.s;
267                 _tag->len = get_from(_m)->tag_value.len;
268         } else {
269                 _tag->len = 0;
270         }
271
272         return 0;
273 }
274
275
276 /*
277  * Extract Call-ID value
278  * Doesn't parse headers !!
279  */
280 static inline int get_callid(struct sip_msg* _m, str* _cid)
281 {
282         if (_m->callid == 0) {
283                 LOG(L_ERR, "get_callid(): Call-ID not found\n");
284                 return -1;
285         }
286
287         _cid->s = _m->callid->body.s;
288         _cid->len = _m->callid->body.len;
289         trim(_cid);
290         return 0;
291 }
292
293
294 /*
295  * Create a copy of route set either in normal or reverse order
296  */
297 static inline int get_route_set(struct sip_msg* _m, rr_t** _rs, unsigned char _order)
298 {
299         struct hdr_field* ptr;
300         rr_t* last, *p, *t;
301         
302         last = 0;
303
304         ptr = _m->record_route;
305         while(ptr) {
306                 if (ptr->type == HDR_RECORDROUTE) {
307                         if (parse_rr(ptr) < 0) {
308                                 LOG(L_ERR, "get_route_set(): Error while parsing Record-Route body\n");
309                                 goto error;
310                         }
311
312                         p = (rr_t*)ptr->parsed;
313                         while(p) {
314                                 if (shm_duplicate_rr(_m, &t, p) < 0) {
315                                         LOG(L_ERR, "get_route_set(): Error while duplicating rr_t\n");
316                                         goto error;
317                                 }
318                                 if (_order == NORMAL_ORDER) {
319                                         if (!*_rs) *_rs = t;
320                                         if (last) last->next = t;
321                                         last = t;
322                                 } else {
323                                         t->next = *_rs;
324                                         *_rs = t;
325                                 }
326
327                                 p = p->next;
328                         }
329                         
330                 }
331                 ptr = ptr->next;
332         }
333         
334         return 0;
335
336  error:
337         shm_free_rr(_rs);
338         return -1;
339 }
340
341
342 /*
343  * Extract all necessarry information from a response and put it
344  * in a dialog structure
345  */
346 static inline int response2dlg(struct sip_msg* _m, dlg_t* _d)
347 {
348         str contact, rtag;
349
350              /* Parse the whole message, we will need all Record-Route headers */
351         if (parse_headers(_m, HDR_EOH, 0) == -1) {
352                 LOG(L_ERR, "response2dlg(): Error while parsing headers\n");
353                 return -1;
354         }
355         
356         if (get_contact_uri(_m, &contact) < 0) return -2;
357         if (contact.len && str_duplicate(&_d->rem_target, &contact) < 0) return -3;
358         
359         if (get_to_tag(_m, &rtag) < 0) goto err1;
360         if (rtag.len && str_duplicate(&_d->id.rem_tag, &rtag) < 0) goto err1;
361         
362         if (get_route_set(_m, &_d->route_set, REVERSE_ORDER) < 0) goto err2;
363
364         return 0;
365  err2:
366         if (_d->id.rem_tag.s) shm_free(_d->id.rem_tag.s);
367         _d->id.rem_tag.s = 0;
368         _d->id.rem_tag.len = 0;
369
370  err1:
371         if (_d->rem_target.s) shm_free(_d->rem_target.s);
372         _d->rem_target.s = 0;
373         _d->rem_target.len = 0;
374         return -4;
375 }
376
377
378 /*
379  * Handle dialog in DLG_NEW state, we will be processing the
380  * first response
381  */
382 static inline int dlg_new_resp_uac(dlg_t* _d, struct sip_msg* _m)
383 {
384         int code;
385              /*
386               * Dialog is in DLG_NEW state, we will copy remote
387               * target URI, remote tag if present, and route-set 
388               * if present. And we will transit into DLG_CONFIRMED 
389               * if the response was 2xx and to DLG_DESTROYED if the 
390               * request was a negative final response.
391               */
392
393         code = _m->first_line.u.reply.statuscode;
394
395         if (code < 200) {
396                      /* A provisional response, do nothing, we could
397                       * update remote tag and route set but we will do that
398                       * for a positive final response anyway and I don't want
399                       * bet on presence of these fields in provisional responses
400                       *
401                       * Send a request to jan@iptel.org if you need to update
402                       * the structures here
403                       */
404         } else if ((code >= 200) && (code < 299)) {
405                      /* A final response, update the structures and transit
406                       * into DLG_CONFIRMED
407                       */
408                 if (response2dlg(_m, _d) < 0) return -1;
409                 _d->state = DLG_CONFIRMED;
410
411                 if (calculate_hooks(_d) < 0) {
412                         LOG(L_ERR, "dlg_new_resp_uac(): Error while calculating hooks\n");
413                         return -2;
414                 }
415         } else {
416                      /* 
417                       * A negative final response, mark the dialog as destroyed
418                       * Again, I do not update the structures here becuase it
419                       * makes no sense to me, a dialog shouldn't be used after
420                       * it is destroyed
421                       */
422                 _d->state = DLG_DESTROYED;
423                      /* Signalize the termination with positive return value */
424                 return 1;
425         }
426
427         return 0;
428 }
429
430
431 /*
432  * Handle dialog in DLG_EARLY state, we will be processing either
433  * next provisional response or a final response
434  */
435 static inline int dlg_early_resp_uac(dlg_t* _d, struct sip_msg* _m)
436 {
437         int code;
438         code = _m->first_line.u.reply.statuscode;       
439
440         if (code < 200) {
441                      /* We are in early state already, do nothing
442                       */
443         } else if ((code >= 200) && (code <= 299)) {
444                      /* Same as in dlg_new_resp_uac */
445                      /* A final response, update the structures and transit
446                       * into DLG_CONFIRMED
447                       */
448                 if (response2dlg(_m, _d) < 0) return -1;
449                 _d->state = DLG_CONFIRMED;
450
451                 if (calculate_hooks(_d) < 0) {
452                         LOG(L_ERR, "dlg_early_resp_uac(): Error while calculating hooks\n");
453                         return -2;
454                 }
455         } else {
456                      /* Else terminate the dialog */
457                 _d->state = DLG_DESTROYED;
458                      /* Signalize the termination with positive return value */
459                 return 1;
460         }
461
462         return 0;
463 }
464
465
466 /*
467  * Extract method from CSeq header field
468  */
469 static inline int get_cseq_method(struct sip_msg* _m, str* _method)
470 {
471         if (!_m->cseq && ((parse_headers(_m, HDR_CSEQ, 0) == -1) || !_m->cseq)) {
472                 LOG(L_ERR, "get_cseq_method(): Error while parsing CSeq\n");
473                 return -1;
474         }
475
476         _method->s = get_cseq(_m)->method.s;
477         _method->len = get_cseq(_m)->method.len;
478         return 0;
479 }
480
481
482 /*
483  * Handle dialog in DLG_CONFIRMED state, we will be processing
484  * a response to a request sent within a dialog
485  */
486 static inline int dlg_confirmed_resp_uac(dlg_t* _d, struct sip_msg* _m)
487 {
488         int code;
489         str method, contact;
490
491         code = _m->first_line.u.reply.statuscode;       
492
493              /* Dialog has been already confirmed, that means we received
494               * a response to a request sent within the dialog. We will
495               * update remote target URI if and only if the message sent was
496               * a target refresher. 
497               */
498
499              /* FIXME: Currently we support only INVITEs as target refreshers,
500               * this should be generalized
501               */
502
503              /* IF we receive a 481 response, terminate the dialog because
504               * the remote peer indicated that it didn't have the dialog
505               * state anymore, signal this termination with a positive return
506               * value
507               */
508         if (code == 481) {
509                 _d->state = DLG_DESTROYED;
510                 return 1;
511         }
512
513              /* Do nothing if not 2xx */
514         if ((code < 200) || (code >= 300)) return 0;
515         
516         if (get_cseq_method(_m, &method) < 0) return -1;
517         if ((method.len == 6) && !memcmp("INVITE", method.s, 6)) {
518                      /* Get contact if any and update remote target */
519                 if (parse_headers(_m, HDR_CONTACT, 0) == -1) {
520                         LOG(L_ERR, "dlg_confirmed_resp_uac(): Error while parsing headers\n");
521                         return -2;
522                 }
523
524                      /* Try to extract contact URI */
525                 if (get_contact_uri(_m, &contact) < 0) return -3;
526                      /* If there is a contact URI */
527                 if (contact.len) {
528                              /* Free old remote target if any */
529                         if (_d->rem_target.s) shm_free(_d->rem_target.s);
530                              /* Duplicate new remote target */
531                         if (str_duplicate(&_d->rem_target, &contact) < 0) return -4;
532                 }
533         }
534
535         return 0;
536 }
537
538
539 /*
540  * A response arrived, update dialog
541  */
542 int dlg_response_uac(dlg_t* _d, struct sip_msg* _m)
543 {
544         if (!_d || !_m) {
545                 LOG(L_ERR, "dlg_response_uac(): Invalid parameter value\n");
546                 return -1;
547         }
548
549              /* The main dispatcher */
550         switch(_d->state) {
551         case DLG_NEW:       
552                 return dlg_new_resp_uac(_d, _m);
553
554         case DLG_EARLY:     
555                 return dlg_early_resp_uac(_d, _m);
556
557         case DLG_CONFIRMED: 
558                 return dlg_confirmed_resp_uac(_d, _m);
559
560         case DLG_DESTROYED:
561                 LOG(L_ERR, "dlg_response_uac(): Cannot handle destroyed dialog\n");
562                 return -2;
563         }
564
565         LOG(L_ERR, "dlg_response_uac(): Error in switch statement\n");
566         return -3;
567 }
568
569
570 /*
571  * Get CSeq number
572  * Does not parse headers !!
573  */
574 static inline int get_cseq_value(struct sip_msg* _m, unsigned int* _cs)
575 {
576         str num;
577
578         if (_m->cseq == 0) {
579                 LOG(L_ERR, "get_cseq_value(): CSeq header not found\n");
580                 return -1;
581         }
582
583         num.s = get_cseq(_m)->number.s;
584         num.len = get_cseq(_m)->number.len;
585
586         trim_leading(&num);
587         if (str2int(&num, _cs) < 0) {
588                 LOG(L_ERR, "get_cseq_value(): Error while converting cseq number\n");
589                 return -2;
590         }
591         return 0;
592 }
593
594
595 /*
596  * Copy To or From URI without tag parameter
597  */
598 static inline int get_dlg_uri(struct hdr_field* _h, str* _s)
599 {
600         struct to_param* ptr, *prev;
601         struct to_body* body;
602         char* tag = 0; /* Makes gcc happy */
603         int tag_len = 0, len;
604
605         if (!_h) {
606                 LOG(L_ERR, "get_dlg_uri(): Header field not found\n");
607                 return -1;
608         }
609
610              /* From was already parsed when extracting tag
611               * and To is parsed by default
612               */
613         
614         body = (struct to_body*)_h->parsed;
615
616         ptr = body->param_lst;
617         prev = 0;
618         while(ptr) {
619                 if (ptr->type == TAG_PARAM) break;
620                 prev = ptr;
621                 ptr = ptr->next;
622         }
623
624         if (ptr) {
625                      /* Tag param found */
626                 if (prev) {
627                         tag = prev->value.s + prev->value.len;
628                 } else {
629                         tag = body->body.s + body->body.len;
630                 }
631                 
632                 if (ptr->next) {
633                         tag_len = ptr->next->name.s - tag;
634                 } else {
635                         tag_len = _h->body.s + _h->body.len - tag;
636                 }
637         }
638
639         _s->s = shm_malloc(_h->body.len - tag_len);
640         if (!_s->s) {
641                 LOG(L_ERR, "get_dlg_uri(): No memory left\n");
642                 return -1;
643         }
644
645         if (tag_len) {
646                 len = tag - _h->body.s;
647                 memcpy(_s->s, _h->body.s, len);
648                 memcpy(_s->s + len, tag + tag_len, _h->body.len - len - tag_len);
649                 _s->len = _h->body.len - tag_len;
650         } else {
651                 memcpy(_s->s, _h->body.s, _h->body.len);
652                 _s->len = _h->body.len;
653         }
654
655         return 0;
656 }
657
658
659 /*
660  * Extract all information from a request 
661  * and update a dialog structure
662  */
663 static inline int request2dlg(struct sip_msg* _m, dlg_t* _d)
664 {
665         str contact, rtag, callid;
666
667         if (parse_headers(_m, HDR_EOH, 0) == -1) {
668                 LOG(L_ERR, "request2dlg(): Error while parsing headers");
669                 return -1;
670         }
671
672         if (get_contact_uri(_m, &contact) < 0) return -2;
673         if (contact.len && str_duplicate(&_d->rem_target, &contact) < 0) return -3;
674         
675         if (get_from_tag(_m, &rtag) < 0) goto err1;
676         if (rtag.len && str_duplicate(&_d->id.rem_tag, &rtag) < 0) goto err1;
677
678         if (get_callid(_m, &callid) < 0) goto err2;
679         if (callid.len && str_duplicate(&_d->id.call_id, &callid) < 0) goto err2;
680
681         if (get_cseq_value(_m, &_d->rem_seq.value) < 0) goto err3;
682         _d->rem_seq.is_set = 1;
683
684         if (get_dlg_uri(_m->from, &_d->rem_uri) < 0) goto err3;
685         if (get_dlg_uri(_m->to, &_d->loc_uri) < 0) goto err4;
686
687         if (get_route_set(_m, &_d->route_set, NORMAL_ORDER) < 0) goto err5;     
688
689         return 0;
690  err5:
691         if (_d->loc_uri.s) shm_free(_d->loc_uri.s);
692         _d->loc_uri.s = 0;
693         _d->loc_uri.len = 0;
694  err4:
695         if (_d->rem_uri.s) shm_free(_d->rem_uri.s);
696         _d->rem_uri.s = 0;
697         _d->rem_uri.len = 0;
698  err3:
699         if (_d->id.call_id.s) shm_free(_d->id.call_id.s);
700         _d->id.call_id.s = 0;
701         _d->id.call_id.len = 0;
702  err2:
703         if (_d->id.rem_tag.s) shm_free(_d->id.rem_tag.s);
704         _d->id.rem_tag.s = 0;
705         _d->id.rem_tag.len = 0;
706  err1:
707         if (_d->rem_target.s) shm_free(_d->rem_target.s);
708         _d->rem_target.s = 0;
709         _d->rem_target.len = 0;
710         return -4;
711 }
712
713
714 /*
715  * Establishing a new dialog, UAS side
716  */
717 int new_dlg_uas(struct sip_msg* _req, int _code, /*str* _tag,*/ dlg_t** _d)
718 {
719         dlg_t* res;
720         str tag;
721
722         if (!_req || /*!_tag ||*/ !_d) {
723                 LOG(L_ERR, "new_dlg_uas(): Invalid parameter value\n");
724                 return -1;
725         }
726
727         if ((_code < 200) || (_code > 299)) {
728                 DBG("new_dlg_uas(): Not a 2xx, no dialog created\n");
729                 return -2;
730         }
731
732         res = (dlg_t*)shm_malloc(sizeof(dlg_t));
733         if (res == 0) {
734                 LOG(L_ERR, "new_dlg_uac(): No memory left\n");
735                 return -3;
736         }
737              /* Clear everything */
738         memset(res, 0, sizeof(dlg_t));  
739
740         if (request2dlg(_req, res) < 0) {
741                 LOG(L_ERR, "new_dlg_uas(): Error while converting request to dialog\n");
742                 return -4;
743         }
744
745         tag.s = tm_tags;
746         tag.len = TOTAG_VALUE_LEN;
747         calc_crc_suffix(_req, tm_tag_suffix);
748         if (str_duplicate(&res->id.loc_tag, &tag) < 0) {
749                 free_dlg(res);
750                 return -5;
751         }
752         
753         *_d = res;
754
755         (*_d)->state = DLG_CONFIRMED;
756         if (calculate_hooks(*_d) < 0) {
757                 LOG(L_ERR, "new_dlg_uas(): Error while calculating hooks\n");
758                 shm_free(*_d);
759                 return -6;
760         }
761
762         return 0;
763 }
764
765
766 /*
767  * UAS side - update a dialog from a request
768  */
769 int dlg_request_uas(dlg_t* _d, struct sip_msg* _m)
770 {
771         str contact;
772         int cseq;
773
774         if (!_d || !_m) {
775                 LOG(L_ERR, "dlg_request_uas(): Invalid parameter value\n");
776                 return -1;
777         }
778
779              /* We must check if the request is not out of order or retransmission
780               * first, if so then we will not update anything
781               */
782         if (parse_headers(_m, HDR_CSEQ, 0) == -1) {
783                 LOG(L_ERR, "dlg_request_uas(): Error while parsing headers\n");
784                 return -2;
785         }
786         if (get_cseq_value(_m, &cseq) < 0) return -3;
787         if (_d->rem_seq.is_set && (cseq <= _d->rem_seq.value)) return 0;
788
789              /* Neither out of order nor retransmission -> update */
790         _d->rem_seq.value = cseq;
791         _d->rem_seq.is_set = 1;
792         
793              /* We will als update remote target URI if the message 
794               * is target refresher
795               */
796         if (_m->first_line.u.request.method_value == METHOD_INVITE) {
797                      /* target refresher */
798                 if (parse_headers(_m, HDR_CONTACT, 0) == -1) {
799                         LOG(L_ERR, "dlg_request_uas(): Error while parsing headers\n");
800                         return -4;
801                 }
802                 
803                 if (get_contact_uri(_m, &contact) < 0) return -5;
804                 if (contact.len) {
805                         if (_d->rem_target.s) shm_free(_d->rem_target.s);
806                         if (str_duplicate(&_d->rem_target, &contact) < 0) return -6;
807                 }
808         }
809
810         return 0;
811 }
812
813
814 /*
815  * Calculate length of the route set
816  */
817 int calculate_routeset_length(dlg_t* _d)
818 {
819         int len;
820         rr_t* ptr;
821
822         len = 0;
823         ptr = _d->hooks.first_route;
824
825         if (ptr) {
826                 len = ROUTE_PREFIX_LEN;
827                 len += CRLF_LEN;
828         }
829
830         while(ptr) {
831                 len += ptr->len;
832                 ptr = ptr->next;
833                 if (ptr) len += ROUTE_SEPARATOR_LEN;
834         } 
835
836         if (_d->hooks.last_route) {
837                 len += ROUTE_SEPARATOR_LEN + 2; /* < > */
838                 len += _d->hooks.last_route->len;
839         }
840
841         return len;
842 }
843
844
845 /*
846  *
847  * Print the route set
848  */
849 char* print_routeset(char* buf, dlg_t* _d)
850 {
851         rr_t* ptr;
852
853         ptr = _d->hooks.first_route;
854
855         if (ptr) {
856                 memcpy(buf, ROUTE_PREFIX, ROUTE_PREFIX_LEN);
857                 buf += ROUTE_PREFIX_LEN;
858         }
859
860         while(ptr) {
861                 memcpy(buf, ptr->nameaddr.name.s, ptr->len);
862                 buf += ptr->len;
863
864                 ptr = ptr->next;
865                 if (ptr) {
866                         memcpy(buf, ROUTE_SEPARATOR, ROUTE_SEPARATOR_LEN);
867                         buf += ROUTE_SEPARATOR_LEN;
868                 }
869         } 
870
871         if (_d->hooks.last_route) {
872                 memcpy(buf, ROUTE_SEPARATOR "<", ROUTE_SEPARATOR_LEN + 1);
873                 buf += ROUTE_SEPARATOR_LEN + 1;
874                 memcpy(buf, _d->hooks.last_route->s, _d->hooks.last_route->len);
875                 buf += _d->hooks.last_route->len;
876                 *buf = '>';
877                 buf++;
878         }
879
880         if (_d->hooks.first_route) {
881                 memcpy(buf, CRLF, CRLF_LEN);
882                 buf += CRLF_LEN;
883         }
884
885         return buf;
886 }
887
888
889 /*
890  * Destroy a dialog state
891  */
892 void free_dlg(dlg_t* _d)
893 {
894         if (!_d) return;
895
896         if (_d->id.call_id.s) shm_free(_d->id.call_id.s);
897         if (_d->id.rem_tag.s) shm_free(_d->id.rem_tag.s);
898         if (_d->id.loc_tag.s) shm_free(_d->id.loc_tag.s);
899
900         if (_d->loc_uri.s) shm_free(_d->loc_uri.s);
901         if (_d->rem_uri.s) shm_free(_d->rem_uri.s);
902         if (_d->rem_target.s) shm_free(_d->rem_target.s);
903
904              /* Free all routes in the route set */
905         shm_free_rr(&_d->route_set);
906         shm_free(_d);
907 }
908
909
910 /*
911  * Print a dialog structure, just for debugging
912  */
913 void print_dlg(FILE* out, dlg_t* _d)
914 {
915         fprintf(out, "====dlg_t===\n");
916         fprintf(out, "id.call_id    : '%.*s'\n", _d->id.call_id.len, _d->id.call_id.s);
917         fprintf(out, "id.rem_tag    : '%.*s'\n", _d->id.rem_tag.len, _d->id.rem_tag.s);
918         fprintf(out, "id.loc_tag    : '%.*s'\n", _d->id.loc_tag.len, _d->id.loc_tag.s);
919         fprintf(out, "loc_seq.value : %d\n", _d->loc_seq.value);
920         fprintf(out, "loc_seq.is_set: %s\n", _d->loc_seq.is_set ? "YES" : "NO");
921         fprintf(out, "rem_seq.value : %d\n", _d->rem_seq.value);
922         fprintf(out, "rem_seq.is_set: %s\n", _d->rem_seq.is_set ? "YES" : "NO");
923         fprintf(out, "loc_uri       : '%.*s'\n", _d->loc_uri.len, _d->loc_uri.s);
924         fprintf(out, "rem_uri       : '%.*s'\n", _d->rem_uri.len, _d->rem_uri.s);
925         fprintf(out, "rem_target    : '%.*s'\n", _d->rem_target.len, _d->rem_target.s);
926         fprintf(out, "secure:       : %d\n", _d->secure);
927         fprintf(out, "state         : ");
928         switch(_d->state) {
929         case DLG_NEW:       fprintf(out, "DLG_NEW\n");       break;
930         case DLG_EARLY:     fprintf(out, "DLG_EARLY\n");     break;
931         case DLG_CONFIRMED: fprintf(out, "DLG_CONFIRMED\n"); break;
932         case DLG_DESTROYED: fprintf(out, "DLG_DESTROYED\n"); break;
933         }
934         print_rr(out, _d->route_set);
935         if (_d->hooks.request_uri) 
936                 fprintf(out, "hooks.request_uri: '%.*s'\n", _d->hooks.request_uri->len, _d->hooks.request_uri->s);
937         if (_d->hooks.next_hop) 
938                 fprintf(out, "hooks.next_hop   : '%.*s'\n", _d->hooks.next_hop->len, _d->hooks.next_hop->s);
939         if (_d->hooks.first_route) 
940                 fprintf(out, "hooks.first_route: '%.*s'\n", _d->hooks.first_route->len, _d->hooks.first_route->nameaddr.name.s);
941         if (_d->hooks.last_route)
942                 fprintf(out, "hooks.last_route : '%.*s'\n", _d->hooks.last_route->len, _d->hooks.last_route->s);
943         
944         fprintf(out, "====dlg_t====\n");
945 }