dlg.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
00003  *
00004  * Copyright (C) 2001-2003 FhG Fokus
00005  *
00006  * This file is part of SIP-router, a free SIP server.
00007  *
00008  * SIP-router is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version
00012  *
00013  * SIP-router is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  *
00022  * History:
00023  * -------
00024  * 2003-03-29 Created by janakj
00025  * 2003-07-08 added wrapper to calculate_hooks, needed by b2bua (dcm)
00026  * 2007-04-13 added dialog callbacks (andrei)
00027  * 2007-05-16 added dialog callbacks destroy (andrei)
00028  */
00029 
00037 #include <string.h>
00038 #include "../../mem/shm_mem.h"
00039 #include "../../dprint.h"
00040 #include "../../parser/contact/parse_contact.h"
00041 #include "../../parser/parse_to.h"
00042 #include "../../parser/parse_from.h"
00043 #include "../../parser/parse_uri.h"
00044 #include "../../trim.h"
00045 #include "../../ut.h"
00046 #include "../../config.h"
00047 #include "dlg.h"
00048 #include "t_reply.h"
00049 #include "../../parser/parser_f.h"
00050 
00051 /* next added to allow automatical tag generation */
00052 #include "callid.h"
00053 #include "uac.h"
00054 
00055 #define NORMAL_ORDER 0  /* Create route set in normal order - UAS */
00056 #define REVERSE_ORDER 1 /* Create route set in reverse order - UAC */
00057 
00058 
00059 #ifdef DIALOG_CALLBACKS
00060 
00061 struct new_dlg_cb{
00062         int types;
00063         struct new_dlg_cb* next;
00064         dialog_cb* callback;
00065         void* param;
00066 };
00067 
00068 static struct new_dlg_cb* new_dlg_cb_list=0;
00069 /* callbacks for new dialogs (called each time a new dialog (uas or uac) is
00070  * created)
00071  * params: type - DLG_CB_UAC or DLG_CB_UAS
00072  *            f - callback function
00073  *        param - parameter passed to the callback; if allocated it must
00074  *                  be allocated in shared mem.
00075  * returns < 0 on error
00076  * WARNING: this callbacks can be registered only before forking (in mod_init)
00077  */
00078 int register_new_dlg_cb(int type, dialog_cb f, void* param)
00079 {
00080         struct new_dlg_cb* dlg_cb;
00081         
00082         dlg_cb=shm_malloc(sizeof(struct new_dlg_cb));
00083         if (dlg_cb==0)
00084                 return E_OUT_OF_MEM;
00085         dlg_cb->types=type;
00086         dlg_cb->callback=f;
00087         dlg_cb->param=param;
00088         dlg_cb->next=new_dlg_cb_list;
00089         new_dlg_cb_list=dlg_cb;
00090         return 0;
00091 }
00092 
00093 
00094 void destroy_new_dlg_cbs()
00095 {
00096         struct new_dlg_cb* c;
00097         struct new_dlg_cb* n;
00098 
00099         c=new_dlg_cb_list;
00100         while(c){
00101                 n=c->next;
00102                 shm_free(c);
00103                 c=n;
00104         }
00105         new_dlg_cb_list=0;
00106 }
00107 
00108 
00109 static void run_new_dlg_callbacks(int type, dlg_t* dlg, struct sip_msg* msg)
00110 {
00111         struct new_dlg_cb* c;
00112         for (c=new_dlg_cb_list; c; c=c->next){
00113                 if (c->types & type)
00114                         c->callback(type, dlg, msg);
00115         }
00116 }
00117 
00118 
00119 int register_dlg_tmcb(int types, dlg_t* dlg, transaction_cb f, void* param)
00120 {
00121         /* only TMCB_DLG bad TMCB_DESTROY allowed */
00122         if ((types&(TMCB_DLG|TMCB_DESTROY))!=types){
00123                 LOG(L_CRIT, "BUG: tm: register_dlg_tmcb: bad types %d\n", types);
00124                 return E_BUG;
00125         }
00126         if (f==0){
00127                 LOG(L_CRIT, "BUG: tm: register_dlg_tmcb: null callback function");
00128                 return E_BUG;
00129         }
00130         return insert_tmcb(&dlg->dlg_callbacks, types, f, param, NULL);
00131 }
00132 
00133 
00134 /* per dialog callbacks receive only the transaction, send buffer, destination
00135  * and the retr. buff */
00136 void run_trans_dlg_callbacks(dlg_t* dlg, struct cell* trans,
00137                                                                 struct retr_buf* rbuf)
00138 {
00139         struct tmcb_params params;
00140         
00141         if (dlg->dlg_callbacks.first==0)
00142                 return;
00143         memset(&params, 0, sizeof(params));
00144         if (rbuf){
00145                 params.t_rbuf=rbuf;
00146                 params.dst=&rbuf->dst;
00147                 params.send_buf.s=rbuf->buffer;
00148                 params.send_buf.len=rbuf->buffer_len;
00149         }
00150         
00151         run_trans_callbacks_internal(&dlg->dlg_callbacks, TMCB_DLG, trans, 
00152                                                                         &params);
00153 }
00154 
00155 /* TMCB_DESTROY per dialog callbacks */
00156 static void destroy_trans_dlg_callbacks(dlg_t* dlg)
00157 {
00158         struct tmcb_params params;
00159         struct tm_callback* cbp;
00160         
00161         if ((dlg->dlg_callbacks.first==0) || 
00162                         ((dlg->dlg_callbacks.reg_types&TMCB_DESTROY)==0) )
00163                 return;
00164         memset(&params, 0, sizeof(params));
00165         for (cbp=(struct tm_callback*)dlg->dlg_callbacks.first;cbp;cbp=cbp->next){
00166                 if (cbp->types & TMCB_DESTROY){
00167                         params.param=&(cbp->param);
00168                         cbp->callback(0, 0, &params);
00169                 }
00170         }
00171 }
00172 #endif /* DIALOG_CALLBACKS */
00173 
00174 /*** Temporary hack ! */
00175 /*
00176  * This function skips name part
00177  * uri parsed by parse_contact must be used
00178  * (the uri must not contain any leading or
00179  *  trailing part and if angle bracket were
00180  *  used, right angle bracket must be the
00181  *  last character in the string)
00182  *
00183  * _s will be modified so it should be a tmp
00184  * copy
00185  */
00186 void get_raw_uri(str* _s)
00187 {
00188         char* aq;
00189         
00190         if (_s->s[_s->len - 1] == '>') {
00191                 aq = find_not_quoted(_s, '<');
00192                 _s->len -= aq - _s->s + 2;
00193                 _s->s = aq + 1;
00194         }
00195 }
00196 
00197 
00198 /*
00199  * Make a copy of a str structure using shm_malloc
00200  */
00201 static inline int str_duplicate(str* _d, str* _s)
00202 {
00203         _d->s = shm_malloc(_s->len);
00204         if (!_d->s) {
00205                 LOG(L_ERR, "str_duplicate(): No memory left\n");
00206                 return -1;
00207         }
00208         
00209         memcpy(_d->s, _s->s, _s->len);
00210         _d->len = _s->len;
00211         return 0;
00212 }
00213 
00214 
00215 /*
00216  * Calculate dialog hooks
00217  * @return:
00218  *  negative : error
00219  *  0 : no routes present
00220  *  F_RB_NH_LOOSE : routes present, next hop is loose router
00221  *  F_RB_NH_STRICT: next hop is strict.
00222  */
00223 static inline int calculate_hooks(dlg_t* _d)
00224 {
00225         str* uri;
00226         struct sip_uri puri;
00227         int nhop;
00228 
00229         /* we might re-calc. some existing hooks =>
00230          * reset all the hooks to 0 */
00231         memset(&_d->hooks, 0, sizeof(_d->hooks));
00232         if (_d->route_set) {
00233                 uri = &_d->route_set->nameaddr.uri;
00234                 if (parse_uri(uri->s, uri->len, &puri) < 0) {
00235                         LOG(L_ERR, "calculate_hooks(): Error while parsing URI\n");
00236                         return -1;
00237                 }
00238                 
00239                 if (puri.lr.s) {
00240                         if (_d->rem_target.s) _d->hooks.request_uri = &_d->rem_target;
00241                         else _d->hooks.request_uri = &_d->rem_uri;
00242                         _d->hooks.next_hop = &_d->route_set->nameaddr.uri;
00243                         _d->hooks.first_route = _d->route_set;
00244                         nhop = F_RB_NH_LOOSE;
00245                 } else {
00246                         _d->hooks.request_uri = &_d->route_set->nameaddr.uri;
00247                         _d->hooks.next_hop = _d->hooks.request_uri;
00248                         _d->hooks.first_route = _d->route_set->next;
00249                         if (_d->rem_target.len > 0) 
00250                                 _d->hooks.last_route = &_d->rem_target;
00251                         else 
00252                                 _d->hooks.last_route = NULL; /* ? */
00253                         nhop = F_RB_NH_STRICT;
00254                 }
00255         } else {
00256                 if (_d->rem_target.s) _d->hooks.request_uri = &_d->rem_target;
00257                 else _d->hooks.request_uri = &_d->rem_uri;
00258                 
00259                 if (_d->dst_uri.s) _d->hooks.next_hop = &_d->dst_uri;
00260                 else _d->hooks.next_hop = _d->hooks.request_uri;
00261 
00262                 nhop = 0;
00263                 /*
00264                  * the routes in the hooks need to be reset because if the route_set 
00265                  * was dropped somewhere else then these will remain set without the
00266                  * actual routes existing any more
00267                  */
00268                 _d->hooks.first_route = 0;
00269                 _d->hooks.last_route = 0;
00270         }
00271 
00272         if ((_d->hooks.request_uri) && (_d->hooks.request_uri->s) && (_d->hooks.request_uri->len)) {
00273                 _d->hooks.ru.s = _d->hooks.request_uri->s;
00274                 _d->hooks.ru.len = _d->hooks.request_uri->len;
00275                 _d->hooks.request_uri = &_d->hooks.ru;
00276                 get_raw_uri(_d->hooks.request_uri);
00277         }
00278         if ((_d->hooks.next_hop) && (_d->hooks.next_hop->s) && (_d->hooks.next_hop->len)) {
00279                 _d->hooks.nh.s = _d->hooks.next_hop->s;
00280                 _d->hooks.nh.len = _d->hooks.next_hop->len;
00281                 _d->hooks.next_hop = &_d->hooks.nh;
00282                 get_raw_uri(_d->hooks.next_hop);
00283         }
00284 
00285         return nhop;
00286 }
00287 
00288 /*
00289  * wrapper to calculate_hooks
00290  * added by dcm
00291  */
00292 int w_calculate_hooks(dlg_t* _d)
00293 {
00294         return calculate_hooks(_d);
00295 }
00296 
00297 /*
00298  * Create a new dialog
00299  */
00300 int new_dlg_uac(str* _cid, str* _ltag, unsigned int _lseq, str* _luri, str* _ruri, dlg_t** _d)
00301 {
00302         dlg_t* res;
00303         str generated_cid;
00304         str generated_ltag;
00305 
00306         if (!_cid) { /* if not given, compute new one */
00307                 generate_callid(&generated_cid);
00308                 _cid = &generated_cid;
00309         }
00310         if (_cid && (!_ltag)) { /* if not given, compute new one */
00311                 generate_fromtag(&generated_ltag, _cid);
00312                 _ltag = &generated_ltag;
00313         }
00314         if (_lseq == 0) _lseq = DEFAULT_CSEQ;
00315 
00316         if (!_cid || !_ltag || !_luri || !_ruri || !_d) {
00317                 LOG(L_ERR, "new_dlg_uac(): Invalid parameter value\n");
00318                 return -1;
00319         }
00320 
00321         res = (dlg_t*)shm_malloc(sizeof(dlg_t));
00322         if (res == 0) {
00323                 LOG(L_ERR, "new_dlg_uac(): No memory left\n");
00324                 return -2;
00325         }
00326 
00327              /* Clear everything */     
00328         memset(res, 0, sizeof(dlg_t));
00329         
00330              /* Make a copy of Call-ID */
00331         if (str_duplicate(&res->id.call_id, _cid) < 0) return -3;
00332              /* Make a copy of local tag (usually From tag) */
00333         if (str_duplicate(&res->id.loc_tag, _ltag) < 0) return -4;
00334              /* Make a copy of local URI (usually From) */
00335         if (str_duplicate(&res->loc_uri, _luri) < 0) return -5;
00336              /* Make a copy of remote URI (usually To) */
00337         if (str_duplicate(&res->rem_uri, _ruri) < 0) return -6;
00338              /* Make a copy of local sequence (usually CSeq) */
00339         res->loc_seq.value = _lseq;
00340              /* And mark it as set */
00341         res->loc_seq.is_set = 1;
00342 
00343         *_d = res;
00344 
00345         if (calculate_hooks(*_d) < 0) {
00346                 LOG(L_ERR, "new_dlg_uac(): Error while calculating hooks\n");
00347                 /* FIXME: free everything here */
00348                 shm_free(res);
00349                 return -2;
00350         }
00351 #ifdef DIALOG_CALLBACKS
00352         run_new_dlg_callbacks(DLG_CB_UAC, res, 0);
00353 #endif
00354         
00355         return 0;
00356 }
00357 
00366 int dlg_add_extra(dlg_t* _d, str* _ldname, str* _rdname)
00367 {
00368         if(!_d || !_ldname || !_rdname)
00369         {
00370                 LM_ERR("Invalid parameters\n");
00371                 return -1;
00372         }
00373 
00374         /* Make a copy of local Display Name */
00375         if(shm_str_dup(&_d->loc_dname, _ldname) < 0) return -2;
00376         /* Make a copy of remote Display Name */
00377         if(shm_str_dup(&_d->rem_dname, _rdname) < 0) return -3;
00378 
00379         return 0;
00380 }
00381 
00382 /*
00383  * Parse Contact header field body and extract URI
00384  * Does not parse headers !!
00385  */
00386 static inline int get_contact_uri(struct sip_msg* _m, str* _uri)
00387 {
00388         contact_t* c;
00389 
00390         _uri->len = 0;
00391         _uri->s = 0;
00392 
00393         if (!_m->contact) return 1;
00394 
00395         if (parse_contact(_m->contact) < 0) {
00396                 LOG(L_ERR, "get_contact_uri(): Error while parsing Contact body\n");
00397                 return -2;
00398         }
00399 
00400         c = ((contact_body_t*)_m->contact->parsed)->contacts;
00401 
00402         if (!c) {
00403                 LOG(L_ERR, "get_contact_uri(): Empty body or * contact\n");
00404                 return -3;
00405         }
00406 
00407         _uri->s = c->uri.s;
00408         _uri->len = c->uri.len;
00409         return 0;
00410 }
00411 
00412 
00413 /*
00414  * Extract tag from To header field of a response
00415  * Doesn't parse message headers !!
00416  */
00417 static inline int get_to_tag(struct sip_msg* _m, str* _tag)
00418 {
00419         if (!_m->to) {
00420                 LOG(L_ERR, "get_to_tag(): To header field missing\n");
00421                 return -1;
00422         }
00423 
00424         if (get_to(_m)->tag_value.len) {
00425                 _tag->s = get_to(_m)->tag_value.s;
00426                 _tag->len = get_to(_m)->tag_value.len;
00427         } else {
00428                 _tag->len = 0;
00429         }
00430 
00431         return 0;
00432 }
00433 
00434 
00435 /*
00436  * Extract tag from From header field of a request
00437  */
00438 static inline int get_from_tag(struct sip_msg* _m, str* _tag)
00439 {
00440         if (parse_from_header(_m) == -1) {
00441                 LOG(L_ERR, "get_from_tag(): Error while parsing From header\n");
00442                 return -1;
00443         }
00444 
00445         if (get_from(_m)->tag_value.len) {
00446                 _tag->s = get_from(_m)->tag_value.s;
00447                 _tag->len = get_from(_m)->tag_value.len;
00448         } else {
00449                 _tag->len = 0;
00450         }
00451 
00452         return 0;
00453 }
00454 
00455 
00456 /*
00457  * Extract Call-ID value
00458  * Doesn't parse headers !!
00459  */
00460 static inline int get_callid(struct sip_msg* _m, str* _cid)
00461 {
00462         if (_m->callid == 0) {
00463                 LOG(L_ERR, "get_callid(): Call-ID not found\n");
00464                 return -1;
00465         }
00466 
00467         _cid->s = _m->callid->body.s;
00468         _cid->len = _m->callid->body.len;
00469         trim(_cid);
00470         return 0;
00471 }
00472 
00473 static rr_t *revert_route(rr_t *r)
00474 {
00475         rr_t *a, *b;
00476 
00477         a = NULL;
00478 
00479         while (r) {
00480                 b = r->next;
00481                 r->next = a;
00482                 a = r;
00483                 r = b;
00484         }
00485 
00486         return a;
00487 }
00488 
00489 /*
00490  * Create a copy of route set either in normal or reverse order
00491  */
00492 static inline int get_route_set(struct sip_msg* _m, rr_t** _rs, unsigned char _order)
00493 {
00494         struct hdr_field* ptr;
00495         rr_t* last, *p, *t;
00496         
00497         last = 0;
00498 
00499         ptr = _m->record_route;
00500         while(ptr) {
00501                 if (ptr->type == HDR_RECORDROUTE_T) {
00502                         if (parse_rr(ptr) < 0) {
00503                                 LOG(L_ERR, "get_route_set(): Error while parsing Record-Route body\n");
00504                                 goto error;
00505                         }
00506 
00507                         p = (rr_t*)ptr->parsed;
00508                         if (shm_duplicate_rr(&t, p) < 0) {
00509                                 LOG(L_ERR, "get_route_set(): Error while duplicating rr_t\n");
00510                                 goto error;
00511                         }
00512                         if (!*_rs) *_rs = t;
00513                         if (last) last->next = t;
00514                         last = t;
00515                         while (last->next) last = last->next; /* !!! there may be more routes in one hdr field !!! */
00516 
00517                 }
00518                 ptr = ptr->next;
00519         }
00520         if ((*_rs) && (_order != NORMAL_ORDER)) {
00521                 /* better to revert the route outside of cycle above */
00522                 *_rs = revert_route(*_rs);
00523         }
00524         
00525         return 0;
00526 
00527  error:
00528         shm_free_rr(_rs);
00529         return -1;
00530 }
00531 
00532 /*
00533  * Extract method from CSeq header field
00534  */
00535 static inline int get_cseq_method(struct sip_msg* _m, str* _method)
00536 {
00537         if (!_m->cseq && ((parse_headers(_m, HDR_CSEQ_F, 0) == -1) || !_m->cseq)) {
00538                 LOG(L_ERR, "get_cseq_method(): Error while parsing CSeq\n");
00539                 return -1;
00540         }
00541 
00542         _method->s = get_cseq(_m)->method.s;
00543         _method->len = get_cseq(_m)->method.len;
00544         return 0;
00545 }
00546 
00547 
00548 static inline int refresh_dialog_resp(struct sip_msg* _m, 
00549                 target_refresh_t is_target_refresh)
00550 {
00551         str method;
00552         
00553         switch (is_target_refresh) {
00554                 case IS_NOT_TARGET_REFRESH: 
00555                         return 0;
00556                 case IS_TARGET_REFRESH: 
00557                         return 1;
00558                 case TARGET_REFRESH_UNKNOWN: 
00559                         if (get_cseq_method(_m, &method) < 0) return 0; /* error */
00560                         if ((method.len == 6) && !memcmp("INVITE", method.s, 6)) 
00561                                 return 1;
00562                         else return 0;
00563         }
00564         return 0;
00565 }
00566                 
00567 static inline int refresh_dialog_req(struct sip_msg* _m, target_refresh_t is_target_refresh)
00568 {
00569         switch (is_target_refresh) {
00570                 case IS_NOT_TARGET_REFRESH: 
00571                         return 0;
00572                 case IS_TARGET_REFRESH: 
00573                         return 1;
00574                 case TARGET_REFRESH_UNKNOWN: 
00575                         return (_m->first_line.u.request.method_value == METHOD_INVITE);
00576                         break;
00577         }
00578         return 0;
00579 }
00580 
00581 /*
00582  * Extract all necessary information from a response and put it
00583  * in a dialog structure
00584  */
00585 static inline int response2dlg(struct sip_msg* _m, dlg_t* _d)
00586 {
00587         str contact, rtag;
00588 
00589              /* Parse the whole message, we will need all Record-Route headers */
00590         if (parse_headers(_m, HDR_EOH_F, 0) == -1) {
00591                 LOG(L_ERR, "response2dlg(): Error while parsing headers\n");
00592                 return -1;
00593         }
00594         
00595         if (get_contact_uri(_m, &contact) < 0) return -2;
00596         if (_d->rem_target.s) {
00597                 shm_free(_d->rem_target.s);
00598                 _d->rem_target.s = 0; 
00599                 _d->rem_target.len = 0;
00600         }
00601         if (_d->dst_uri.s) {
00602                 shm_free(_d->dst_uri.s);
00603                 _d->dst_uri.s = 0; 
00604                 _d->dst_uri.len = 0;
00605         }
00606         if (contact.len && str_duplicate(&_d->rem_target, &contact) < 0) return -3;
00607         
00608         if (get_to_tag(_m, &rtag) < 0) goto err1;
00609         if (rtag.len && str_duplicate(&_d->id.rem_tag, &rtag) < 0) goto err1;
00610         
00611         if (get_route_set(_m, &_d->route_set, REVERSE_ORDER) < 0) goto err2;
00612 
00613         return 0;
00614  err2:
00615         if (_d->id.rem_tag.s) shm_free(_d->id.rem_tag.s);
00616         _d->id.rem_tag.s = 0;
00617         _d->id.rem_tag.len = 0;
00618 
00619  err1:
00620         if (_d->rem_target.s) shm_free(_d->rem_target.s);
00621         _d->rem_target.s = 0;
00622         _d->rem_target.len = 0;
00623         return -4;
00624 }
00625 
00626 
00627 /*
00628  * Handle dialog in DLG_NEW state, we will be processing the
00629  * first response
00630  */
00631 static inline int dlg_new_resp_uac(dlg_t* _d, struct sip_msg* _m)
00632 {
00633         int code;
00634              /*
00635               * Dialog is in DLG_NEW state, we will copy remote
00636               * target URI, remote tag if present, and route-set 
00637               * if present. And we will transit into DLG_CONFIRMED 
00638               * if the response was 2xx and to DLG_DESTROYED if the 
00639               * request was a negative final response.
00640               */
00641 
00642         code = _m->first_line.u.reply.statuscode;
00643 
00644         if (code < 200) {
00645                      /* A provisional response, do nothing, we could
00646                       * update remote tag and route set but we will do that
00647                       * for a positive final response anyway and I don't want
00648                       * bet on presence of these fields in provisional responses
00649                       *
00650                       * Send a request to jan@iptel.org if you need to update
00651                       * the structures here
00652                       */
00653         } else if ((code >= 200) && (code < 299)) {
00654                      /* A final response, update the structures and transit
00655                       * into DLG_CONFIRMED
00656                       */
00657                 if (response2dlg(_m, _d) < 0) return -1;
00658                 _d->state = DLG_CONFIRMED;
00659 
00660                 if (calculate_hooks(_d) < 0) {
00661                         LOG(L_ERR, "dlg_new_resp_uac(): Error while calculating hooks\n");
00662                         return -2;
00663                 }
00664         } else {
00665                      /* 
00666                       * A negative final response, mark the dialog as destroyed
00667                       * Again, I do not update the structures here because it
00668                       * makes no sense to me, a dialog shouldn't be used after
00669                       * it is destroyed
00670                       */
00671                 _d->state = DLG_DESTROYED;
00672                      /* Signalize the termination with positive return value */
00673                 return 1;
00674         }
00675 
00676         return 0;
00677 }
00678 
00679 
00680 /*
00681  * Handle dialog in DLG_EARLY state, we will be processing either
00682  * next provisional response or a final response
00683  */
00684 static inline int dlg_early_resp_uac(dlg_t* _d, struct sip_msg* _m)
00685 {
00686         int code;
00687         code = _m->first_line.u.reply.statuscode;       
00688 
00689         if (code < 200) {
00690                      /* We are in early state already, do nothing
00691                       */
00692         } else if ((code >= 200) && (code <= 299)) {
00693                 /* Warning - we can handle here response for non-initial request (for
00694                  * example UPDATE within early INVITE/BYE dialog) and move into
00695                  * confirmed state may be error! But this depends on dialog type... */
00696                 
00697                      /* Same as in dlg_new_resp_uac */
00698                      /* A final response, update the structures and transit
00699                       * into DLG_CONFIRMED
00700                       */
00701                 if (response2dlg(_m, _d) < 0) return -1;
00702                 _d->state = DLG_CONFIRMED;
00703 
00704                 if (calculate_hooks(_d) < 0) {
00705                         LOG(L_ERR, "dlg_early_resp_uac(): Error while calculating hooks\n");
00706                         return -2;
00707                 }
00708         } else {
00709                      /* Else terminate the dialog */
00710                 _d->state = DLG_DESTROYED;
00711                      /* Signalize the termination with positive return value */
00712                 return 1;
00713         }
00714 
00715         return 0;
00716 }
00717 
00718 
00719 /*
00720  * Handle dialog in DLG_CONFIRMED state, we will be processing
00721  * a response to a request sent within a dialog
00722  */
00723 static inline int dlg_confirmed_resp_uac(dlg_t* _d, struct sip_msg* _m, 
00724                 target_refresh_t is_target_refresh)
00725 {
00726         int code;
00727         str contact;
00728 
00729         code = _m->first_line.u.reply.statuscode;       
00730 
00731              /* Dialog has been already confirmed, that means we received
00732               * a response to a request sent within the dialog. We will
00733               * update remote target URI if and only if the message sent was
00734               * a target refresher. 
00735               */
00736 
00737              /* IF we receive a 481 response, terminate the dialog because
00738               * the remote peer indicated that it didn't have the dialog
00739               * state anymore, signal this termination with a positive return
00740               * value
00741               */
00742         if (code == 481) {
00743                 _d->state = DLG_DESTROYED;
00744                 return 1;
00745         }
00746 
00747              /* Do nothing if not 2xx */
00748         if ((code < 200) || (code >= 300)) return 0;
00749         
00750         if (refresh_dialog_resp(_m, is_target_refresh)) {
00751                      /* Get contact if any and update remote target */
00752                 if (parse_headers(_m, HDR_CONTACT_F, 0) == -1) {
00753                         LOG(L_ERR, "dlg_confirmed_resp_uac(): Error while parsing headers\n");
00754                         return -2;
00755                 }
00756 
00757                      /* Try to extract contact URI */
00758                 if (get_contact_uri(_m, &contact) < 0) return -3;
00759                      /* If there is a contact URI */
00760                 if (contact.len) {
00761                              /* Free old remote target and destination uri if any */
00762                         if (_d->rem_target.s) shm_free(_d->rem_target.s);
00763                         if (_d->dst_uri.s) {
00764                                 shm_free(_d->dst_uri.s);
00765                                 _d->dst_uri.s = 0;
00766                                 _d->dst_uri.len = 0;
00767                         }
00768                                 
00769                              /* Duplicate new remote target */
00770                         if (str_duplicate(&_d->rem_target, &contact) < 0) return -4;
00771                 }
00772 
00773                 if (calculate_hooks(_d) < 0)
00774                         return -1;
00775         }
00776 
00777         return 0;
00778 }
00779 
00780 
00781 /*
00782  * A response arrived, update dialog
00783  */
00784 int dlg_response_uac(dlg_t* _d, struct sip_msg* _m, 
00785                 target_refresh_t is_target_refresh)
00786 {
00787         if (!_d || !_m) {
00788                 LOG(L_ERR, "dlg_response_uac(): Invalid parameter value\n");
00789                 return -1;
00790         }
00791 
00792              /* The main dispatcher */
00793         switch(_d->state) {
00794         case DLG_NEW:       
00795                 return dlg_new_resp_uac(_d, _m);
00796 
00797         case DLG_EARLY:     
00798                 return dlg_early_resp_uac(_d, _m);
00799 
00800         case DLG_CONFIRMED: 
00801                 return dlg_confirmed_resp_uac(_d, _m, is_target_refresh);
00802 
00803         case DLG_DESTROYED:
00804                 LOG(L_DBG, "dlg_response_uac(): Cannot handle destroyed dialog\n");
00805                 return -2;
00806         }
00807 
00808         LOG(L_ERR, "dlg_response_uac(): Error in switch statement\n");
00809         return -3;
00810 }
00811 
00812 
00813 /*
00814  * Get CSeq number
00815  * Does not parse headers !!
00816  */
00817 static inline int get_cseq_value(struct sip_msg* _m, unsigned int* _cs)
00818 {
00819         str num;
00820 
00821         if (_m->cseq == 0) {
00822                 LOG(L_ERR, "get_cseq_value(): CSeq header not found\n");
00823                 return -1;
00824         }
00825 
00826         num.s = get_cseq(_m)->number.s;
00827         num.len = get_cseq(_m)->number.len;
00828 
00829         trim_leading(&num);
00830         if (str2int(&num, _cs) < 0) {
00831                 LOG(L_ERR, "get_cseq_value(): Error while converting cseq number\n");
00832                 return -2;
00833         }
00834         return 0;
00835 }
00836 
00837 
00838 /*
00839  * Copy To or From URI without tag parameter
00840  */
00841 static inline int get_dlg_uri(struct hdr_field* _h, str* _s)
00842 {
00843         struct to_param* ptr, *prev;
00844         struct to_body* body;
00845         char* tag = 0; /* Makes gcc happy */
00846         int tag_len = 0, len;
00847 
00848         if (!_h) {
00849                 LOG(L_ERR, "get_dlg_uri(): Header field not found\n");
00850                 return -1;
00851         }
00852 
00853              /* From was already parsed when extracting tag
00854               * and To is parsed by default
00855               */
00856         
00857         body = (struct to_body*)_h->parsed;
00858 
00859         ptr = body->param_lst;
00860         prev = 0;
00861         while(ptr) {
00862                 if (ptr->type == TAG_PARAM) break;
00863                 prev = ptr;
00864                 ptr = ptr->next;
00865         }
00866 
00867         if (ptr) {
00868                      /* Tag param found */
00869                 if (prev) {
00870                         tag = prev->value.s + prev->value.len;
00871                 } else {
00872                         tag = body->body.s + body->body.len;
00873                 }
00874                 
00875                 if (ptr->next) {
00876                         tag_len = ptr->value.s + ptr->value.len - tag;
00877                 } else {
00878                         tag_len = _h->body.s + _h->body.len - tag;
00879                 }
00880         }
00881 
00882         _s->s = shm_malloc(_h->body.len - tag_len);
00883         if (!_s->s) {
00884                 LOG(L_ERR, "get_dlg_uri(): No memory left\n");
00885                 return -1;
00886         }
00887 
00888         if (tag_len) {
00889                 len = tag - _h->body.s;
00890                 memcpy(_s->s, _h->body.s, len);
00891                 memcpy(_s->s + len, tag + tag_len, _h->body.len - len - tag_len);
00892                 _s->len = _h->body.len - tag_len;
00893         } else {
00894                 memcpy(_s->s, _h->body.s, _h->body.len);
00895                 _s->len = _h->body.len;
00896         }
00897 
00898         return 0;
00899 }
00900 
00901 
00902 /*
00903  * Extract all information from a request 
00904  * and update a dialog structure
00905  */
00906 static inline int request2dlg(struct sip_msg* _m, dlg_t* _d)
00907 {
00908         str contact, rtag, callid;
00909 
00910         if (parse_headers(_m, HDR_EOH_F, 0) == -1) {
00911                 LOG(L_ERR, "request2dlg(): Error while parsing headers");
00912                 return -1;
00913         }
00914 
00915         if (get_contact_uri(_m, &contact) < 0) return -2;
00916         if (contact.len) {
00917                 if (_d->rem_target.s) shm_free(_d->rem_target.s);
00918                 if (_d->dst_uri.s) {
00919                         shm_free(_d->dst_uri.s);
00920                         _d->dst_uri.s = 0;
00921                         _d->dst_uri.len = 0;
00922                 }
00923                 if (str_duplicate(&_d->rem_target, &contact) < 0) return -3;
00924         }
00925         
00926         if (get_from_tag(_m, &rtag) < 0) goto err1;
00927         if (rtag.len && str_duplicate(&_d->id.rem_tag, &rtag) < 0) goto err1;
00928 
00929         if (get_callid(_m, &callid) < 0) goto err2;
00930         if (callid.len && str_duplicate(&_d->id.call_id, &callid) < 0) goto err2;
00931 
00932         if (get_cseq_value(_m, &_d->rem_seq.value) < 0) goto err3;
00933         _d->rem_seq.is_set = 1;
00934 
00935         if (get_dlg_uri(_m->from, &_d->rem_uri) < 0) goto err3;
00936         if (get_dlg_uri(_m->to, &_d->loc_uri) < 0) goto err4;
00937 
00938         if (get_route_set(_m, &_d->route_set, NORMAL_ORDER) < 0) goto err5;     
00939 
00940         return 0;
00941  err5:
00942         if (_d->loc_uri.s) shm_free(_d->loc_uri.s);
00943         _d->loc_uri.s = 0;
00944         _d->loc_uri.len = 0;
00945  err4:
00946         if (_d->rem_uri.s) shm_free(_d->rem_uri.s);
00947         _d->rem_uri.s = 0;
00948         _d->rem_uri.len = 0;
00949  err3:
00950         if (_d->id.call_id.s) shm_free(_d->id.call_id.s);
00951         _d->id.call_id.s = 0;
00952         _d->id.call_id.len = 0;
00953  err2:
00954         if (_d->id.rem_tag.s) shm_free(_d->id.rem_tag.s);
00955         _d->id.rem_tag.s = 0;
00956         _d->id.rem_tag.len = 0;
00957  err1:
00958         if (_d->rem_target.s) shm_free(_d->rem_target.s);
00959         _d->rem_target.s = 0;
00960         _d->rem_target.len = 0;
00961         return -4;
00962 }
00963 
00964 
00965 /*
00966  * Establishing a new dialog, UAS side
00967  */
00968 int new_dlg_uas(struct sip_msg* _req, int _code, /*str* _tag,*/ dlg_t** _d)
00969 {
00970         dlg_t* res;
00971         str tag;
00972 
00973         if (!_req ||  !_d) {
00974                 LOG(L_ERR, "new_dlg_uas(): Invalid parameter value\n");
00975                 return -1;
00976         }
00977 
00978         if (_code > 299) {
00979                 DBG("new_dlg_uas(): Status code >= 300, no dialog created\n");
00980         }
00981 
00982         res = (dlg_t*)shm_malloc(sizeof(dlg_t));
00983         if (res == 0) {
00984                 LOG(L_ERR, "new_dlg_uac(): No memory left\n");
00985                 return -3;
00986         }
00987              /* Clear everything */
00988         memset(res, 0, sizeof(dlg_t));  
00989 
00990         if (request2dlg(_req, res) < 0) {
00991                 LOG(L_ERR, "new_dlg_uas(): Error while converting request to dialog\n");
00992                 free_dlg(res);
00993                 return -4;
00994         }
00995 
00996         if (_code > 100) {
00997                 tag.s = tm_tags;
00998                 tag.len = TOTAG_VALUE_LEN;
00999                 calc_crc_suffix(_req, tm_tag_suffix);
01000                 if (str_duplicate(&res->id.loc_tag, &tag) < 0) {
01001                         free_dlg(res);
01002                         return -5;
01003                 }
01004         }
01005         
01006         *_d = res;
01007 
01008         if (_code < 100)
01009                 (*_d)->state = DLG_NEW;
01010         else if (_code < 200)
01011                 (*_d)->state = DLG_EARLY;
01012         else
01013                 (*_d)->state = DLG_CONFIRMED;
01014 
01015         if (calculate_hooks(*_d) < 0) {
01016                 LOG(L_ERR, "new_dlg_uas(): Error while calculating hooks\n");
01017                 free_dlg(res);
01018                 return -6;
01019         }
01020 #ifdef DIALOG_CALLBACKS
01021         run_new_dlg_callbacks(DLG_CB_UAS, res, _req);
01022 #endif
01023 
01024         return 0;
01025 }
01026 
01027 /*
01028  * UAS side - update dialog state and to tag
01029  */
01030 int update_dlg_uas(dlg_t *_d, int _code, str* _tag)
01031 {
01032         if (_d->state == DLG_CONFIRMED) {
01033                 LOG(L_ERR, "update_dlg_uas(): Dialog is already confirmed\n");
01034                 return -1;
01035         } else if (_d->state == DLG_DESTROYED) {
01036                 LOG(L_ERR, "update_dlg_uas(): Dialog is already destroyed\n");
01037                 return -2;
01038         }
01039 
01040         if (_tag && _tag->s) {
01041                 if (_d->id.loc_tag.s) {
01042                         if ((_tag->len == _d->id.loc_tag.len)
01043                         && (!memcmp(_tag->s, _d->id.loc_tag.s, _tag->len))) {
01044                                 LOG(L_DBG, "update_dlg_uas(): Local tag is already set\n");
01045                         } else {
01046                                 LOG(L_ERR, "update_dlg_uas(): ERROR: trying to rewrite local tag\n");
01047                                 return -3;
01048                         }
01049                 } else {
01050                         if (str_duplicate(&_d->id.loc_tag, _tag) < 0) {
01051                                 LOG(L_ERR, "update_dlg_uas(): Not enough memory\n");
01052                                 return -4;
01053                         }
01054                 }
01055         }
01056 
01057         if ((100 < _code) && (_code < 200))
01058                 _d->state = DLG_EARLY;
01059         else if (_code < 300)
01060                 _d->state = DLG_CONFIRMED;
01061         else
01062                 _d->state = DLG_DESTROYED;
01063 
01064         return 0;
01065 }
01066 
01067 /*
01068  * UAS side - update a dialog from a request
01069  */
01070 int dlg_request_uas(dlg_t* _d, struct sip_msg* _m, target_refresh_t is_target_refresh)
01071 {
01072         str contact;
01073         int cseq;
01074 
01075         if (!_d || !_m) {
01076                 LOG(L_ERR, "dlg_request_uas(): Invalid parameter value\n");
01077                 return -1;
01078         }
01079 
01080              /* We must check if the request is not out of order or retransmission
01081               * first, if so then we will not update anything
01082               */
01083         if (parse_headers(_m, HDR_CSEQ_F, 0) == -1) {
01084                 LOG(L_ERR, "dlg_request_uas(): Error while parsing headers\n");
01085                 return -2;
01086         }
01087         if (get_cseq_value(_m, (unsigned int*)&cseq) < 0) return -3;
01088         if (_d->rem_seq.is_set && (cseq <= _d->rem_seq.value)) return 0;
01089 
01090              /* Neither out of order nor retransmission -> update */
01091         _d->rem_seq.value = cseq;
01092         _d->rem_seq.is_set = 1;
01093         
01094              /* We will als update remote target URI if the message 
01095               * is target refresher
01096               */
01097         if (refresh_dialog_req(_m, is_target_refresh)) { /* target refresher */
01098                 if (parse_headers(_m, HDR_CONTACT_F, 0) == -1) {
01099                         LOG(L_ERR, "dlg_request_uas(): Error while parsing headers\n");
01100                         return -4;
01101                 }
01102                 
01103                 if (get_contact_uri(_m, &contact) < 0) return -5;
01104                 if (contact.len) {
01105                         if (_d->rem_target.s) shm_free(_d->rem_target.s);
01106                         if (_d->dst_uri.s) {
01107                                 shm_free(_d->dst_uri.s);
01108                                 _d->dst_uri.s = 0;
01109                                 _d->dst_uri.len = 0;
01110                         }
01111                         if (str_duplicate(&_d->rem_target, &contact) < 0) return -6;
01112                 }
01113 
01114                 if (calculate_hooks(_d) < 0)
01115                         return -1;
01116                 
01117         }
01118 
01119         return 0;
01120 }
01121 
01122 
01123 /*
01124  * Calculate length of the route set
01125  */
01126 int calculate_routeset_length(dlg_t* _d)
01127 {
01128         int len;
01129         rr_t *ptr;
01130 
01131         if (! _d->route_set)
01132                 return 0;
01133 
01134         len = ROUTE_PREFIX_LEN;
01135 
01136         for (ptr = _d->hooks.first_route; ptr; ptr = ptr->next) {
01137                 len += ptr->len;
01138                 len += ROUTE_SEPARATOR_LEN;
01139         }
01140         if (_d->hooks.last_route) {
01141                 if (_d->hooks.first_route)
01142                         len += ROUTE_SEPARATOR_LEN;
01143                 len += _d->hooks.last_route->len + 2; /* < > */
01144         } else {
01145                 len -= ROUTE_SEPARATOR_LEN;
01146         }
01147 
01148         len += CRLF_LEN;
01149 
01150         return len;
01151 }
01152 
01153 /*
01154  *
01155  * Print the route set
01156  */
01157 char* print_routeset(char* buf, dlg_t* _d)
01158 {
01159         rr_t* ptr;
01160 
01161         ptr = _d->hooks.first_route;
01162 
01163         if (ptr || _d->hooks.last_route) {
01164                 memcpy(buf, ROUTE_PREFIX, ROUTE_PREFIX_LEN);
01165                 buf += ROUTE_PREFIX_LEN;
01166         }
01167 
01168         while(ptr) {
01169                 memcpy(buf, ptr->nameaddr.name.s, ptr->len);
01170                 buf += ptr->len;
01171 
01172                 ptr = ptr->next;
01173                 if (ptr) {
01174                         memcpy(buf, ROUTE_SEPARATOR, ROUTE_SEPARATOR_LEN);
01175                         buf += ROUTE_SEPARATOR_LEN;
01176                 }
01177         } 
01178 
01179         if (_d->hooks.last_route) {
01180                 if (_d->hooks.first_route) {
01181                         memcpy(buf, ROUTE_SEPARATOR, ROUTE_SEPARATOR_LEN);
01182                         buf += ROUTE_SEPARATOR_LEN;
01183                 }
01184                 memcpy(buf, "<", 1);
01185                 buf++;
01186                 memcpy(buf, _d->hooks.last_route->s, _d->hooks.last_route->len);
01187                 buf += _d->hooks.last_route->len;
01188                 *buf = '>';
01189                 buf++;
01190         }
01191 
01192         if (_d->hooks.first_route || _d->hooks.last_route) {
01193                 memcpy(buf, CRLF, CRLF_LEN);
01194                 buf += CRLF_LEN;
01195         }
01196 
01197         return buf;
01198 }
01199 
01200 
01201 /*
01202  * Destroy a dialog state
01203  */
01204 void free_dlg(dlg_t* _d)
01205 {
01206         if (!_d) return;
01207 #ifdef DIALOG_CALLBACKS
01208         destroy_trans_dlg_callbacks(_d);
01209 #endif
01210         if (_d->id.call_id.s) shm_free(_d->id.call_id.s);
01211         if (_d->id.rem_tag.s) shm_free(_d->id.rem_tag.s);
01212         if (_d->id.loc_tag.s) shm_free(_d->id.loc_tag.s);
01213 
01214         if (_d->loc_uri.s) shm_free(_d->loc_uri.s);
01215         if (_d->rem_uri.s) shm_free(_d->rem_uri.s);
01216         if (_d->rem_target.s) shm_free(_d->rem_target.s);
01217         if (_d->dst_uri.s) shm_free(_d->dst_uri.s);
01218 
01219              /* Free all routes in the route set */
01220         shm_free_rr(&_d->route_set);
01221         shm_free(_d);
01222 }
01223 
01224 
01225 /*
01226  * Print a dialog structure, just for debugging
01227  */
01228 void print_dlg(FILE* out, dlg_t* _d)
01229 {
01230         fprintf(out, "====dlg_t===\n");
01231         fprintf(out, "id.call_id    : '%.*s'\n", _d->id.call_id.len, _d->id.call_id.s);
01232         fprintf(out, "id.rem_tag    : '%.*s'\n", _d->id.rem_tag.len, _d->id.rem_tag.s);
01233         fprintf(out, "id.loc_tag    : '%.*s'\n", _d->id.loc_tag.len, _d->id.loc_tag.s);
01234         fprintf(out, "loc_seq.value : %d\n", _d->loc_seq.value);
01235         fprintf(out, "loc_seq.is_set: %s\n", _d->loc_seq.is_set ? "YES" : "NO");
01236         fprintf(out, "rem_seq.value : %d\n", _d->rem_seq.value);
01237         fprintf(out, "rem_seq.is_set: %s\n", _d->rem_seq.is_set ? "YES" : "NO");
01238         fprintf(out, "loc_uri       : '%.*s'\n", _d->loc_uri.len, _d->loc_uri.s);
01239         fprintf(out, "rem_uri       : '%.*s'\n", _d->rem_uri.len, _d->rem_uri.s);
01240         fprintf(out, "rem_target    : '%.*s'\n", _d->rem_target.len, _d->rem_target.s);
01241         fprintf(out, "dst_uri       : '%.*s'\n", _d->dst_uri.len, _d->dst_uri.s);
01242         fprintf(out, "secure:       : %d\n", _d->secure);
01243         fprintf(out, "state         : ");
01244         switch(_d->state) {
01245         case DLG_NEW:       fprintf(out, "DLG_NEW\n");       break;
01246         case DLG_EARLY:     fprintf(out, "DLG_EARLY\n");     break;
01247         case DLG_CONFIRMED: fprintf(out, "DLG_CONFIRMED\n"); break;
01248         case DLG_DESTROYED: fprintf(out, "DLG_DESTROYED\n"); break;
01249         }
01250         print_rr(out, _d->route_set);
01251         if (_d->hooks.request_uri) 
01252                 fprintf(out, "hooks.request_uri: '%.*s'\n", _d->hooks.request_uri->len, _d->hooks.request_uri->s);
01253         if (_d->hooks.next_hop) 
01254                 fprintf(out, "hooks.next_hop   : '%.*s'\n", _d->hooks.next_hop->len, _d->hooks.next_hop->s);
01255         if (_d->hooks.first_route) 
01256                 fprintf(out, "hooks.first_route: '%.*s'\n", _d->hooks.first_route->len, _d->hooks.first_route->nameaddr.name.s);
01257         if (_d->hooks.last_route)
01258                 fprintf(out, "hooks.last_route : '%.*s'\n", _d->hooks.last_route->len, _d->hooks.last_route->s);
01259         
01260         fprintf(out, "====dlg_t====\n");
01261 }
01262 
01263 /*
01264  * set dialog's request uri and destination uri (optional)
01265  */
01266 int set_dlg_target(dlg_t* _d, str* _ruri, str* _duri) {
01267 
01268         if (!_d || !_ruri) {
01269                 LOG(L_ERR, "set_dlg_target(): Invalid parameter value\n");
01270                 return -1;
01271         }
01272 
01273         if (_d->rem_target.s) shm_free(_d->rem_target.s);
01274         if (_d->dst_uri.s) {
01275                 shm_free(_d->dst_uri.s);
01276                 _d->dst_uri.s = 0;
01277                 _d->dst_uri.len = 0;
01278         }
01279 
01280         if (str_duplicate(&_d->rem_target, _ruri)) return -1;
01281         if (_duri && _duri->len) {
01282                 if (str_duplicate(&_d->dst_uri, _duri)) return -1;
01283         }
01284 
01285         if (calculate_hooks(_d) < 0) {
01286                 LOG(L_ERR, "set_dlg_target(): Error while calculating hooks\n");
01287                 return -1;
01288         }
01289 
01290         return 0;
01291 }