dispatch.c

Go to the documentation of this file.
00001 /*
00002  * $Id: dispatch.c 5554 2009-02-02 14:05:17Z miconda $
00003  *
00004  * dispatcher module
00005  *
00006  * Copyright (C) 2004-2006 FhG Fokus
00007  * Copyright (C) 2005 Voice-System.ro
00008  *
00009  * This file is part of Kamailio, a free SIP server.
00010  *
00011  * Kamailio is free software; you can redistribute it and/or modify
00012  * it under the terms of the GNU General Public License as published by
00013  * the Free Software Foundation; either version 2 of the License, or
00014  * (at your option) any later version
00015  *
00016  * Kamailio is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License 
00022  * along with this program; if not, write to the Free Software 
00023  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00024  *
00025  * History
00026  * -------
00027  * 2004-07-31  first version, by daniel
00028  * 2005-04-22  added ruri  & to_uri hashing (andrei)
00029  * 2005-12-10  added failover support via avp (daniel)
00030  * 2006-08-15  added support for authorization username hashing (carsten)
00031  * 2007-01-11  Added a function to check if a specific gateway is in a
00032  * group (carsten)
00033  * 2007-01-12  Added a threshhold for automatic deactivation (carsten)
00034  * 2007-02-09  Added active probing of failed destinations and automatic
00035  * re-enabling of destinations (carsten)
00036  * 2007-05-08  Ported the changes to SVN-Trunk, renamed ds_is_domain to
00037  * ds_is_from_list and modified the function to work with IPv6 adresses.
00038  * 2007-07-18  removed index stuff 
00039  *             added DB support to load/reload data(ancuta)
00040  * 2007-09-17  added list-file support for reload data (carstenbock)
00041  */
00042 
00043 /*! \file
00044  * \ingroup dispatcher
00045  * \brief Dispatcher :: Dispatch
00046  */
00047 
00048 #include <stdio.h>
00049 #include <string.h>
00050 #include <stdlib.h>
00051 
00052 #include "../../ut.h"
00053 #include "../../trim.h"
00054 #include "../../dprint.h"
00055 #include "../../action.h"
00056 #include "../../route.h"
00057 #include "../../dset.h"
00058 #include "../../mem/shm_mem.h"
00059 #include "../../parser/parse_uri.h"
00060 #include "../../parser/parse_from.h"
00061 #include "../../usr_avp.h"
00062 #include "../../mi/mi.h"
00063 #include "../../parser/digest/digest.h"
00064 #include "../../resolve.h"
00065 #include "../tm/tm_load.h"
00066 #include "../../db/db.h"
00067 #include "../../db/db_res.h"
00068 #include "../../str.h"
00069 
00070 #include "dispatch.h"
00071 
00072 #define DS_TABLE_VERSION   1
00073 #define DS_TABLE_VERSION2  2
00074 #define DS_TABLE_VERSION3  3
00075 
00076 static int _ds_table_version = DS_TABLE_VERSION;
00077 
00078 typedef struct _ds_dest
00079 {
00080    str uri;
00081    int flags;
00082    int priority;
00083    struct ip_addr ip_address;    /*!< IP-Address of the entry */
00084    unsigned short int port;   /*!< Port of the request URI */
00085    int failure_count;
00086    struct _ds_dest *next;
00087 } ds_dest_t, *ds_dest_p;
00088 
00089 typedef struct _ds_set
00090 {
00091    int id;           /*!< id of dst set */
00092    int nr;           /*!< number of items in dst set */
00093    int last;         /*!< last used item in dst set */
00094    ds_dest_p dlist;
00095    struct _ds_set *next;
00096 } ds_set_t, *ds_set_p;
00097 
00098 extern int ds_force_dst;
00099 
00100 static db_func_t ds_dbf;
00101 static db_con_t* ds_db_handle=0;
00102 ds_set_p *ds_lists=NULL;
00103 int *ds_list_nr = NULL;
00104 int *crt_idx    = NULL;
00105 int *next_idx   = NULL;
00106 
00107 #define _ds_list  (ds_lists[*crt_idx])
00108 #define _ds_list_nr (*ds_list_nr)
00109 
00110 void destroy_list(int);
00111 
00112 static int ds_print_sets(void)
00113 {
00114    ds_set_p si = NULL;
00115    int i;
00116 
00117    if(_ds_list==NULL)
00118       return -1;
00119    
00120    /* get the index of the set */
00121    si = _ds_list;
00122    while(si)
00123    {
00124       for(i=0; i<si->nr; i++)
00125       {
00126          LM_DBG("dst>> %d %.*s %d %d\n", si->id,
00127                si->dlist[i].uri.len, si->dlist[i].uri.s,
00128                si->dlist[i].flags, si->dlist[i].priority);
00129       }
00130       si = si->next;
00131    }
00132 
00133    return 0;
00134 }
00135 
00136 int init_data(void)
00137 {
00138    int * p;
00139 
00140    ds_lists = (ds_set_p*)shm_malloc(2*sizeof(ds_set_p));
00141    if(!ds_lists)
00142    {
00143       LM_ERR("Out of memory\n");
00144       return -1;
00145    }
00146    ds_lists[0] = ds_lists[1] = 0;
00147 
00148    
00149    p = (int*)shm_malloc(3*sizeof(int));
00150    if(!p)
00151    {
00152       LM_ERR("Out of memory\n");
00153       return -1;
00154    }
00155 
00156    crt_idx = p;
00157    next_idx = p+1;
00158    ds_list_nr = p+2;
00159    *crt_idx= *next_idx = 0;
00160 
00161    return 0;
00162 }
00163 
00164 int add_dest2list(int id, str uri, int flags, int priority, int list_idx,
00165       int * setn)
00166 {
00167    ds_dest_p dp = NULL;
00168    ds_set_p  sp = NULL;
00169    ds_dest_p dp0 = NULL;
00170    ds_dest_p dp1 = NULL;
00171    
00172    /* For DNS-Lookups */
00173    static char hn[256];
00174    struct hostent* he;
00175    struct sip_uri puri;
00176 
00177    /* check uri */
00178    if(parse_uri(uri.s, uri.len, &puri)!=0 || puri.host.len>254)
00179    {
00180       LM_ERR("bad uri [%.*s]\n", uri.len, uri.s);
00181       goto err;
00182    }
00183    
00184    /* get dest set */
00185    sp = ds_lists[list_idx];
00186    while(sp)
00187    {
00188       if(sp->id == id)
00189          break;
00190       sp = sp->next;
00191    }
00192 
00193    if(sp==NULL)
00194    {
00195       sp = (ds_set_p)shm_malloc(sizeof(ds_set_t));
00196       if(sp==NULL)
00197       {
00198          LM_ERR("no more memory.\n");
00199          goto err;
00200       }
00201       
00202       memset(sp, 0, sizeof(ds_set_t));
00203       sp->next = ds_lists[list_idx];
00204       ds_lists[list_idx] = sp;
00205       *setn = *setn+1;
00206    }
00207    sp->id = id;
00208    sp->nr++;
00209 
00210    /* store uri */
00211    dp = (ds_dest_p)shm_malloc(sizeof(ds_dest_t));
00212    if(dp==NULL)
00213    {
00214       LM_ERR("no more memory!\n");
00215       goto err;
00216    }
00217    memset(dp, 0, sizeof(ds_dest_t));
00218 
00219    dp->uri.s = (char*)shm_malloc((uri.len+1)*sizeof(char));
00220    if(dp->uri.s==NULL)
00221    {
00222       LM_ERR("no more memory!\n");
00223       goto err;
00224    }
00225    strncpy(dp->uri.s, uri.s, uri.len);
00226    dp->uri.s[uri.len]='\0';
00227    dp->uri.len = uri.len;
00228    dp->flags = flags;
00229    dp->priority = priority;
00230 
00231    /* The Hostname needs to be \0 terminated for resolvehost, so we
00232     * make a copy here. */
00233    strncpy(hn, puri.host.s, puri.host.len);
00234    hn[puri.host.len]='\0';
00235       
00236    /* Do a DNS-Lookup for the Host-Name: */
00237    he=resolvehost(hn, 1);
00238    if (he==0)
00239    {
00240       LM_ERR("could not resolve %.*s\n", puri.host.len, puri.host.s);
00241       pkg_free(hn);
00242       goto err;
00243    }
00244    /* Free the hostname */
00245    hostent2ip_addr(&dp->ip_address, he, 0);
00246       
00247    /* Copy the Port out of the URI: */
00248    dp->port = puri.port_no;      
00249 
00250    if(sp->dlist==NULL)
00251    {
00252       sp->dlist = dp;
00253    } else {
00254       dp1 = NULL;
00255       dp0 = sp->dlist;
00256       /* highest priority last -> reindex will copy backwards */
00257       while(dp0) {
00258          if(dp0->priority > dp->priority)
00259             break;
00260          dp1 = dp0;
00261          dp0=dp0->next;
00262       }
00263       if(dp1==NULL)
00264       {
00265          dp->next = sp->dlist;
00266          sp->dlist = dp;
00267       } else {
00268          dp->next  = dp1->next;
00269          dp1->next = dp;
00270       }
00271    }
00272 
00273    LM_DBG("dest [%d/%d] <%.*s>\n", sp->id, sp->nr, dp->uri.len, dp->uri.s);
00274    
00275    return 0;
00276 err:
00277    /* free allocated memory */
00278    if(dp!=NULL)
00279    {
00280       if(dp->uri.s!=NULL)
00281          shm_free(dp->uri.s);
00282       shm_free(dp);
00283    }
00284    return -1;
00285 }
00286 
00287 /*! \brief  compact destinations from sets for fast access */
00288 int reindex_dests(int list_idx, int setn)
00289 {
00290    int j;
00291    ds_set_p  sp = NULL;
00292    ds_dest_p dp = NULL, dp0= NULL;
00293 
00294    for(sp = ds_lists[list_idx]; sp!= NULL;   sp->dlist = dp0, sp = sp->next)
00295    {
00296       dp0 = (ds_dest_p)shm_malloc(sp->nr*sizeof(ds_dest_t));
00297       if(dp0==NULL)
00298       {
00299          LM_ERR("no more memory!\n");
00300          goto err1;
00301       }
00302       memset(dp0, 0, sp->nr*sizeof(ds_dest_t));
00303 
00304       /*copy from the old pointer to destination, and then free it*/
00305       for(j=sp->nr-1; j>=0 && sp->dlist!= NULL; j--)
00306       {
00307          memcpy(&dp0[j], sp->dlist, sizeof(ds_dest_t));
00308          if(j==sp->nr-1)
00309             dp0[j].next = NULL;
00310          else
00311             dp0[j].next = &dp0[j+1];
00312    
00313          dp = sp->dlist;
00314          sp->dlist = dp->next;
00315          
00316          shm_free(dp);
00317          dp=NULL;
00318       }
00319    }
00320 
00321    LM_DBG("found [%d] dest sets\n", setn);
00322    return 0;
00323 
00324 err1:
00325    return -1;
00326 }
00327 
00328 /*! \brief load groups of destinations from file */
00329 int ds_load_list(char *lfile)
00330 {
00331    char line[256], *p;
00332    FILE *f = NULL;
00333    int id, setn, flags, priority;
00334    str uri;
00335    
00336    if( (*crt_idx) != (*next_idx)) {
00337       LM_WARN("load command already generated, aborting reload...\n");
00338       return 0;
00339    }
00340 
00341    if(lfile==NULL || strlen(lfile)<=0)
00342    {
00343       LM_ERR("bad list file\n");
00344       return -1;
00345    }
00346 
00347    f = fopen(lfile, "r");
00348    if(f==NULL)
00349    {
00350       LM_ERR("can't open list file [%s]\n", lfile);
00351       return -1;
00352       
00353    }
00354 
00355    id = setn = flags = priority = 0;
00356 
00357    *next_idx = (*crt_idx + 1)%2;
00358    destroy_list(*next_idx);
00359    
00360    p = fgets(line, 256, f);
00361    while(p)
00362    {
00363       /* eat all white spaces */
00364       while(*p && (*p==' ' || *p=='\t' || *p=='\r' || *p=='\n'))
00365          p++;
00366       if(*p=='\0' || *p=='#')
00367          goto next_line;
00368       
00369       /* get set id */
00370       id = 0;
00371       while(*p>='0' && *p<='9')
00372       {
00373          id = id*10+ (*p-'0');
00374          p++;
00375       }
00376       
00377       /* eat all white spaces */
00378       while(*p && (*p==' ' || *p=='\t' || *p=='\r' || *p=='\n'))
00379          p++;
00380       if(*p=='\0' || *p=='#')
00381       {
00382          LM_ERR("bad line [%s]\n", line);
00383          goto error;
00384       }
00385 
00386       /* get uri */
00387       uri.s = p;
00388       while(*p && *p!=' ' && *p!='\t' && *p!='\r' && *p!='\n' && *p!='#')
00389          p++;
00390       uri.len = p-uri.s;
00391 
00392       /* eat all white spaces */
00393       while(*p && (*p==' ' || *p=='\t' || *p=='\r' || *p=='\n'))
00394          p++;
00395       
00396       /* get flags */
00397       flags = 0;
00398       priority = 0;
00399       if(*p=='\0' || *p=='#')
00400          goto add_destination; /* no flags given */
00401 
00402       while(*p>='0' && *p<='9')
00403       {
00404          flags = flags*10+ (*p-'0');
00405          p++;
00406       }
00407       
00408       /* eat all white spaces */
00409       while(*p && (*p==' ' || *p=='\t' || *p=='\r' || *p=='\n'))
00410          p++;
00411       
00412       /* get priority */
00413       priority = 0;
00414       if(*p=='\0' || *p=='#')
00415          goto add_destination; /* no priority given */
00416 
00417       while(*p>='0' && *p<='9')
00418       {
00419          priority = priority*10+ (*p-'0');
00420          p++;
00421       }
00422       
00423 add_destination:
00424       if(add_dest2list(id, uri, flags, priority, *next_idx, &setn) != 0)
00425          goto error;
00426                
00427       
00428 next_line:
00429       p = fgets(line, 256, f);
00430    }
00431       
00432    if(reindex_dests(*next_idx, setn)!=0){
00433       LM_ERR("error on reindex\n");
00434       goto error;
00435    }
00436 
00437    fclose(f);
00438    f = NULL;
00439    /* Update list */
00440    _ds_list_nr = setn;
00441    *crt_idx = *next_idx;
00442    ds_print_sets();
00443    return 0;
00444 
00445 error:
00446    if(f!=NULL)
00447       fclose(f);
00448    destroy_list(*next_idx);
00449    *next_idx = *crt_idx; 
00450    return -1;
00451 }
00452 
00453 int ds_connect_db(void)
00454 {
00455    if(!ds_db_url.s)
00456       return -1;
00457 
00458    if (ds_db_handle)
00459    {
00460       LM_CRIT("BUG - db connection found already open\n");
00461       return -1;
00462    }
00463 
00464    if ((ds_db_handle = ds_dbf.init(&ds_db_url)) == 0){
00465       
00466          return -1;
00467    }
00468    return 0;
00469 }
00470 
00471 void ds_disconnect_db(void)
00472 {
00473    if(ds_db_handle)
00474    {
00475       ds_dbf.close(ds_db_handle);
00476       ds_db_handle = 0;
00477    }
00478 }
00479 
00480 /*! \brief Initialize and verify DB stuff*/
00481 int init_ds_db(void)
00482 {
00483    int ret;
00484 
00485    if(ds_table_name.s == 0)
00486    {
00487       LM_ERR("invalid database name\n");
00488       return -1;
00489    }
00490    
00491    /* Find a database module */
00492    if (db_bind_mod(&ds_db_url, &ds_dbf) < 0)
00493    {
00494       LM_ERR("Unable to bind to a database driver\n");
00495       return -1;
00496    }
00497    
00498    if(ds_connect_db()!=0){
00499       
00500       LM_ERR("unable to connect to the database\n");
00501       return -1;
00502    }
00503    
00504    _ds_table_version = db_table_version(&ds_dbf, ds_db_handle, &ds_table_name);
00505    if (_ds_table_version < 0) 
00506    {
00507       LM_ERR("failed to query table version\n");
00508       return -1;
00509    } else if (_ds_table_version != DS_TABLE_VERSION
00510          && _ds_table_version != DS_TABLE_VERSION2
00511          && _ds_table_version != DS_TABLE_VERSION3) {
00512       LM_ERR("invalid table version (found %d , required %d, %d or %d)\n"
00513          "(use kamdbctl reinit)\n",
00514          _ds_table_version, DS_TABLE_VERSION, DS_TABLE_VERSION2,
00515          DS_TABLE_VERSION3);
00516       return -1;
00517    }
00518 
00519    ret = ds_load_db();
00520 
00521    ds_disconnect_db();
00522 
00523    return ret;
00524 }
00525 
00526 /*! \brief load groups of destinations from DB*/
00527 int ds_load_db(void)
00528 {
00529    int i, id, nr_rows, setn;
00530    int flags;
00531    int priority;
00532    int nrcols;
00533    str uri;
00534    db_res_t * res;
00535    db_val_t * values;
00536    db_row_t * rows;
00537    
00538    db_key_t query_cols[4] = {&ds_set_id_col, &ds_dest_uri_col,
00539                         &ds_dest_flags_col, &ds_dest_priority_col};
00540    
00541    nrcols = 2;
00542    if(_ds_table_version == DS_TABLE_VERSION2)
00543       nrcols = 3;
00544    else if(_ds_table_version == DS_TABLE_VERSION3)
00545       nrcols = 4;
00546 
00547    if( (*crt_idx) != (*next_idx))
00548    {
00549       LM_WARN("load command already generated, aborting reload...\n");
00550       return 0;
00551    }
00552 
00553    if(ds_db_handle == NULL){
00554          LM_ERR("invalid DB handler\n");
00555          return -1;
00556    }
00557 
00558    if (ds_dbf.use_table(ds_db_handle, &ds_table_name) < 0)
00559    {
00560       LM_ERR("error in use_table\n");
00561       return -1;
00562    }
00563 
00564    /*select the whole table and all the columns*/
00565    if(ds_dbf.query(ds_db_handle,0,0,0,query_cols,0,nrcols,0,&res) < 0)
00566    {
00567       LM_ERR("error while querying database\n");
00568       return -1;
00569    }
00570 
00571    nr_rows = RES_ROW_N(res);
00572    rows  = RES_ROWS(res);
00573    if(nr_rows == 0)
00574    {
00575       LM_WARN("no dispatching data in the db -- empty destination set\n");
00576       ds_dbf.free_result(ds_db_handle, res);
00577       return 0;
00578    }
00579 
00580    setn = 0;
00581    *next_idx = (*crt_idx + 1)%2;
00582    destroy_list(*next_idx);
00583    
00584    for(i=0; i<nr_rows; i++)
00585    {
00586       values = ROW_VALUES(rows+i);
00587 
00588       id = VAL_INT(values);
00589       uri.s = VAL_STR(values+1).s;
00590       uri.len = strlen(uri.s);
00591       flags = 0;
00592       if(nrcols>=3)
00593          flags = VAL_INT(values+2);
00594       priority=0;
00595       if(nrcols>=4)
00596          priority = VAL_INT(values+3);
00597 
00598       if(add_dest2list(id, uri, flags, priority, *next_idx, &setn) != 0)
00599          goto err2;
00600 
00601    }
00602    ds_dbf.free_result(ds_db_handle, res);
00603 
00604    if(reindex_dests(*next_idx, setn)!=0)
00605    {
00606       LM_ERR("error on reindex\n");
00607       goto err2;
00608    }
00609 
00610    /*update data*/
00611    _ds_list_nr = setn;
00612    *crt_idx = *next_idx;
00613 
00614    ds_print_sets();
00615 
00616    return 0;
00617 
00618 err2:
00619    destroy_list(*next_idx);
00620    ds_dbf.free_result(ds_db_handle, res);
00621    *next_idx = *crt_idx; 
00622 
00623    return -1;
00624 }
00625 
00626 /*! \brief called from dispatcher.c: free all*/
00627 int ds_destroy_list(void)
00628 {
00629    if (ds_lists) {
00630       destroy_list(0);
00631       destroy_list(1);
00632       shm_free(ds_lists);
00633    }
00634 
00635    if (crt_idx)
00636       shm_free(crt_idx);
00637 
00638    return 0;
00639 }
00640 
00641 void destroy_list(int list_id)
00642 {
00643    ds_set_p  sp = NULL;
00644    ds_dest_p dest = NULL;
00645 
00646    sp = ds_lists[list_id];
00647 
00648    while(sp)
00649    {
00650       for(dest = sp->dlist; dest!= NULL; dest=dest->next)
00651       {
00652          if(dest->uri.s!=NULL)
00653             {
00654                shm_free(dest->uri.s);
00655                dest->uri.s = NULL;
00656             }
00657       }
00658       shm_free(sp->dlist);
00659       sp = sp->next;
00660    }
00661    
00662    ds_lists[list_id]  = NULL;
00663 }
00664 
00665 /**
00666  *
00667  */
00668 unsigned int ds_get_hash(str *x, str *y)
00669 {
00670    char* p;
00671    register unsigned v;
00672    register unsigned h;
00673 
00674    if(!x && !y)
00675       return 0;
00676    h=0;
00677    if(x)
00678    {
00679       p=x->s;
00680       if (x->len>=4)
00681       {
00682          for (; p<=(x->s+x->len-4); p+=4)
00683          {
00684             v=(*p<<24)+(p[1]<<16)+(p[2]<<8)+p[3];
00685             h+=v^(v>>3);
00686          }
00687       }
00688       v=0;
00689       for (;p<(x->s+x->len); p++)
00690       { 
00691          v<<=8; 
00692          v+=*p;
00693       }
00694       h+=v^(v>>3);
00695    }
00696    if(y)
00697    {
00698       p=y->s;
00699       if (y->len>=4) 
00700       {
00701          for (; p<=(y->s+y->len-4); p+=4)
00702          {
00703             v=(*p<<24)+(p[1]<<16)+(p[2]<<8)+p[3];
00704             h+=v^(v>>3);
00705          }
00706       }
00707    
00708       v=0;
00709       for (;p<(y->s+y->len); p++)
00710       { 
00711          v<<=8; 
00712          v+=*p;
00713       }
00714       h+=v^(v>>3);
00715    }
00716    h=((h)+(h>>11))+((h>>13)+(h>>23));
00717 
00718    return (h)?h:1;
00719 }
00720 
00721 
00722 /*! \brief
00723  * gets the part of the uri we will use as a key for hashing
00724  * \param  key1       - will be filled with first part of the key
00725  *                       (uri user or "" if no user)
00726  * \param  key2       - will be filled with the second part of the key
00727  *                       (uri host:port)
00728  * \param  uri        - str with the whole uri
00729  * \param  parsed_uri - struct sip_uri pointer with the parsed uri
00730  *                       (it must point inside uri). It can be null
00731  *                       (in this case the uri will be parsed internally).
00732  * \param  flags  -    if & DS_HASH_USER_ONLY, only the user part of the uri
00733  *                      will be used
00734  * \return: -1 on error, 0 on success
00735  */
00736 static inline int get_uri_hash_keys(str* key1, str* key2,
00737                      str* uri, struct sip_uri* parsed_uri, int flags)
00738 {
00739    struct sip_uri tmp_p_uri; /* used only if parsed_uri==0 */
00740    
00741    if (parsed_uri==0)
00742    {
00743       if (parse_uri(uri->s, uri->len, &tmp_p_uri)<0)
00744       {
00745          LM_ERR("invalid uri %.*s\n", uri->len, uri->len?uri->s:"");
00746          goto error;
00747       }
00748       parsed_uri=&tmp_p_uri;
00749    }
00750    /* uri sanity checks */
00751    if (parsed_uri->host.s==0)
00752    {
00753          LM_ERR("invalid uri, no host present: %.*s\n",
00754                uri->len, uri->len?uri->s:"");
00755          goto error;
00756    }
00757    
00758    /* we want: user@host:port if port !=5060
00759     *          user@host if port==5060
00760     *          user if the user flag is set*/
00761    *key1=parsed_uri->user;
00762    key2->s=0;
00763    key2->len=0;
00764    if (!(flags & DS_HASH_USER_ONLY))
00765    {  /* key2=host */
00766       *key2=parsed_uri->host;
00767       /* add port if needed */
00768       if (parsed_uri->port.s!=0)
00769       { /* uri has a port */
00770          /* skip port if == 5060 or sips and == 5061 */
00771          if (parsed_uri->port_no !=
00772                ((parsed_uri->type==SIPS_URI_T)?SIPS_PORT:SIP_PORT))
00773             key2->len+=parsed_uri->port.len+1 /* ':' */;
00774       }
00775    }
00776    if (key1->s==0)
00777    {
00778       LM_WARN("empty username in: %.*s\n", uri->len, uri->len?uri->s:"");
00779    }
00780    return 0;
00781 error:
00782    return -1;
00783 }
00784 
00785 
00786 
00787 /**
00788  *
00789  */
00790 int ds_hash_fromuri(struct sip_msg *msg, unsigned int *hash)
00791 {
00792    str from;
00793    str key1;
00794    str key2;
00795    
00796    if(msg==NULL || hash == NULL)
00797    {
00798       LM_ERR("bad parameters\n");
00799       return -1;
00800    }
00801    
00802    if(parse_from_header(msg)<0)
00803    {
00804       LM_ERR("cannot parse From hdr\n");
00805       return -1;
00806    }
00807    
00808    if(msg->from==NULL || get_from(msg)==NULL)
00809    {
00810       LM_ERR("cannot get From uri\n");
00811       return -1;
00812    }
00813    
00814    from   = get_from(msg)->uri;
00815    trim(&from);
00816    if (get_uri_hash_keys(&key1, &key2, &from, 0, ds_flags)<0)
00817       return -1;
00818    *hash = ds_get_hash(&key1, &key2);
00819    
00820    return 0;
00821 }
00822 
00823 
00824 
00825 /**
00826  *
00827  */
00828 int ds_hash_touri(struct sip_msg *msg, unsigned int *hash)
00829 {
00830    str to;
00831    str key1;
00832    str key2;
00833    
00834    if(msg==NULL || hash == NULL)
00835    {
00836       LM_ERR("bad parameters\n");
00837       return -1;
00838    }
00839    if ((msg->to==0) && ((parse_headers(msg, HDR_TO_F, 0)==-1) ||
00840             (msg->to==0)))
00841    {
00842       LM_ERR("cannot parse To hdr\n");
00843       return -1;
00844    }
00845    
00846    
00847    to   = get_to(msg)->uri;
00848    trim(&to);
00849    
00850    if (get_uri_hash_keys(&key1, &key2, &to, 0, ds_flags)<0)
00851       return -1;
00852    *hash = ds_get_hash(&key1, &key2);
00853    
00854    return 0;
00855 }
00856 
00857 
00858 
00859 /**
00860  *
00861  */
00862 int ds_hash_callid(struct sip_msg *msg, unsigned int *hash)
00863 {
00864    str cid;
00865    if(msg==NULL || hash == NULL)
00866    {
00867       LM_ERR("bad parameters\n");
00868       return -1;
00869    }
00870    
00871    if(msg->callid==NULL && ((parse_headers(msg, HDR_CALLID_F, 0)==-1) ||
00872             (msg->callid==NULL)) )
00873    {
00874       LM_ERR("cannot parse Call-Id\n");
00875       return -1;
00876    }
00877    
00878    cid.s   = msg->callid->body.s;
00879    cid.len = msg->callid->body.len;
00880    trim(&cid);
00881    
00882    *hash = ds_get_hash(&cid, NULL);
00883    
00884    return 0;
00885 }
00886 
00887 
00888 
00889 int ds_hash_ruri(struct sip_msg *msg, unsigned int *hash)
00890 {
00891    str* uri;
00892    str key1;
00893    str key2;
00894    
00895    
00896    if(msg==NULL || hash == NULL)
00897    {
00898       LM_ERR("bad parameters\n");
00899       return -1;
00900    }
00901    if (parse_sip_msg_uri(msg)<0){
00902       LM_ERR("bad request uri\n");
00903       return -1;
00904    }
00905    
00906    uri=GET_RURI(msg);
00907    if (get_uri_hash_keys(&key1, &key2, uri, &msg->parsed_uri, ds_flags)<0)
00908       return -1;
00909    
00910    *hash = ds_get_hash(&key1, &key2);
00911    return 0;
00912 }
00913 
00914 int ds_hash_authusername(struct sip_msg *msg, unsigned int *hash)
00915 {
00916    /* Header, which contains the authorization */
00917    struct hdr_field* h = 0;
00918    /* The Username */
00919    str username = {0, 0};
00920    /* The Credentials from this request */
00921    auth_body_t* cred;
00922    
00923    if(msg==NULL || hash == NULL)
00924    {
00925       LM_ERR("bad parameters\n");
00926       return -1;
00927    }
00928    if (parse_headers(msg, HDR_PROXYAUTH_F, 0) == -1)
00929    {
00930       LM_ERR("error parsing headers!\n");
00931       return -1;
00932    }
00933    if (msg->proxy_auth && !msg->proxy_auth->parsed)
00934       parse_credentials(msg->proxy_auth);
00935    if (msg->proxy_auth && msg->proxy_auth->parsed) {
00936       h = msg->proxy_auth;
00937    }
00938    if (!h)
00939    {
00940       if (parse_headers(msg, HDR_AUTHORIZATION_F, 0) == -1)
00941       {
00942          LM_ERR("error parsing headers!\n");
00943          return -1;
00944       }
00945       if (msg->authorization && !msg->authorization->parsed)
00946          parse_credentials(msg->authorization);
00947       if (msg->authorization && msg->authorization->parsed) {
00948          h = msg->authorization;
00949       }
00950    }
00951    if (!h)
00952    {
00953       LM_DBG("No Authorization-Header!\n");
00954       return 1;
00955    }
00956 
00957    cred=(auth_body_t*)(h->parsed);
00958    if (!cred || !cred->digest.username.user.len)
00959    {
00960       LM_ERR("No Authorization-Username or Credentials!\n");
00961       return 1;
00962    }
00963    
00964    username.s = cred->digest.username.user.s;
00965    username.len = cred->digest.username.user.len;
00966 
00967    trim(&username);
00968    
00969    *hash = ds_get_hash(&username, NULL);
00970    
00971    return 0;
00972 }
00973 
00974 
00975 int ds_hash_pvar(struct sip_msg *msg, unsigned int *hash)
00976 {
00977    /* The String to create the hash */
00978    str hash_str = {0, 0};
00979    
00980    if(msg==NULL || hash == NULL || hash_param_model == NULL)
00981    {
00982       LM_ERR("bad parameters\n");
00983       return -1;
00984    }
00985    if (pv_printf_s(msg, hash_param_model, &hash_str)<0) {
00986       LM_ERR("error - cannot print the format\n");
00987       return -1;
00988    }
00989 
00990    /* Remove empty spaces */
00991    trim(&hash_str);
00992    if (hash_str.len <= 0) {
00993       LM_ERR("String is empty!\n");
00994       return -1;
00995    }
00996    LM_DBG("Hashing %.*s!\n", hash_str.len, hash_str.s);
00997 
00998    *hash = ds_get_hash(&hash_str, NULL);
00999    
01000    return 0;
01001 }
01002 
01003 static inline int ds_get_index(int group, ds_set_p *index)
01004 {
01005    ds_set_p si = NULL;
01006    
01007    if(index==NULL || group<0 || _ds_list==NULL)
01008       return -1;
01009    
01010    /* get the index of the set */
01011    si = _ds_list;
01012    while(si)
01013    {
01014       if(si->id == group)
01015       {
01016          *index = si;
01017          break;
01018       }
01019       si = si->next;
01020    }
01021 
01022    if(si==NULL)
01023    {
01024       LM_ERR("destination set [%d] not found\n", group);
01025       return -1;
01026    }
01027 
01028    return 0;
01029 }
01030 
01031 static inline int ds_update_dst(struct sip_msg *msg, str *uri, int mode)
01032 {
01033    struct action act;
01034    str *duri = NULL;
01035    switch(mode)
01036    {
01037       case 1:
01038          act.type = SET_HOSTALL_T;
01039          act.elem[0].type = STRING_ST;
01040          if(uri->len>4 
01041                && strncasecmp(uri->s,"sip:",4)==0)
01042             act.elem[0].u.string = uri->s+4;
01043          else
01044             act.elem[0].u.string = uri->s;
01045          act.next = 0;
01046    
01047          if (do_action(&act, msg) < 0) {
01048             LM_ERR("error while setting host\n");
01049             return -1;
01050          }
01051       break;
01052       default:
01053          duri = uri;
01054          if (set_dst_uri(msg, uri) < 0) {
01055             LM_ERR("error while setting dst uri\n");
01056             return -1;
01057          }  
01058       break;
01059    }
01060    if(ds_append_branch!=0 && route_type==FAILURE_ROUTE)
01061    {
01062       if (append_branch(msg, 0, duri, 0, Q_UNSPECIFIED, 0, 0)!=1 )
01063       {
01064          LM_ERR("append_branch action failed\n");
01065          return -1;
01066       }
01067    }
01068    return 0;
01069 }
01070 
01071 /**
01072  *
01073  */
01074 int ds_select_dst(struct sip_msg *msg, int set, int alg, int mode)
01075 {
01076    int i, cnt;
01077    unsigned int hash;
01078    int_str avp_val;
01079    ds_set_p idx = NULL;
01080 
01081    if(msg==NULL)
01082    {
01083       LM_ERR("bad parameters\n");
01084       return -1;
01085    }
01086    
01087    if(_ds_list==NULL || _ds_list_nr<=0)
01088    {
01089       LM_ERR("no destination sets\n");
01090       return -1;
01091    }
01092 
01093    if((mode==0) && (ds_force_dst==0)
01094          && (msg->dst_uri.s!=NULL || msg->dst_uri.len>0))
01095    {
01096       LM_ERR("destination already set [%.*s]\n", msg->dst_uri.len,
01097             msg->dst_uri.s);
01098       return -1;
01099    }
01100    
01101 
01102    /* get the index of the set */
01103    if(ds_get_index(set, &idx)!=0)
01104    {
01105       LM_ERR("destination set [%d] not found\n", set);
01106       return -1;
01107    }
01108    
01109    LM_DBG("set [%d]\n", set);
01110 
01111    hash = 0;
01112    switch(alg)
01113    {
01114       case 0:
01115          if(ds_hash_callid(msg, &hash)!=0)
01116          {
01117             LM_ERR("can't get callid hash\n");
01118             return -1;
01119          }
01120       break;
01121       case 1:
01122          if(ds_hash_fromuri(msg, &hash)!=0)
01123          {
01124             LM_ERR("can't get From uri hash\n");
01125             return -1;
01126          }
01127       break;
01128       case 2:
01129          if(ds_hash_touri(msg, &hash)!=0)
01130          {
01131             LM_ERR("can't get To uri hash\n");
01132             return -1;
01133          }
01134       break;
01135       case 3:
01136          if (ds_hash_ruri(msg, &hash)!=0)
01137          {
01138             LM_ERR("can't get ruri hash\n");
01139             return -1;
01140          }
01141       break;
01142       case 4:
01143          hash = idx->last;
01144          idx->last = (idx->last+1) % idx->nr;
01145       break;
01146       case 5:
01147          i = ds_hash_authusername(msg, &hash);
01148          switch (i)
01149          {
01150             case 0:
01151                /* Authorization-Header found: Nothing to be done here */
01152             break;
01153             case 1:
01154                /* No Authorization found: Use round robin */
01155                hash = idx->last;
01156                idx->last = (idx->last+1) % idx->nr;
01157             break;
01158             default:
01159                LM_ERR("can't get authorization hash\n");
01160                return -1;
01161             break;
01162          }
01163       break;
01164       case 6:
01165          hash = rand() % idx->nr;
01166       break;
01167       case 7:
01168          if (ds_hash_pvar(msg, &hash)!=0)
01169          {
01170             LM_ERR("can't get PV hash\n");
01171             return -1;
01172          }
01173       break;      
01174       case 8:
01175          /* use first entry */
01176          hash = 0;
01177       break;
01178       default:
01179          LM_WARN("algo %d not implemented - using first entry...\n", alg);
01180          hash = 0;
01181    }
01182 
01183    LM_DBG("alg hash [%u]\n", hash);
01184    cnt = 0;
01185 
01186    if(ds_use_default!=0 && idx->nr!=1)
01187       hash = hash%(idx->nr-1);
01188    else
01189       hash = hash%idx->nr;
01190    i=hash;
01191    while ((idx->dlist[i].flags & DS_INACTIVE_DST)
01192          || (idx->dlist[i].flags & DS_PROBING_DST))
01193    {
01194       if(ds_use_default!=0)
01195          i = (i+1)%(idx->nr-1);
01196       else
01197          i = (i+1)%idx->nr;
01198       if(i==hash)
01199       {
01200          if(ds_use_default!=0)
01201          {
01202             i = idx->nr-1;
01203          } else {
01204             return -1;
01205          }
01206       }
01207    }
01208 
01209    hash = i;
01210 
01211    if(ds_update_dst(msg, &idx->dlist[hash].uri, mode)!=0)
01212    {
01213       LM_ERR("cannot set dst addr\n");
01214       return -1;
01215    }
01216    /* if alg is round-robin then update the shortcut to next to be used */
01217    if(alg==4)
01218       idx->last = (hash+1) % idx->nr;
01219    
01220    LM_DBG("selected [%d-%d/%d] <%.*s>\n", alg, set, hash,
01221          idx->dlist[hash].uri.len, idx->dlist[hash].uri.s);
01222 
01223    if(!(ds_flags&DS_FAILOVER_ON))
01224       return 1;
01225 
01226    if(dst_avp_name.n!=0)
01227    {
01228       if(ds_use_default!=0 && hash!=idx->nr-1)
01229       {
01230          avp_val.s = idx->dlist[idx->nr-1].uri;
01231          if(add_avp(AVP_VAL_STR|dst_avp_type, dst_avp_name, avp_val)!=0)
01232             return -1;
01233          cnt++;
01234       }
01235    
01236       /* add to avp */
01237 
01238       for(i=hash-1; i>=0; i--)
01239       {  
01240          if((idx->dlist[i].flags & DS_INACTIVE_DST)
01241                || (ds_use_default!=0 && i==(idx->nr-1)))
01242             continue;
01243          LM_DBG("using entry [%d/%d]\n", set, i);
01244          avp_val.s = idx->dlist[i].uri;
01245          if(add_avp(AVP_VAL_STR|dst_avp_type, dst_avp_name, avp_val)!=0)
01246             return -1;
01247          cnt++;
01248       }
01249 
01250       for(i=idx->nr-1; i>hash; i--)
01251       {  
01252          if((idx->dlist[i].flags & DS_INACTIVE_DST)
01253                || (ds_use_default!=0 && i==(idx->nr-1)))
01254             continue;
01255          LM_DBG("using entry [%d/%d]\n", set, i);
01256          avp_val.s = idx->dlist[i].uri;
01257          if(add_avp(AVP_VAL_STR|dst_avp_type, dst_avp_name, avp_val)!=0)
01258             return -1;
01259          cnt++;
01260       }
01261    
01262       /* add to avp the first used dst */
01263       avp_val.s = idx->dlist[hash].uri;
01264       if(add_avp(AVP_VAL_STR|dst_avp_type, dst_avp_name, avp_val)!=0)
01265          return -1;
01266       cnt++;
01267    }
01268 
01269    if(grp_avp_name.n!=0)
01270    {
01271       /* add to avp the group id */
01272       avp_val.n = set;
01273       if(add_avp(grp_avp_type, grp_avp_name, avp_val)!=0)
01274          return -1;
01275    }
01276 
01277    if(cnt_avp_name.n!=0)
01278    {
01279       /* add to avp the number of dst */
01280       avp_val.n = cnt;
01281       if(add_avp(cnt_avp_type, cnt_avp_name, avp_val)!=0)
01282          return -1;
01283    }
01284    
01285    return 1;
01286 }
01287 
01288 int ds_next_dst(struct sip_msg *msg, int mode)
01289 {
01290    struct usr_avp *avp;
01291    struct usr_avp *prev_avp;
01292    int_str avp_value;
01293    
01294    if(!(ds_flags&DS_FAILOVER_ON) || dst_avp_name.n==0)
01295    {
01296       LM_WARN("failover support disabled\n");
01297       return -1;
01298    }
01299 
01300 
01301    prev_avp = search_first_avp(dst_avp_type, dst_avp_name, &avp_value, 0);
01302    if(prev_avp==NULL)
01303       return -1; /* used avp deleted -- strange */
01304 
01305    avp = search_next_avp(prev_avp, &avp_value);
01306    destroy_avp(prev_avp);
01307    if(avp==NULL || !(avp->flags&AVP_VAL_STR))
01308       return -1; /* no more avps or value is int */
01309    
01310    if(ds_update_dst(msg, &avp_value.s, mode)!=0)
01311    {
01312       LM_ERR("cannot set dst addr\n");
01313       return -1;
01314    }
01315    LM_DBG("using [%.*s]\n", avp_value.s.len, avp_value.s.s);
01316    
01317    return 1;
01318 }
01319 
01320 int ds_mark_dst(struct sip_msg *msg, int mode)
01321 {
01322    int group, ret;
01323    struct usr_avp *prev_avp;
01324    int_str avp_value;
01325    
01326    if(!(ds_flags&DS_FAILOVER_ON))
01327    {
01328       LM_WARN("failover support disabled\n");
01329       return -1;
01330    }
01331 
01332    prev_avp = search_first_avp(grp_avp_type, grp_avp_name, &avp_value, 0);
01333    
01334    if(prev_avp==NULL || prev_avp->flags&AVP_VAL_STR)
01335       return -1; /* grp avp deleted -- strange */
01336    group = avp_value.n;
01337    
01338    prev_avp = search_first_avp(dst_avp_type, dst_avp_name, &avp_value, 0);
01339    
01340    if(prev_avp==NULL || !(prev_avp->flags&AVP_VAL_STR))
01341       return -1; /* dst avp deleted -- strange */
01342    
01343    if(mode==1) {
01344       ret = ds_set_state(group, &avp_value.s, 
01345             DS_INACTIVE_DST|DS_PROBING_DST, 0);
01346    } else if(mode==2) {
01347       ret = ds_set_state(group, &avp_value.s, DS_PROBING_DST, 1);
01348       if (ret == 0) ret = ds_set_state(group, &avp_value.s,
01349             DS_INACTIVE_DST, 0);
01350    } else {
01351       ret = ds_set_state(group, &avp_value.s, DS_INACTIVE_DST, 1);
01352       if (ret == 0) ret = ds_set_state(group, &avp_value.s,
01353             DS_PROBING_DST, 0);
01354    }
01355    
01356    LM_DBG("mode [%d] grp [%d] dst [%.*s]\n", mode, group, avp_value.s.len,
01357          avp_value.s.s);
01358    
01359    return (ret==0)?1:-1;
01360 }
01361 
01362 int ds_set_state(int group, str *address, int state, int type)
01363 {
01364    int i=0;
01365    ds_set_p idx = NULL;
01366 
01367    if(_ds_list==NULL || _ds_list_nr<=0)
01368    {
01369       LM_ERR("the list is null\n");
01370       return -1;
01371    }
01372    
01373    /* get the index of the set */
01374    if(ds_get_index(group, &idx)!=0)
01375    {
01376       LM_ERR("destination set [%d] not found\n", group);
01377       return -1;
01378    }
01379 
01380    while(i<idx->nr)
01381    {
01382       if(idx->dlist[i].uri.len==address->len 
01383             && strncasecmp(idx->dlist[i].uri.s, address->s,
01384                address->len)==0)
01385       {
01386          
01387          /* remove the Probing/Inactive-State? Set the fail-count to 0. */
01388          if (state == DS_PROBING_DST) {
01389             if (type) {
01390                if (idx->dlist[i].flags & DS_INACTIVE_DST) {
01391                   LM_INFO("Ignoring the request to set this destination"
01392                         " to probing: It is already inactive!\n");
01393                   return 0;
01394                }
01395                
01396                idx->dlist[i].failure_count++;
01397                /* Fire only, if the Threshold is reached. */
01398                if (idx->dlist[i].failure_count 
01399                      < probing_threshhold) return 0;
01400                if (idx->dlist[i].failure_count
01401                      > probing_threshhold) 
01402                   idx->dlist[i].failure_count
01403                      = probing_threshhold;            
01404             }
01405          }
01406          /* Reset the Failure-Counter */
01407          if ((state & DS_RESET_FAIL_DST) > 0) {
01408             idx->dlist[i].failure_count = 0;
01409             state &= ~DS_RESET_FAIL_DST;
01410          }
01411          
01412          if(type)
01413             idx->dlist[i].flags |= state;
01414          else
01415             idx->dlist[i].flags &= ~state;
01416             
01417          return 0;
01418       }
01419       i++;
01420    }
01421 
01422    return -1;
01423 }
01424 
01425 int ds_print_list(FILE *fout)
01426 {
01427    int j;
01428    ds_set_p list;
01429       
01430    if(_ds_list==NULL || _ds_list_nr<=0)
01431    {
01432       LM_ERR("no destination sets\n");
01433       return -1;
01434    }
01435    
01436    fprintf(fout, "\nnumber of destination sets: %d\n", _ds_list_nr);
01437    
01438    for(list = _ds_list; list!= NULL; list= list->next)
01439    {
01440       for(j=0; j<list->nr; j++)
01441       {
01442          fprintf(fout, "\n set #%d\n", list->id);
01443       
01444          if (list->dlist[j].flags&DS_INACTIVE_DST)
01445             fprintf(fout, "    Disabled         ");
01446          else if (list->dlist[j].flags&DS_PROBING_DST)
01447             fprintf(fout, "    Probing          ");
01448          else {
01449             fprintf(fout, "    Active");
01450             /* Optional: Print the tries for this host. */
01451             if (list->dlist[j].failure_count > 0) {
01452                fprintf(fout, " (Fail %d/%d)",
01453                      list->dlist[j].failure_count,
01454                      probing_threshhold);
01455             } else {
01456                fprintf(fout, "           ");
01457             }
01458          }
01459   
01460          fprintf(fout, "   %.*s\n",
01461             list->dlist[j].uri.len, list->dlist[j].uri.s);     
01462       }
01463    }
01464    return 0;
01465 }
01466 
01467 
01468 /* Checks, if the request (sip_msg *_m) comes from a host in a group
01469  * (group-id or -1 for all groups)
01470  */
01471 int ds_is_from_list(struct sip_msg *_m, int group)
01472 {
01473    pv_value_t val;
01474    ds_set_p list;
01475    int j;
01476 
01477    memset(&val, 0, sizeof(pv_value_t));
01478    val.flags = PV_VAL_INT|PV_TYPE_INT;
01479 
01480    for(list = _ds_list; list!= NULL; list= list->next)
01481    {
01482       // LM_ERR("list id: %d (n: %d)\n", list->id, list->nr);
01483       if ((group == -1) || (group == list->id))
01484       {
01485          for(j=0; j<list->nr; j++)
01486          {
01487             // LM_ERR("port no: %d (%d)\n", list->dlist[j].port, j);
01488             if (ip_addr_cmp(&_m->rcv.src_ip, &list->dlist[j].ip_address)
01489                   && (list->dlist[j].port==0
01490                   || _m->rcv.src_port == list->dlist[j].port))
01491             {
01492                if(group==-1 && ds_setid_pvname.s!=0)
01493                {
01494                   val.ri = list->id;
01495                   if(ds_setid_pv.setf(_m, &ds_setid_pv.pvp,
01496                         (int)EQ_T, &val)<0)
01497                   {
01498                      LM_ERR("setting PV failed\n");
01499                      return -2;
01500                   }
01501                }
01502                return 1;
01503             }
01504          }
01505       }
01506    }
01507    return -1;
01508 }
01509 
01510 
01511 int ds_print_mi_list(struct mi_node* rpl)
01512 {
01513    int len, j;
01514    char* p;
01515    char c;
01516    ds_set_p list;
01517    struct mi_node* node = NULL;
01518    struct mi_node* set_node = NULL;
01519    struct mi_attr* attr = NULL;
01520    
01521    if(_ds_list==NULL || _ds_list_nr<=0)
01522    {
01523       LM_ERR("no destination sets\n");
01524       return  0;
01525    }
01526 
01527    p= int2str(_ds_list_nr, &len); 
01528    node = add_mi_node_child(rpl, MI_DUP_VALUE, "SET_NO",6, p, len);
01529    if(node== NULL)
01530       return -1;
01531 
01532    for(list = _ds_list; list!= NULL; list= list->next)
01533    {
01534       p = int2str(list->id, &len);
01535       set_node= add_mi_node_child(rpl, MI_DUP_VALUE,"SET", 3, p, len);
01536       if(set_node == NULL)
01537          return -1;
01538 
01539       for(j=0; j<list->nr; j++)
01540       {
01541          node= add_mi_node_child(set_node, 0, "URI", 3,
01542                list->dlist[j].uri.s, list->dlist[j].uri.len);
01543          if(node == NULL)
01544             return -1;
01545   
01546          if (list->dlist[j].flags & DS_INACTIVE_DST) c = 'I';
01547          else if (list->dlist[j].flags & DS_PROBING_DST) c = 'P';
01548          else c = 'A';
01549   
01550          attr = add_mi_attr (node, MI_DUP_VALUE, "flag",4, &c, 1);
01551          if(attr == 0)
01552             return -1;
01553   
01554       }
01555    }
01556 
01557    return 0;
01558 }
01559 
01560 /*! \brief
01561  * Callback-Function for the OPTIONS-Request
01562  * This Function is called, as soon as the Transaction is finished
01563  * (e. g. a Response came in, the timeout was hit, ...)
01564  * 
01565  */ 
01566 static void ds_options_callback( struct cell *t, int type,
01567       struct tmcb_params *ps )
01568 {
01569    int group = 0;
01570    str uri = {0, 0};
01571    /* The Param does contain the group, in which the failed host
01572     * can be found.*/
01573    if (!*ps->param)
01574    {
01575       LM_DBG("No parameter provided, OPTIONS-Request was finished"
01576             " with code %d\n", ps->code);
01577       return;
01578    }
01579    /* The param is a (void*) Pointer, so we need to dereference it and
01580     *  cast it to an int. */
01581    group = (int)(long)(*ps->param);
01582    /* The SIP-URI is taken from the Transaction.
01583     * Remove the "To: " (s+4) and the trailing new-line (s - 4 (To: )
01584     * - 2 (\r\n)). */
01585    uri.s = t->to.s + 4;
01586    uri.len = t->to.len - 6;
01587    LM_DBG("OPTIONS-Request was finished with code %d (to %.*s, group %d)\n",
01588          ps->code, uri.len, uri.s, group);
01589    /* ps->code contains the result-code of the request.
01590     * 
01591     * We accept both a "200 OK", "501 Not supported" and "403" as an
01592     * successful reply.
01593     *   501: Cisco-Gateways reply with a "501 Not supported" to the request.
01594     *   403: Aastra-Gateways reply with a "403" to the request.
01595     *   405: Some GWs reply with a "405 Method Not Allowed" to the request. */
01596    if ((ps->code == 200) || (ps->code == 501) || (ps->code == 403) || (ps->code == 405))
01597    {
01598       /* Set the according entry back to "Active":
01599        *  remove the Probing/Inactive Flag and reset the failure counter. */
01600       if (ds_set_state(group, &uri,
01601                DS_INACTIVE_DST|DS_PROBING_DST|DS_RESET_FAIL_DST, 0) != 0)
01602       {
01603          LM_ERR("Setting the state failed (%.*s, group %d)\n", uri.len,
01604                uri.s, group);
01605       }
01606    }
01607    if(ds_probing_mode==1 && ps->code == 408)
01608    {
01609       if (ds_set_state(group, &uri, DS_PROBING_DST, 1) != 0)
01610       {
01611          LM_ERR("Setting the probing state failed (%.*s, group %d)\n",
01612                uri.len, uri.s, group);
01613       }
01614    }
01615 
01616    return;
01617 }
01618 
01619 /*! \brief
01620  * Timer for checking inactive destinations
01621  * 
01622  * This timer is regularly fired.
01623  */
01624 void ds_check_timer(unsigned int ticks, void* param)
01625 {
01626    int j;
01627    ds_set_p list;
01628    
01629    /* Check for the list. */
01630    if(_ds_list==NULL || _ds_list_nr<=0)
01631    {
01632       LM_ERR("no destination sets\n");
01633       return;
01634    }
01635 
01636    /* Iterate over the groups and the entries of each group: */
01637    for(list = _ds_list; list!= NULL; list= list->next)
01638    {
01639       for(j=0; j<list->nr; j++) 
01640       {
01641          /* If the Flag of the entry has "Probing set, send a probe: */
01642          if (ds_probing_mode==1 ||
01643                (list->dlist[j].flags&DS_PROBING_DST) != 0)
01644          {
01645             LM_DBG("probing set #%d, URI %.*s\n", list->id,
01646                   list->dlist[j].uri.len, list->dlist[j].uri.s);
01647             
01648             /* Send ping using TM-Module.
01649              * int request(str* m, str* ruri, str* to, str* from, str* h,
01650              *    str* b, str *oburi,
01651              *    transaction_cb cb, void* cbp); */
01652             if (tmb.t_request(&ds_ping_method,
01653                      &list->dlist[j].uri,
01654                      &list->dlist[j].uri,
01655                      &ds_ping_from,
01656                      NULL,
01657                      NULL,
01658                      NULL,
01659                      ds_options_callback,
01660                      (void*)(long)list->id) < 0) {
01661                LM_ERR("unable to ping [%.*s]\n",
01662                      list->dlist[j].uri.len, list->dlist[j].uri.s);
01663             }
01664          }
01665       }
01666    }
01667 }

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