rd_funcs.c

Go to the documentation of this file.
00001 /*
00002  * $Id: rd_funcs.c 4918 2008-09-15 16:53:10Z carstenbock $
00003  *
00004  * Copyright (C) 2005 Voice Sistem SRL
00005  *
00006  * This file is part of Kamailio, a free SIP server.
00007  *
00008  * Kamailio is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU General Public License
00010  * as published by the Free Software Foundation; either version 2
00011  * of the License, or (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  *
00023  * History:
00024  * ---------
00025  *  2005-06-22  first version (bogdan)
00026  *  2006-05-23  push also q value into branches (bogdan)
00027  */
00028 
00029 
00030 #include "../../usr_avp.h"
00031 #include "../../dset.h"
00032 #include "../../dprint.h"
00033 #include "../../qvalue.h"
00034 #include "../../parser/contact/parse_contact.h"
00035 #include "../../qvalue.h"
00036 #include "rd_filter.h"
00037 #include "rd_funcs.h"
00038 
00039 
00040 #define MAX_CONTACTS_PER_REPLY   16
00041 #define DEFAULT_Q_VALUE          10
00042 
00043 static int shmcontact2dset(struct sip_msg *req, struct sip_msg *shrpl,
00044       long max, struct acc_param *reason, unsigned int bflags);
00045 
00046 
00047 int get_redirect( struct sip_msg *msg , int maxt, int maxb,
00048                            struct acc_param *reason, unsigned int bflags)
00049 {
00050    struct cell *t;
00051    str backup_uri;
00052    int max;
00053    int cts_added;
00054    int n;
00055    int i;
00056 
00057    /* get transaction */
00058    t = rd_tmb.t_gett();
00059    if (t==T_UNDEFINED || t==T_NULL_CELL)
00060    {
00061       LM_CRIT("no current transaction found\n");
00062       goto error;
00063    }
00064 
00065    LM_DBG("resume branch=%d\n", t->first_branch);
00066 
00067    cts_added = 0; /* no contact added */
00068    backup_uri = msg->new_uri; /* shmcontact2dset will ater this value */
00069 
00070    /* look if there are any 3xx branches starting from resume_branch */
00071    for( i=t->first_branch ; i<t->nr_of_outgoings ; i++) {
00072       LM_DBG("checking branch=%d (added=%d)\n", i, cts_added);
00073       /* is a redirected branch? */
00074       if (t->uac[i].last_received<300 || t->uac[i].last_received>399)
00075          continue;
00076       LM_DBG("branch=%d is a redirect (added=%d)\n", i, cts_added);
00077       /* ok - we have a new redirected branch -> how many contacts can
00078        * we get from it*/
00079       if (maxb==0) {
00080          max = maxt?(maxt-cts_added):(-1);
00081       } else {
00082          max = maxt?((maxt-cts_added>=maxb)?maxb:(maxt-cts_added)):maxb;
00083       }
00084       if (max==0)
00085          continue;
00086       /* get the contact from it */
00087       n = shmcontact2dset( msg, t->uac[i].reply, max, reason, bflags);
00088       if ( n<0 ) {
00089          LM_ERR("get contact from shm_reply branch %d failed\n",i);
00090          /* do not go to error, try next branches */
00091       } else {
00092          /* count the added contacts */
00093          cts_added += n;
00094       }
00095    }
00096 
00097    /* restore original new_uri */
00098    msg->new_uri = backup_uri;
00099 
00100    /* return false if no contact was appended */
00101    return (cts_added>0)?1:-1;
00102 error:
00103    return -1;
00104 }
00105 
00106 
00107 
00108 /* returns the number of contacts put in the sorted array */
00109 static int sort_contacts(contact_t *ct_list, contact_t **ct_array,
00110                                           qvalue_t *q_array)
00111 {
00112    param_t *q_para;
00113    qvalue_t q;
00114    int n;
00115    int i,j;
00116    char backup;
00117 
00118    n = 0; /* number of sorted contacts */
00119 
00120    for( ; ct_list ; ct_list = ct_list->next ) {
00121       /* check the filters first */
00122       backup = ct_list->uri.s[ct_list->uri.len];
00123       ct_list->uri.s[ct_list->uri.len] = 0;
00124       if ( run_filters( ct_list->uri.s )==-1 ){
00125          ct_list->uri.s[ct_list->uri.len] = backup;
00126          continue;
00127       }
00128       ct_list->uri.s[ct_list->uri.len] = backup;
00129       /* does the contact has a q val? */
00130       q_para = ct_list->q;
00131       if (q_para==0 || q_para->body.len==0) {
00132          q = DEFAULT_Q_VALUE;
00133       } else {
00134          if (str2q( &q, q_para->body.s, q_para->body.len)!=0) {
00135             LM_ERR("invalid q param\n");
00136             /* skip this contact */
00137             continue;
00138          }
00139       }
00140       LM_DBG("sort_contacts: <%.*s> q=%d\n",
00141             ct_list->uri.len,ct_list->uri.s,q);
00142       /*insert the contact into the sorted array */
00143       for(i=0;i<n;i++) {
00144          /* keep in mind that the contact list is reversts */
00145          if (q_array[i]<=q)
00146             continue;
00147          break;
00148       }
00149       if (i!=MAX_CONTACTS_PER_REPLY) {
00150          /* insert the contact at this position */
00151          for( j=n-1-1*(n==MAX_CONTACTS_PER_REPLY) ; j>=i ; j-- ) {
00152             ct_array[j+1] = ct_array[j];
00153             q_array[j+1] = q_array[j];
00154          }
00155          ct_array[j+1] = ct_list;
00156          q_array[j+1] = q;
00157          if (n!=MAX_CONTACTS_PER_REPLY)
00158             n++;
00159       }
00160    }
00161    return n;
00162 }
00163 
00164 
00165 
00166 /* returns : -1 - error
00167  *            0 - ok, but no contact added
00168  *            n - ok and n contacts added
00169  */
00170 static int shmcontact2dset(struct sip_msg *req, struct sip_msg *sh_rpl,
00171                         long max, struct acc_param *reason, unsigned int bflags)
00172 {
00173    static struct sip_msg  dup_rpl;
00174    static contact_t *scontacts[MAX_CONTACTS_PER_REPLY];
00175    static qvalue_t  sqvalues[MAX_CONTACTS_PER_REPLY];
00176    struct hdr_field *hdr;
00177    struct hdr_field *contact_hdr;
00178    contact_t        *contacts;
00179    int n,i;
00180    int added;
00181    int dup;
00182    int ret;
00183 
00184    /* dup can be:
00185     *    0 - sh reply but nothing duplicated 
00186     *    1 - sh reply but only contact body parsed
00187     *    2 - sh reply and contact header and body parsed
00188     *    3 - private reply
00189     */
00190    dup = 0; /* sh_rpl not duplicated */
00191    ret = 0; /* success and no contact added */
00192    contact_hdr = 0;
00193 
00194    if (sh_rpl==0 || sh_rpl==FAKED_REPLY)
00195       return 0;
00196 
00197    if (sh_rpl->contact==0) {
00198       /* contact header is not parsed */
00199       if ( sh_rpl->msg_flags&FL_SHM_CLONE ) {
00200          /* duplicate the reply into private memory to be able 
00201           * to parse it and after words to free the parsed mems */
00202          memcpy( &dup_rpl, sh_rpl, sizeof(struct sip_msg) );
00203          dup = 2;
00204          /* ok -> force the parsing of contact header */
00205          if ( parse_headers( &dup_rpl, HDR_CONTACT_T, 0)<0 ) {
00206             LM_ERR("dup_rpl parse failed\n");
00207             ret = -1;
00208             goto restore;
00209          }
00210          if (dup_rpl.contact==0) {
00211             LM_DBG("contact hdr not found in dup_rpl\n");
00212             goto restore;
00213          }
00214          contact_hdr = dup_rpl.contact;
00215       } else {
00216          dup = 3;
00217          /* force the parsing of contact header */
00218          if ( parse_headers( sh_rpl, HDR_CONTACT_T, 0)<0 ) {
00219             LM_ERR("sh_rpl parse failed\n");
00220             ret = -1;
00221             goto restore;
00222          }
00223          if (sh_rpl->contact==0) {
00224             LM_DBG("contact hdr not found in sh_rpl\n");
00225             goto restore;
00226          }
00227          contact_hdr = sh_rpl->contact;
00228       }
00229    } else {
00230       contact_hdr = sh_rpl->contact;
00231    }
00232 
00233    /* parse the body of contact header */
00234    if (contact_hdr->parsed==0) {
00235       if ( parse_contact(contact_hdr)<0 ) {
00236          LM_ERR("contact hdr parse failed\n");
00237          ret = -1;
00238          goto restore;
00239       }
00240       if (dup==0)
00241          dup = 1;
00242    }
00243 
00244 
00245    /* we have the contact header and its body parsed -> sort the contacts
00246     * based on the q value */
00247    contacts = ((contact_body_t*)contact_hdr->parsed)->contacts;
00248    if (contacts==0) {
00249       LM_DBG("contact hdr has no contacts\n");
00250       goto restore;
00251    }
00252    n = sort_contacts( contacts, scontacts, sqvalues);
00253    if (n==0) {
00254       LM_DBG("no contacts left after filtering\n");
00255       goto restore;
00256    }
00257 
00258    /* to many branches ? */
00259    if (max!=-1 && n>max)
00260       n = max;
00261 
00262    added = 0;
00263 
00264    /* add the sortet contacts as branches in dset and log this! */
00265    for ( i=0 ; i<n ; i++ ) {
00266       LM_DBG("adding contact <%.*s>\n", scontacts[i]->uri.len, scontacts[i]->uri.s);
00267       if (append_branch( 0, &scontacts[i]->uri, 0, 0, sqvalues[i], bflags, 0)<0) {
00268          LM_ERR("failed to add contact to dset\n");
00269       } else {
00270          added++;
00271          if (rd_acc_fct!=0 && reason) {
00272             /* log the redirect */
00273             req->new_uri =  scontacts[i]->uri;
00274             //FIXME
00275             rd_acc_fct( req, (char*)reason, acc_db_table, NULL, NULL, NULL, NULL);
00276          }
00277       }
00278    }
00279 
00280    ret = (added==0)?-1:added;
00281 restore:
00282    if (dup==1) {
00283       free_contact( (contact_body_t**)(void*)(&contact_hdr->parsed) );
00284    } else if (dup==2) {
00285       /* are any new headers found? */
00286       if (dup_rpl.last_header!=sh_rpl->last_header) {
00287          /* identify in the new headere list (from dup_rpl) 
00288           * the sh_rpl->last_header and start remove everything after */
00289          hdr = sh_rpl->last_header;
00290          free_hdr_field_lst(hdr->next);
00291          hdr->next=0;
00292       }
00293    }
00294    return ret;
00295 
00296 }
00297 

Generated on Thu May 24 08:00:53 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6