dlg.c

Go to the documentation of this file.
00001 /*
00002  * $Id: dlg.c 5299 2008-12-04 18:12:33Z henningw $
00003  *
00004  * Copyright (C) 2001-2003 FhG Fokus
00005  *
00006  * This file is part of Kamailio, a free SIP server.
00007  *
00008  * Kamailio 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  * Kamailio 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  * 2008-04-04 added support for local and remote dispaly name in TM dialogs
00027  *            (by Andrei Pisau <andrei.pisau at voice-system dot ro> )
00028  */
00029 
00030 /*! \file
00031  * \brief TM :: Dialog handling
00032  *
00033  * \ingroup tm
00034  * - Module: \ref tm
00035  */
00036 
00037 
00038 
00039 #include <string.h>
00040 #include "../../mem/shm_mem.h"
00041 #include "../../dprint.h"
00042 #include "../../parser/contact/parse_contact.h"
00043 #include "../../parser/parse_to.h"
00044 #include "../../parser/parse_from.h"
00045 #include "../../parser/parse_uri.h"
00046 #include "../../trim.h"
00047 #include "../../ut.h"
00048 #include "../../config.h"
00049 #include "dlg.h"
00050 #include "t_reply.h"
00051 #include "../../parser/parser_f.h"
00052 
00053 
00054 #define NORMAL_ORDER 0  /*!< Create route set in normal order - UAS */
00055 #define REVERSE_ORDER 1 /*!< Create route set in reverse order - UAC */
00056 
00057 #define ROUTE_PREFIX "Route: "
00058 #define ROUTE_PREFIX_LEN (sizeof(ROUTE_PREFIX) - 1)
00059 
00060 #define ROUTE_SEPARATOR "," CRLF "       "
00061 #define ROUTE_SEPARATOR_LEN (sizeof(ROUTE_SEPARATOR) - 1)
00062 
00063 
00064 
00065 /*!
00066  * \brief This function skips a name part in a URI
00067  *
00068  * This function skips a name part in a URI.
00069  * The URI parsed by parse_contact must be used (the URI
00070  * must not contain any leading or trailing part and if
00071  * angle bracket were used, right angle bracket must be the
00072  * last character in the string)
00073  * \note Temporary hack!
00074  * \param _s URI, will be modified so it should be a temporary copy
00075  */
00076 void get_raw_uri(str* _s)
00077 {
00078    char* aq;
00079    if (_s->s[_s->len - 1] == '>') {
00080       aq = find_not_quoted(_s, '<');
00081       _s->len -= aq - _s->s + 2;
00082       _s->s = aq + 1;
00083    }
00084 }
00085 
00086 
00087 /*!
00088  * \brief Calculate dialog hooks
00089  * \param _d dialog state
00090  * \return 0 on success, -1 on error
00091  */
00092 static inline int calculate_hooks(dlg_t* _d)
00093 {
00094    str* uri;
00095    struct sip_uri puri;
00096 
00097    if (_d->route_set) {
00098       uri = &_d->route_set->nameaddr.uri;
00099       if (parse_uri(uri->s, uri->len, &puri) < 0) {
00100          LM_ERR("failed parse to URI\n");
00101          return -1;
00102       }
00103 
00104       if (puri.lr.s) {
00105          if (_d->rem_target.s) _d->hooks.request_uri = &_d->rem_target;
00106          else _d->hooks.request_uri = &_d->rem_uri;
00107          _d->hooks.next_hop = &_d->route_set->nameaddr.uri;
00108          _d->hooks.first_route = _d->route_set;
00109       } else {
00110          _d->hooks.request_uri = &_d->route_set->nameaddr.uri;
00111          _d->hooks.next_hop = _d->hooks.request_uri;
00112          _d->hooks.first_route = _d->route_set->next;
00113          _d->hooks.last_route = &_d->rem_target;
00114       }
00115    } else {
00116       if (_d->rem_target.s) _d->hooks.request_uri = &_d->rem_target;
00117       else _d->hooks.request_uri = &_d->rem_uri;
00118       if(_d->hooks.next_hop==NULL)
00119          _d->hooks.next_hop = _d->hooks.request_uri;
00120    }
00121 
00122    if ((_d->hooks.request_uri) && (_d->hooks.request_uri->s) && (_d->hooks.request_uri->len)) {
00123       _d->hooks.ru.s = _d->hooks.request_uri->s;
00124       _d->hooks.ru.len = _d->hooks.request_uri->len;
00125       _d->hooks.request_uri = &_d->hooks.ru;
00126       get_raw_uri(_d->hooks.request_uri);
00127    }
00128    if ((_d->hooks.next_hop) && (_d->hooks.next_hop->s) && (_d->hooks.next_hop->len)) {
00129       _d->hooks.nh.s = _d->hooks.next_hop->s;
00130       _d->hooks.nh.len = _d->hooks.next_hop->len;
00131       _d->hooks.next_hop = &_d->hooks.nh;
00132       get_raw_uri(_d->hooks.next_hop);
00133    }
00134 
00135    return 0;
00136 }
00137 
00138 
00139 /*!
00140  * \brief Small wrapper to calculate_hooks
00141  * \param _d dialog state
00142  * \return 0 on success, -1 on error
00143  */
00144 int w_calculate_hooks(dlg_t* _d)
00145 {
00146    return calculate_hooks(_d);
00147 }
00148 
00149 
00150 /*!
00151  * \brief Create a new dialog
00152  * \param _cid Callid
00153  * \param _ltag local tag (usually From tag)
00154  * \param _lseq local sequence (usually CSeq)
00155  * \param _luri local URI (usually From)
00156  * \param _ruri remote URI (usually To)
00157  * \param _d dialog state
00158  * \return 0 on success, negative on errors
00159  */
00160 int new_dlg_uac(str* _cid, str* _ltag, unsigned int _lseq, str* _luri, str* _ruri, dlg_t** _d)
00161 {
00162    dlg_t* res;
00163 
00164    if (!_cid || !_ltag || !_luri || !_ruri || !_d) {
00165       LM_ERR("Invalid parameter value\n");
00166       return -1;
00167    }
00168 
00169    res = (dlg_t*)shm_malloc(sizeof(dlg_t));
00170    if (res == 0) {
00171       LM_ERR("No memory left\n");
00172       return -2;
00173    }
00174 
00175         /* Clear everything */   
00176    memset(res, 0, sizeof(dlg_t));
00177    
00178         /* Make a copy of Call-ID */
00179    if (shm_str_dup(&res->id.call_id, _cid) < 0) return -3;
00180         /* Make a copy of local tag (usually From tag) */
00181    if (shm_str_dup(&res->id.loc_tag, _ltag) < 0) return -4;
00182         /* Make a copy of local URI (usually From) */
00183    if (shm_str_dup(&res->loc_uri, _luri) < 0) return -5;
00184         /* Make a copy of remote URI (usually To) */
00185    if (shm_str_dup(&res->rem_uri, _ruri) < 0) return -6;
00186         /* Make a copy of local sequence (usually CSeq) */
00187    res->loc_seq.value = _lseq;
00188         /* And mark it as set */
00189    res->loc_seq.is_set = 1;
00190 
00191    *_d = res;
00192 
00193    if (calculate_hooks(*_d) < 0) {
00194       LM_ERR("failed to calculate hooks\n");
00195       /* FIXME: free everything here */
00196       shm_free(res);
00197       return -2;
00198    }
00199    
00200    return 0;
00201 }
00202 
00203 
00204 /*!
00205  * \brief Store display names into a dialog
00206  * \param _d dialog state
00207  * \param _ldname local display name
00208  * \param _rdname remote display name
00209  * \return 0 on success, negative on error
00210  */
00211 int dlg_add_extra(dlg_t* _d, str* _ldname, str* _rdname)
00212 {
00213    if(!_d || !_ldname || !_rdname)
00214    {
00215       LM_ERR("Invalid parameters\n");
00216       return -1;
00217    }
00218 
00219    /* Make a copy of local Display Name */
00220    if(shm_str_dup(&_d->loc_dname, _ldname) < 0) return -2;
00221    /* Make a copy of remote Display Name */
00222    if(shm_str_dup(&_d->rem_dname, _rdname) < 0) return -3;
00223 
00224    return 0;
00225 }
00226 
00227 
00228 /*!
00229  * \brief Parse Contact header field body and extract URI
00230  * \note Does not parse headers!
00231  * \param _m SIP message
00232  * \param _uri SIP URI
00233  * \return 0 on success, negative on error
00234  */
00235 static inline int get_contact_uri(struct sip_msg* _m, str* _uri)
00236 {
00237    contact_t* c;
00238 
00239    _uri->len = 0;
00240 
00241    if (!_m->contact) return 1;
00242 
00243    if (parse_contact(_m->contact) < 0) {
00244       LM_ERR("failed to parse Contact body\n");
00245       return -2;
00246    }
00247 
00248    c = ((contact_body_t*)_m->contact->parsed)->contacts;
00249 
00250    if (!c) {
00251       LM_ERR("Empty body or * contact\n");
00252       return -3;
00253    }
00254 
00255    _uri->s = c->uri.s;
00256    _uri->len = c->uri.len;
00257    return 0;
00258 }
00259 
00260 
00261 /*!
00262  * \brief Extract tag from To header field of a response
00263  * \note Doesn't parse message headers!
00264  * \param _m SIP message
00265  * \param _tag tag
00266  * \return 0 on success, -1 on error
00267  */
00268 static inline int get_to_tag(struct sip_msg* _m, str* _tag)
00269 {
00270    if (!_m->to) {
00271       LM_ERR("To header field missing\n");
00272       return -1;
00273    }
00274 
00275    if (get_to(_m)->tag_value.len) {
00276       _tag->s = get_to(_m)->tag_value.s;
00277       _tag->len = get_to(_m)->tag_value.len;
00278    } else {
00279       _tag->len = 0;
00280    }
00281 
00282    return 0;
00283 }
00284 
00285 
00286 /*!
00287  * \brief Extract tag from From header field of a request
00288  * \param _m SIP message
00289  * \param _tag tag
00290  * \return 0 on success, -1 on error
00291  */
00292 static inline int get_from_tag(struct sip_msg* _m, str* _tag)
00293 {
00294    if (parse_from_header(_m)<0) {
00295       LM_ERR("failed to parse From header\n");
00296       return -1;
00297    }
00298 
00299    if (get_from(_m)->tag_value.len) {
00300       _tag->s = get_from(_m)->tag_value.s;
00301       _tag->len = get_from(_m)->tag_value.len;
00302    } else {
00303       _tag->len = 0;
00304    }
00305 
00306    return 0;
00307 }
00308 
00309 
00310 /*!
00311  * \brief Extract Call-ID value
00312  * \note Doesn't parse headers!
00313  * \param _m SIP message
00314  * \param _cid Callid
00315  * \return 0 on success, -1 on error
00316  */
00317 static inline int get_callid(struct sip_msg* _m, str* _cid)
00318 {
00319    if (_m->callid == 0) {
00320       LM_ERR("Call-ID not found\n");
00321       return -1;
00322    }
00323 
00324    _cid->s = _m->callid->body.s;
00325    _cid->len = _m->callid->body.len;
00326    trim(_cid);
00327    return 0;
00328 }
00329 
00330 
00331 /*!
00332  * \brief Create a copy of route set either in normal or reverse order
00333  * \param _m SIP message
00334  * \param _rs Route set
00335  * \param _order how to order the copy, set to NORMAL_ORDER for normal copy
00336  * \return 0 on success, -1 on error
00337  */
00338 static inline int get_route_set(struct sip_msg* _m, rr_t** _rs, unsigned char _order)
00339 {
00340    struct hdr_field* ptr;
00341    rr_t* last, *p, *t;
00342    
00343    last = 0;
00344    *_rs = 0;
00345 
00346    ptr = _m->record_route;
00347    while(ptr) {
00348       if (ptr->type == HDR_RECORDROUTE_T) {
00349          if (parse_rr(ptr) < 0) {
00350             LM_ERR("failed to parse Record-Route body\n");
00351             goto error;
00352          }
00353 
00354          p = (rr_t*)ptr->parsed;
00355          while(p) {
00356             if (shm_duplicate_rr(&t, p, 1/*only first*/) < 0) {
00357                LM_ERR("duplicating rr_t\n");
00358                goto error;
00359             }
00360             if (_order == NORMAL_ORDER) {
00361                if (!*_rs) *_rs = t;
00362                if (last) last->next = t;
00363                last = t;
00364             } else {
00365                t->next = *_rs;
00366                *_rs = t;
00367             }
00368 
00369             p = p->next;
00370          }
00371          
00372       }
00373       ptr = ptr->next;
00374    }
00375    
00376    return 0;
00377 
00378  error:
00379         shm_free_rr(_rs);
00380    return -1;
00381 }
00382 
00383 
00384 /*!
00385  * \brief Extract necessary information from response and insert it into dialog
00386  *
00387  * Extract all necessary information from a response and put it in a dialog structure
00388  * \param _m SIP message
00389  * \param _d dialog state
00390  * \return 0 on success, negative on error
00391  */
00392 static inline int response2dlg(struct sip_msg* _m, dlg_t* _d)
00393 {
00394    str contact, rtag;
00395 
00396         /* Parse the whole message, we will need all Record-Route headers */
00397    if (parse_headers(_m, HDR_EOH_F, 0) == -1) {
00398       LM_ERR("failed to parse headers\n");
00399       return -1;
00400    }
00401    
00402    if (get_contact_uri(_m, &contact) < 0) return -2;
00403    if (contact.len && shm_str_dup(&_d->rem_target, &contact) < 0) return -3;
00404    
00405    if (get_to_tag(_m, &rtag) < 0) goto err1;
00406    if (rtag.len && shm_str_dup(&_d->id.rem_tag, &rtag) < 0) goto err1;
00407    
00408    if (get_route_set(_m, &_d->route_set, REVERSE_ORDER) < 0) goto err2;
00409 
00410    return 0;
00411  err2:
00412    if (_d->id.rem_tag.s) shm_free(_d->id.rem_tag.s);
00413    _d->id.rem_tag.s = 0;
00414    _d->id.rem_tag.len = 0;
00415 
00416  err1:
00417    if (_d->rem_target.s) shm_free(_d->rem_target.s);
00418    _d->rem_target.s = 0;
00419    _d->rem_target.len = 0;
00420    return -4;
00421 }
00422 
00423 
00424 /*!
00425  * \brief Handle dialog in DLG_NEW state
00426  *
00427  * Handle dialog in DLG_NEW state, we will be processing the first response
00428  * \param _d dialog state
00429  * \param _m SIP message
00430  * \return 1 if the dialog was destroyed, negative on errors, 0 otherwise
00431  */
00432 static inline int dlg_new_resp_uac(dlg_t* _d, struct sip_msg* _m)
00433 {
00434    int code;
00435         /*
00436          * Dialog is in DLG_NEW state, we will copy remote
00437          * target URI, remote tag if present, and route-set 
00438          * if present. And we will transit into DLG_CONFIRMED 
00439          * if the response was 2xx and to DLG_DESTROYED if the 
00440          * request was a negative final response.
00441          */
00442 
00443    code = _m->first_line.u.reply.statuscode;
00444 
00445    if (code < 200) {
00446            /* A provisional response, do nothing, we could
00447             * update remote tag and route set but we will do that
00448             * for a positive final response anyway and I don't want
00449             * bet on presence of these fields in provisional responses
00450             */
00451    } else if ((code >= 200) && (code < 299)) {
00452            /* A final response, update the structures and transit
00453             * into DLG_CONFIRMED
00454             */
00455       if (response2dlg(_m, _d) < 0) return -1;
00456       _d->state = DLG_CONFIRMED;
00457 
00458       if (calculate_hooks(_d) < 0) {
00459          LM_ERR("failed to calculate hooks\n");
00460          return -2;
00461       }
00462    } else {
00463            /* 
00464             * A negative final response, mark the dialog as destroyed
00465             * Again, I do not update the structures here because it
00466             * makes no sense to me, a dialog shouldn't be used after
00467             * it is destroyed
00468             */
00469       _d->state = DLG_DESTROYED;
00470            /* Signalize the termination with positive return value */
00471       return 1;
00472    }
00473 
00474    return 0;
00475 }
00476 
00477 
00478 /*!
00479  * \brief Handle dialog in DLG_EARLY state
00480  *
00481  * Handle dialog in DLG_EARLY state we will be processing either
00482  * next provisional response or a final response.
00483  * \param _d dialog state
00484  * \param _m SIP message
00485  * \return 1 if the dialog was destroyed, negative on errors, 0 otherwise
00486  */
00487 static inline int dlg_early_resp_uac(dlg_t* _d, struct sip_msg* _m)
00488 {
00489    int code;
00490    code = _m->first_line.u.reply.statuscode; 
00491 
00492    if (code < 200) {
00493            /* We are in early state already, do nothing
00494             */
00495    } else if ((code >= 200) && (code <= 299)) {
00496            /* Same as in dlg_new_resp_uac */
00497            /* A final response, update the structures and transit
00498             * into DLG_CONFIRMED
00499             */
00500       if (response2dlg(_m, _d) < 0) return -1;
00501       _d->state = DLG_CONFIRMED;
00502 
00503       if (calculate_hooks(_d) < 0) {
00504          LM_ERR("failed to calculate hooks\n");
00505          return -2;
00506       }
00507    } else {
00508            /* Else terminate the dialog */
00509       _d->state = DLG_DESTROYED;
00510            /* Signalize the termination with positive return value */
00511       return 1;
00512    }
00513 
00514    return 0;
00515 }
00516 
00517 
00518 /*!
00519  * \brief Extract method from CSeq header field
00520  * \param _m SIP message
00521  * \param _method SIP method
00522  * \return 0 on success, -1 on error
00523  */
00524 static inline int get_cseq_method(struct sip_msg* _m, str* _method)
00525 {
00526    if (!_m->cseq && ((parse_headers(_m, HDR_CSEQ_F, 0)==-1) || !_m->cseq)) {
00527       LM_ERR("failed to parse CSeq\n");
00528       return -1;
00529    }
00530 
00531    _method->s = get_cseq(_m)->method.s;
00532    _method->len = get_cseq(_m)->method.len;
00533    return 0;
00534 }
00535 
00536 
00537 /*!
00538  * \brief Handle dialog in DLG_CONFIRMED state
00539  *
00540  * Handle dialog in DLG_CONFIRMED state, we will be processing
00541  * a response to a request sent within a dialog.
00542  * \param _d dialog state
00543  * \param _m SIP message
00544  * \return 1 if the dialog was destroyed, negative on errors, 0 otherwise
00545  */
00546 static inline int dlg_confirmed_resp_uac(dlg_t* _d, struct sip_msg* _m)
00547 {
00548    int code;
00549    str method, contact;
00550 
00551    code = _m->first_line.u.reply.statuscode;
00552 
00553         /* Dialog has been already confirmed, that means we received
00554          * a response to a request sent within the dialog. We will
00555          * update remote target URI if and only if the message sent was
00556          * a target refresher.
00557          */
00558 
00559         /* FIXME: Currently we support only INVITEs as target refreshers,
00560          * this should be generalized
00561          */
00562 
00563         /* IF we receive a 481 response, terminate the dialog because
00564          * the remote peer indicated that it didn't have the dialog
00565          * state anymore, signal this termination with a positive return
00566          * value
00567          */
00568    if (code == 481) {
00569       _d->state = DLG_DESTROYED;
00570       return 1;
00571    }
00572 
00573    /* Do nothing if not 2xx */
00574    if ((code < 200) || (code >= 300)) return 0;
00575 
00576    if (get_cseq_method(_m, &method) < 0) return -1;
00577    if ((method.len == 6) && !memcmp("INVITE", method.s, 6)) {
00578       /* Get contact if any and update remote target */
00579       if (parse_headers(_m, HDR_CONTACT_F, 0) == -1) {
00580          LM_ERR("failed to parse headers\n");
00581          return -2;
00582       }
00583 
00584       /* Try to extract contact URI */
00585       if (get_contact_uri(_m, &contact) < 0) return -3;
00586       /* If there is a contact URI */
00587       if (contact.len) {
00588          /* Free old remote target if any */
00589          if (_d->rem_target.s) shm_free(_d->rem_target.s);
00590          /* Duplicate new remote target */
00591          if (shm_str_dup(&_d->rem_target, &contact) < 0) return -4;
00592       }
00593    }
00594 
00595    return 0;
00596 }
00597 
00598 
00599 /*!
00600  * \brief A response arrived, update dialog
00601  * \param _d dialog state
00602  * \param _m SIP message
00603  * \return 1 if the dialog was destroyed, negative on errors, 0 otherwise
00604  */
00605 int dlg_response_uac(dlg_t* _d, struct sip_msg* _m)
00606 {
00607    if (!_d || !_m) {
00608       LM_ERR("invalid parameter value\n");
00609       return -1;
00610    }
00611 
00612    /* The main dispatcher */
00613    switch(_d->state) {
00614    case DLG_NEW:
00615       return dlg_new_resp_uac(_d, _m);
00616 
00617    case DLG_EARLY:
00618       return dlg_early_resp_uac(_d, _m);
00619 
00620    case DLG_CONFIRMED:
00621       return dlg_confirmed_resp_uac(_d, _m);
00622 
00623    case DLG_DESTROYED:
00624       LM_ERR("failed handle destroyed dialog\n");
00625       return -2;
00626    }
00627 
00628    LM_ERR("unsuccessful switch statement\n");
00629    return -3;
00630 }
00631 
00632 
00633 /*!
00634  * \brief Get CSeq number
00635  * \note Does not parse headers!
00636  * \param _m SIP message
00637  * \param _cs CSeq number
00638  * \return 0 on success, negative on error
00639  */
00640 static inline int get_cseq_value(struct sip_msg* _m, unsigned int* _cs)
00641 {
00642    str num;
00643 
00644    if (_m->cseq == 0) {
00645       LM_ERR("CSeq header not found\n");
00646       return -1;
00647    }
00648 
00649    num.s = get_cseq(_m)->number.s;
00650    num.len = get_cseq(_m)->number.len;
00651 
00652    trim_leading(&num);
00653    if (str2int(&num, _cs) < 0) {
00654       LM_ERR("converting cseq number failed\n");
00655       return -2;
00656    }
00657    return 0;
00658 }
00659 
00660 
00661 /*!
00662  * \brief Copy To or From URI without tag parameter
00663  * \param _h SIP header
00664  * \param _s target string
00665  * \return 0 on success, -1 on error
00666  */
00667 static inline int get_dlg_uri(struct hdr_field* _h, str* _s)
00668 {
00669    struct to_param* ptr, *prev;
00670    struct to_body* body;
00671    char* tag = 0;
00672    int tag_len = 0, len;
00673 
00674    if (!_h) {
00675       LM_ERR("header field not found\n");
00676       return -1;
00677    }
00678 
00679         /* From was already parsed when extracting tag
00680          * and To is parsed by default
00681          */
00682    
00683    body = (struct to_body*)_h->parsed;
00684 
00685    ptr = body->param_lst;
00686    prev = 0;
00687    while(ptr) {
00688       if (ptr->type == TAG_PARAM) break;
00689       prev = ptr;
00690       ptr = ptr->next;
00691    }
00692 
00693    if (ptr) {
00694            /* Tag param found */
00695       if (prev) {
00696          tag = prev->value.s + prev->value.len;
00697       } else {
00698          tag = body->body.s + body->body.len;
00699       }
00700       
00701       if (ptr->next) {
00702          tag_len = ptr->value.s + ptr->value.len - tag;
00703       } else {
00704          tag_len = _h->body.s + _h->body.len - tag;
00705       }
00706    }
00707 
00708    _s->s = shm_malloc(_h->body.len - tag_len);
00709    if (!_s->s) {
00710       LM_ERR("No share memory left\n");
00711       return -1;
00712    }
00713 
00714    if (tag_len) {
00715       len = tag - _h->body.s;
00716       memcpy(_s->s, _h->body.s, len);
00717       memcpy(_s->s + len, tag + tag_len, _h->body.len - len - tag_len);
00718       _s->len = _h->body.len - tag_len;
00719    } else {
00720       memcpy(_s->s, _h->body.s, _h->body.len);
00721       _s->len = _h->body.len;
00722    }
00723 
00724    return 0;
00725 }
00726 
00727 
00728 /*!
00729  * \brief Extract all information from request and update dialog structure
00730  * \param _m SIP message
00731  * \param _d dialog state
00732  */
00733 static inline int request2dlg(struct sip_msg* _m, dlg_t* _d)
00734 {
00735    str contact, rtag, callid;
00736 
00737    if (parse_headers(_m, HDR_EOH_F, 0) == -1) {
00738       LM_ERR("failed to parse headers");
00739       return -1;
00740    }
00741 
00742    if (get_contact_uri(_m, &contact) < 0) return -2;
00743    if (contact.len && shm_str_dup(&_d->rem_target, &contact) < 0) return -3;
00744    
00745    if (get_from_tag(_m, &rtag) < 0) goto err1;
00746    if (rtag.len && shm_str_dup(&_d->id.rem_tag, &rtag) < 0) goto err1;
00747 
00748    if (get_callid(_m, &callid) < 0) goto err2;
00749    if (callid.len && shm_str_dup(&_d->id.call_id, &callid) < 0) goto err2;
00750 
00751    if (get_cseq_value(_m, &_d->rem_seq.value) < 0) goto err3;
00752    _d->rem_seq.is_set = 1;
00753 
00754    if (get_dlg_uri(_m->from, &_d->rem_uri) < 0) goto err3;
00755    if (get_dlg_uri(_m->to, &_d->loc_uri) < 0) goto err4;
00756 
00757    if (get_route_set(_m, &_d->route_set, NORMAL_ORDER) < 0) goto err5;  
00758 
00759    return 0;
00760  err5:
00761    if (_d->loc_uri.s) shm_free(_d->loc_uri.s);
00762    _d->loc_uri.s = 0;
00763    _d->loc_uri.len = 0;
00764  err4:
00765    if (_d->rem_uri.s) shm_free(_d->rem_uri.s);
00766    _d->rem_uri.s = 0;
00767    _d->rem_uri.len = 0;
00768  err3:
00769    if (_d->id.call_id.s) shm_free(_d->id.call_id.s);
00770    _d->id.call_id.s = 0;
00771    _d->id.call_id.len = 0;
00772  err2:
00773    if (_d->id.rem_tag.s) shm_free(_d->id.rem_tag.s);
00774    _d->id.rem_tag.s = 0;
00775    _d->id.rem_tag.len = 0;
00776  err1:
00777    if (_d->rem_target.s) shm_free(_d->rem_target.s);
00778    _d->rem_target.s = 0;
00779    _d->rem_target.len = 0;
00780    return -4;
00781 }
00782 
00783 
00784 /*!
00785  * \brief Establishing a new dialog from the UAS side
00786  * \param _req SIP request
00787  * \param _code request code
00788  * \param _d dialog state
00789  * \return 0 on success, negative on error
00790  */
00791 int new_dlg_uas(struct sip_msg* _req, int _code, dlg_t** _d)
00792 {
00793    dlg_t* res;
00794    str tag;
00795 
00796    if (!_req || !_d) {
00797       LM_ERR("Invalid parameter value\n");
00798       return -1;
00799    }
00800 
00801    if ((_code < 200) || (_code > 299)) {
00802       LM_DBG("not a 2xx, no dialog created\n");
00803       return -2;
00804    }
00805 
00806    res = (dlg_t*)shm_malloc(sizeof(dlg_t));
00807    if (res == 0) {
00808       LM_ERR("no more share memory\n");
00809       return -3;
00810    }
00811         /* Clear everything */
00812    memset(res, 0, sizeof(dlg_t));   
00813 
00814    if (request2dlg(_req, res) < 0) {
00815       LM_ERR("converting request to dialog failed\n");
00816       return -4;
00817    }
00818 
00819    tag.s = tm_tags;
00820    tag.len = TOTAG_VALUE_LEN;
00821    calc_crc_suffix(_req, tm_tag_suffix);
00822    if (shm_str_dup(&res->id.loc_tag, &tag) < 0) {
00823       free_dlg(res);
00824       return -5;
00825    }
00826    
00827    *_d = res;
00828 
00829    (*_d)->state = DLG_CONFIRMED;
00830    if (calculate_hooks(*_d) < 0) {
00831       LM_ERR("calculating hooks failed\n");
00832       shm_free(*_d);
00833       return -6;
00834    }
00835 
00836    return 0;
00837 }
00838 
00839 
00840 /*!
00841  * \brief UAS side - update a dialog from a request
00842  * \param _d dialog state
00843  * \param _m SIP request
00844  * \return 0 on success, negative on error
00845  */
00846 int dlg_request_uas(dlg_t* _d, struct sip_msg* _m)
00847 {
00848    str contact;
00849    unsigned int cseq;
00850 
00851    if (!_d || !_m) {
00852       LM_ERR("Invalid parameter value\n");
00853       return -1;
00854    }
00855 
00856         /* We must check if the request is not out of order or retransmission
00857          * first, if so then we will not update anything
00858          */
00859    if (parse_headers(_m, HDR_CSEQ_F, 0) == -1) {
00860       LM_ERR("parsing headers failed\n");
00861       return -2;
00862    }
00863    if (get_cseq_value(_m, &cseq) < 0) return -3;
00864    if (_d->rem_seq.is_set && (cseq <= _d->rem_seq.value)) return 0;
00865 
00866         /* Neither out of order nor retransmission -> update */
00867    _d->rem_seq.value = cseq;
00868    _d->rem_seq.is_set = 1;
00869    
00870         /* We will als update remote target URI if the message 
00871          * is target refresher
00872          */
00873    if (_m->first_line.u.request.method_value == METHOD_INVITE) {
00874            /* target refresher */
00875       if (parse_headers(_m, HDR_CONTACT_F, 0) == -1) {
00876          LM_ERR("parsing headers failed\n");
00877          return -4;
00878       }
00879       
00880       if (get_contact_uri(_m, &contact) < 0) return -5;
00881       if (contact.len) {
00882          if (_d->rem_target.s) shm_free(_d->rem_target.s);
00883          if (shm_str_dup(&_d->rem_target, &contact) < 0) return -6;
00884       }
00885    }
00886 
00887    return 0;
00888 }
00889 
00890 
00891 /*!
00892  * \brief Calculate length of the route set
00893  * \param _d dialog set
00894  * \return the length of the route set, can be 0
00895  */
00896 int calculate_routeset_length(dlg_t* _d)
00897 {
00898    int len;
00899    rr_t* ptr;
00900 
00901    len = 0;
00902    ptr = _d->hooks.first_route;
00903 
00904    if (ptr) {
00905       len = ROUTE_PREFIX_LEN;
00906       len += CRLF_LEN;
00907    }
00908 
00909    while(ptr) {
00910       len += ptr->len;
00911       ptr = ptr->next;
00912       if (ptr) len += ROUTE_SEPARATOR_LEN;
00913    } 
00914 
00915    if (_d->hooks.last_route) {
00916       len += ROUTE_SEPARATOR_LEN + 2; /* < > */
00917       len += _d->hooks.last_route->len;
00918    }
00919 
00920    return len;
00921 }
00922 
00923 
00924 /*!
00925  * \brief Print the route set
00926  * \param buf buffer
00927  * \param _d dialog state
00928  * \return pointer to the buffer
00929  */
00930 char* print_routeset(char* buf, dlg_t* _d)
00931 {
00932    rr_t* ptr;
00933 
00934    ptr = _d->hooks.first_route;
00935 
00936    if (ptr || _d->hooks.last_route) {
00937       memcpy(buf, ROUTE_PREFIX, ROUTE_PREFIX_LEN);
00938       buf += ROUTE_PREFIX_LEN;
00939    }
00940 
00941    while(ptr) {
00942       memcpy(buf, ptr->nameaddr.name.s, ptr->len);
00943       buf += ptr->len;
00944 
00945       ptr = ptr->next;
00946       if (ptr) {
00947          memcpy(buf, ROUTE_SEPARATOR, ROUTE_SEPARATOR_LEN);
00948          buf += ROUTE_SEPARATOR_LEN;
00949       }
00950    } 
00951 
00952    if (_d->hooks.last_route) {
00953       if (_d->hooks.first_route) {
00954          memcpy(buf, ROUTE_SEPARATOR, ROUTE_SEPARATOR_LEN);
00955          buf += ROUTE_SEPARATOR_LEN;
00956       }
00957       memcpy(buf, "<", 1);
00958       buf++;
00959       memcpy(buf, _d->hooks.last_route->s, _d->hooks.last_route->len);
00960       buf += _d->hooks.last_route->len;
00961       *buf = '>';
00962       buf++;
00963    }
00964 
00965    if (_d->hooks.first_route || _d->hooks.last_route) {
00966       memcpy(buf, CRLF, CRLF_LEN);
00967       buf += CRLF_LEN;
00968    }
00969 
00970    return buf;
00971 }
00972 
00973 
00974 /*!
00975  * \brief Destroy a dialog state
00976  * \param _d dialog state
00977  */
00978 void free_dlg(dlg_t* _d)
00979 {
00980    if (!_d) return;
00981 
00982    if (_d->id.call_id.s) shm_free(_d->id.call_id.s);
00983    if (_d->id.rem_tag.s) shm_free(_d->id.rem_tag.s);
00984    if (_d->id.loc_tag.s) shm_free(_d->id.loc_tag.s);
00985 
00986    if (_d->loc_uri.s) shm_free(_d->loc_uri.s);
00987    if (_d->rem_uri.s) shm_free(_d->rem_uri.s);
00988    if (_d->rem_target.s) shm_free(_d->rem_target.s);
00989 
00990    if (_d->loc_dname.s) shm_free(_d->loc_dname.s);
00991    if (_d->rem_dname.s) shm_free(_d->rem_dname.s);
00992 
00993    /* Free all routes in the route set */
00994    shm_free_rr(&_d->route_set);
00995    shm_free(_d);
00996 }
00997 
00998 
00999 /*!
01000  * \brief Print a dialog structure, just for debugging
01001  * \param out file
01002  * \param _d dialog state
01003  * \todo why is this included in the TM API exports
01004  */
01005 void print_dlg(FILE* out, dlg_t* _d)
01006 {
01007    fprintf(out, "====dlg_t===\n");
01008    fprintf(out, "id.call_id    : '%.*s'\n",
01009          _d->id.call_id.len, _d->id.call_id.s);
01010    fprintf(out, "id.rem_tag    : '%.*s'\n",
01011          _d->id.rem_tag.len, _d->id.rem_tag.s);
01012    fprintf(out, "id.loc_tag    : '%.*s'\n",
01013          _d->id.loc_tag.len, _d->id.loc_tag.s);
01014    fprintf(out, "loc_seq.value : %d\n", _d->loc_seq.value);
01015    fprintf(out, "loc_seq.is_set: %s\n", _d->loc_seq.is_set ? "YES" : "NO");
01016    fprintf(out, "rem_seq.value : %d\n", _d->rem_seq.value);
01017    fprintf(out, "rem_seq.is_set: %s\n", _d->rem_seq.is_set ? "YES" : "NO");
01018    fprintf(out, "loc_uri       : '%.*s'\n",_d->loc_uri.len, _d->loc_uri.s);
01019    fprintf(out, "rem_uri       : '%.*s'\n",_d->rem_uri.len, _d->rem_uri.s);
01020    fprintf(out, "loc_dname     : '%.*s'\n",_d->loc_dname.len,_d->loc_dname.s);
01021    fprintf(out, "rem_dname     : '%.*s'\n",_d->rem_dname.len,_d->rem_dname.s);
01022    fprintf(out, "rem_target    : '%.*s'\n",
01023          _d->rem_target.len,_d->rem_target.s);
01024    fprintf(out, "state         : ");
01025    switch(_d->state) {
01026    case DLG_NEW:       fprintf(out, "DLG_NEW\n");       break;
01027    case DLG_EARLY:     fprintf(out, "DLG_EARLY\n");     break;
01028    case DLG_CONFIRMED: fprintf(out, "DLG_CONFIRMED\n"); break;
01029    case DLG_DESTROYED: fprintf(out, "DLG_DESTROYED\n"); break;
01030    }
01031    print_rr(out, _d->route_set);
01032    if (_d->hooks.request_uri) 
01033       fprintf(out, "hooks.request_uri: '%.*s'\n",
01034          _d->hooks.request_uri->len, _d->hooks.request_uri->s);
01035    if (_d->hooks.next_hop) 
01036       fprintf(out, "hooks.next_hop   : '%.*s'\n",
01037          _d->hooks.next_hop->len, _d->hooks.next_hop->s);
01038    if (_d->hooks.first_route) 
01039       fprintf(out, "hooks.first_route: '%.*s'\n",
01040          _d->hooks.first_route->len,_d->hooks.first_route->nameaddr.name.s);
01041    if (_d->hooks.last_route)
01042       fprintf(out, "hooks.last_route : '%.*s'\n",
01043          _d->hooks.last_route->len, _d->hooks.last_route->s);
01044    
01045    fprintf(out, "====dlg_t====\n");
01046 }

Generated on Tue May 22 16:00:26 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6