reg_mod.c

Go to the documentation of this file.
00001 /*
00002  * $Id: reg_mod.c 5503 2009-01-23 13:07:41Z carstenbock $
00003  *
00004  * Registrar module interface
00005  *
00006  * Copyright (C) 2001-2003 FhG Fokus
00007  *
00008  * This file is part of Kamailio, a free SIP server.
00009  *
00010  * Kamailio is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version
00014  *
00015  * Kamailio is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License 
00021  * along with this program; if not, write to the Free Software 
00022  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023  *
00024  * History:
00025  * --------
00026  *  2003-03-11  updated to the new module exports interface (andrei)
00027  *  2003-03-16  flags export parameter added (janakj)
00028  *  2003-03-21  save_noreply added, provided by Maxim Sobolev
00029  *              <sobomax@portaone.com> (janakj)
00030  *  2005-07-11  added sip_natping_flag for nat pinging with SIP method
00031  *              instead of UDP package (bogdan)
00032  *  2006-09-19  AOR may be provided via an AVP instead of being fetched
00033  *              from URI (bogdan)
00034  *  2006-10-04  removed the "desc_time_order" parameter, as its functionality
00035  *              was moved to usrloc (Carsten Bock, BASIS AudioNet GmbH)
00036  *  2006-11-22  save_noreply and save_memory merged into save();
00037  *              removed the module parameter "use_domain" - now it is
00038  *              imported from usrloc module (bogdan)
00039  *  2006-11-28  Added statistics tracking for the number of accepted/rejected
00040  *              registrations, as well as for the max expiry time, max 
00041  *              contacts and default expiry time(Jeffrey Magder-SOMA Networks)
00042  *  2007-02-24  sip_natping_flag moved into branch flags, so migrated to 
00043  *              nathelper module (bogdan)
00044  *
00045  */
00046 
00047 /*!
00048  * \defgroup registrar Registrar :: SIP Registrar support
00049  * The module contains REGISTER processing logic.
00050  */  
00051 
00052 /*!
00053  * \file
00054  * \brief SIP registrar module - interface
00055  * \ingroup registrar   
00056  *
00057  * - Module: \ref registrar
00058  */  
00059 
00060 #include <stdio.h>
00061 #include "../../sr_module.h"
00062 #include "../../timer.h"
00063 #include "../../dprint.h"
00064 #include "../../error.h"
00065 #include "../../socket_info.h"
00066 #include "../../pvar.h"
00067 #include "../usrloc/ul_mod.h"
00068 #include "../sl/sl_api.h"
00069 #include "../../mod_fix.h"
00070 
00071 #include "save.h"
00072 #include "lookup.h"
00073 #include "regpv.h"
00074 #include "reply.h"
00075 #include "reg_mod.h"
00076 
00077 
00078 MODULE_VERSION
00079 
00080 
00081 /*! \brief Module init & destroy function */
00082 static int  mod_init(void);
00083 static int  child_init(int);
00084 static void mod_destroy(void);
00085 /*! \brief Fixup functions */
00086 static int domain_fixup(void** param, int param_no);
00087 static int save_fixup(void** param, int param_no);
00088 static int unreg_fixup(void** param, int param_no);
00089 static int fetchc_fixup(void** param, int param_no);
00090 /*! \brief Functions */
00091 static int add_sock_hdr(struct sip_msg* msg, char *str, char *foo);
00092 
00093 
00094 int default_expires = 3600;         /*!< Default expires value in seconds */
00095 qvalue_t default_q  = Q_UNSPECIFIED;      /*!< Default q value multiplied by 1000 */
00096 int append_branches = 1;         /*!< If set to 1, lookup will put all contacts found in msg structure */
00097 int case_sensitive  = 0;         /*!< If set to 1, username in aor will be case sensitive */
00098 int tcp_persistent_flag = -1;       /*!< if the TCP connection should be kept open */
00099 int min_expires     = 60;        /*!< Minimum expires the phones are allowed to use in seconds
00100                    * use 0 to switch expires checking off */
00101 int max_expires     = 0;         /*!< Maximum expires the phones are allowed to use in seconds,
00102                    * use 0 to switch expires checking off */
00103 int max_contacts = 0;            /*!< Maximum number of contacts per AOR (0=no checking) */
00104 int retry_after = 0;          /*!< The value of Retry-After HF in 5xx replies */
00105 int method_filtering = 0;        /*!< if the looked up contacts should be filtered based on supported methods */
00106 int path_enabled = 0;            /*!< if the Path HF should be handled */
00107 int path_mode = PATH_MODE_STRICT;      /*!< if the Path HF should be inserted in the reply.
00108          *   - STRICT (2): always insert, error if no support indicated in request
00109          *   - LAZY   (1): insert only if support indicated in request
00110          *   - OFF    (0): never insert */
00111 
00112 int path_use_params = 0;         /*!< if the received- and nat-parameters of last Path uri should be used
00113                    * to determine if UAC is nat'ed */
00114 
00115 char *aor_avp_param =0;          /*!< if instead of extacting the AOR from the request, it should be 
00116                    * fetched via this AVP ID */
00117 unsigned short aor_avp_type=0;
00118 int_str aor_avp_name;
00119 
00120 /* Populate this AVP if testing for specific registration instance. */
00121 char *reg_callid_avp_param = 0;
00122 unsigned short reg_callid_avp_type = 0;
00123 int_str reg_callid_avp_name;
00124 
00125 char* rcv_avp_param = 0;
00126 unsigned short rcv_avp_type = 0;
00127 int_str rcv_avp_name;
00128 
00129 int reg_use_domain = 0;
00130 char* realm_pref    = "";           /*!< Realm prefix to be removed */
00131 str realm_prefix;
00132 
00133 int sock_flag = -1;
00134 str sock_hdr_name = {0,0};
00135 
00136 #define RCV_NAME "received"
00137 str rcv_param = str_init(RCV_NAME);
00138 
00139 stat_var *accepted_registrations;
00140 stat_var *rejected_registrations;
00141 stat_var *max_expires_stat;
00142 stat_var *max_contacts_stat;
00143 stat_var *default_expire_stat;
00144 
00145 /** SL binds */
00146 struct sl_binds slb;
00147 
00148 /*! \brief
00149  * Exported PV
00150  */
00151 static pv_export_t mod_pvs[] = {
00152    { {"ulc", sizeof("ulc")-1}, PVT_OTHER, pv_get_ulc, pv_set_ulc,
00153       pv_parse_ulc_name, pv_parse_index, 0, 0 },
00154    { {0, 0}, 0, 0, 0, 0, 0, 0, 0 }
00155 };
00156 
00157 
00158 /*! \brief
00159  * Exported functions
00160  */
00161 static cmd_export_t cmds[] = {
00162    {"save",         (cmd_function)save,         1,    save_fixup, 0,
00163          REQUEST_ROUTE | ONREPLY_ROUTE },
00164    {"save",         (cmd_function)save,         2,    save_fixup, 0,
00165          REQUEST_ROUTE | ONREPLY_ROUTE },
00166    {"lookup",       (cmd_function)lookup,       1,  domain_fixup, 0,
00167          REQUEST_ROUTE | FAILURE_ROUTE },
00168    {"registered",   (cmd_function)registered,   1,  domain_fixup, 0,
00169          REQUEST_ROUTE | FAILURE_ROUTE },
00170    {"add_sock_hdr", (cmd_function)add_sock_hdr, 1,fixup_str_null, 0,
00171          REQUEST_ROUTE },
00172    {"unregister",   (cmd_function)unregister,   2,   unreg_fixup, 0,
00173          REQUEST_ROUTE| FAILURE_ROUTE },
00174    {"reg_fetch_contacts", (cmd_function)pv_fetch_contacts, 3, 
00175          fetchc_fixup, 0,
00176          REQUEST_ROUTE| FAILURE_ROUTE },
00177    {"reg_free_contacts", (cmd_function)pv_free_contacts,   1,
00178          fixup_str_null, 0,
00179          REQUEST_ROUTE| FAILURE_ROUTE },
00180    {0, 0, 0, 0, 0, 0}
00181 };
00182 
00183 
00184 /*! \brief
00185  * Exported parameters
00186  */
00187 static param_export_t params[] = {
00188    {"default_expires",    INT_PARAM, &default_expires     },
00189    {"default_q",          INT_PARAM, &default_q           },
00190    {"append_branches",    INT_PARAM, &append_branches     },
00191    {"case_sensitive",     INT_PARAM, &case_sensitive      },
00192    {"tcp_persistent_flag",INT_PARAM, &tcp_persistent_flag },
00193    {"realm_prefix",       STR_PARAM, &realm_pref          },
00194    {"min_expires",        INT_PARAM, &min_expires         },
00195    {"max_expires",        INT_PARAM, &max_expires         },
00196    {"received_param",     STR_PARAM, &rcv_param           },
00197    {"received_avp",       STR_PARAM, &rcv_avp_param       },
00198    {"aor_avp",            STR_PARAM, &aor_avp_param       },
00199    {"reg_callid_avp",     STR_PARAM, &reg_callid_avp_param},
00200    {"max_contacts",       INT_PARAM, &max_contacts        },
00201    {"retry_after",        INT_PARAM, &retry_after         },
00202    {"sock_flag",          INT_PARAM, &sock_flag           },
00203    {"sock_hdr_name",      STR_PARAM, &sock_hdr_name.s     },
00204    {"method_filtering",   INT_PARAM, &method_filtering    },
00205    {"use_path",           INT_PARAM, &path_enabled        },
00206    {"path_mode",          INT_PARAM, &path_mode           },
00207    {"path_use_received",  INT_PARAM, &path_use_params     },
00208    {0, 0, 0}
00209 };
00210 
00211 
00212 /*! \brief We expose internal variables via the statistic framework below.*/
00213 stat_export_t mod_stats[] = {
00214    {"max_expires",       STAT_NO_RESET, &max_expires_stat        },
00215    {"max_contacts",      STAT_NO_RESET, &max_contacts_stat       },
00216    {"default_expire",    STAT_NO_RESET, &default_expire_stat     },
00217    {"accepted_regs",                 0, &accepted_registrations  },
00218    {"rejected_regs",                 0, &rejected_registrations  },
00219    {0, 0, 0}
00220 };
00221 
00222 
00223 /*! \brief
00224  * Module exports structure
00225  */
00226 struct module_exports exports = {
00227    "registrar", 
00228    DEFAULT_DLFLAGS, /* dlopen flags */
00229    cmds,        /* Exported functions */
00230    params,      /* Exported parameters */
00231    mod_stats,   /* exported statistics */
00232    0,           /* exported MI functions */
00233    mod_pvs,     /* exported pseudo-variables */
00234    0,           /* extra processes */
00235    mod_init,    /* module initialization function */
00236    0,
00237    mod_destroy, /* destroy function */
00238    child_init,  /* Per-child init function */
00239 };
00240 
00241 
00242 /*! \brief
00243  * Initialize parent
00244  */
00245 static int mod_init(void)
00246 {
00247    pv_spec_t avp_spec;
00248    str s;
00249    bind_usrloc_t bind_usrloc;
00250 
00251    /* load the SL API */
00252    if (load_sl_api(&slb)!=0) {
00253       LM_ERR("can't load SL API\n");
00254       return -1;
00255    }
00256 
00257    realm_prefix.s = realm_pref;
00258    realm_prefix.len = strlen(realm_pref);
00259 
00260    rcv_param.len = strlen(rcv_param.s);
00261 
00262    if (rcv_avp_param && *rcv_avp_param) {
00263       s.s = rcv_avp_param; s.len = strlen(s.s);
00264       if (pv_parse_spec(&s, &avp_spec)==0
00265             || avp_spec.type!=PVT_AVP) {
00266          LM_ERR("malformed or non AVP %s AVP definition\n", rcv_avp_param);
00267          return -1;
00268       }
00269 
00270       if(pv_get_avp_name(0, &avp_spec.pvp, &rcv_avp_name, &rcv_avp_type)!=0)
00271       {
00272          LM_ERR("[%s]- invalid AVP definition\n", rcv_avp_param);
00273          return -1;
00274       }
00275    } else {
00276       rcv_avp_name.n = 0;
00277       rcv_avp_type = 0;
00278    }
00279    if (aor_avp_param && *aor_avp_param) {
00280       s.s = aor_avp_param; s.len = strlen(s.s);
00281       if (pv_parse_spec(&s, &avp_spec)==0
00282             || avp_spec.type!=PVT_AVP) {
00283          LM_ERR("malformed or non AVP %s AVP definition\n", aor_avp_param);
00284          return -1;
00285       }
00286 
00287       if(pv_get_avp_name(0, &avp_spec.pvp, &aor_avp_name, &aor_avp_type)!=0)
00288       {
00289          LM_ERR("[%s]- invalid AVP definition\n", aor_avp_param);
00290          return -1;
00291       }
00292    } else {
00293       aor_avp_name.n = 0;
00294       aor_avp_type = 0;
00295    }
00296 
00297    if (reg_callid_avp_param && *reg_callid_avp_param) {
00298       s.s = reg_callid_avp_param; s.len = strlen(s.s);
00299       if (pv_parse_spec(&s, &avp_spec)==0
00300          || avp_spec.type!=PVT_AVP) {
00301          LM_ERR("malformed or non AVP %s AVP definition\n", reg_callid_avp_param);
00302          return -1;
00303       }
00304 
00305       if(pv_get_avp_name(0, &avp_spec.pvp, &reg_callid_avp_name, &reg_callid_avp_type)!=0)
00306       {
00307          LM_ERR("[%s]- invalid AVP definition\n", reg_callid_avp_param);
00308          return -1;
00309       }
00310    } else {
00311       reg_callid_avp_name.n = 0;
00312       reg_callid_avp_type = 0;
00313    }
00314 
00315    bind_usrloc = (bind_usrloc_t)find_export("ul_bind_usrloc", 1, 0);
00316    if (!bind_usrloc) {
00317       LM_ERR("can't bind usrloc\n");
00318       return -1;
00319    }
00320 
00321    /* Normalize default_q parameter */
00322    if (default_q != Q_UNSPECIFIED) {
00323       if (default_q > MAX_Q) {
00324          LM_DBG("default_q = %d, lowering to MAX_Q: %d\n", default_q, MAX_Q);
00325          default_q = MAX_Q;
00326       } else if (default_q < MIN_Q) {
00327          LM_DBG("default_q = %d, raising to MIN_Q: %d\n", default_q, MIN_Q);
00328          default_q = MIN_Q;
00329       }
00330    }
00331    
00332 
00333    if (bind_usrloc(&ul) < 0) {
00334       return -1;
00335    }
00336 
00337    /*
00338     * Import use_domain parameter from usrloc
00339     */
00340    reg_use_domain = ul.use_domain;
00341 
00342    if (sock_hdr_name.s) {
00343       sock_hdr_name.len = strlen(sock_hdr_name.s);
00344       if (sock_hdr_name.len==0 || sock_flag==-1) {
00345          LM_WARN("empty sock_hdr_name or sock_flag no set -> reseting\n");
00346          pkg_free(sock_hdr_name.s);
00347          sock_hdr_name.s = 0;
00348          sock_hdr_name.len = 0;
00349          sock_flag = -1;
00350       }
00351    } else if (sock_flag!=-1) {
00352       LM_WARN("sock_flag defined but no sock_hdr_name -> reseting flag\n");
00353       sock_flag = -1;
00354    }
00355 
00356    /* fix the flags */
00357    sock_flag = (sock_flag!=-1)?(1<<sock_flag):0;
00358    tcp_persistent_flag = (tcp_persistent_flag!=-1)?(1<<tcp_persistent_flag):0;
00359 
00360    return 0;
00361 }
00362 
00363 
00364 static int child_init(int rank)
00365 {
00366    if (rank==1) {
00367       /* init stats */
00368       update_stat( max_expires_stat, max_expires );
00369       update_stat( max_contacts_stat, max_contacts );
00370       update_stat( default_expire_stat, default_expires );
00371    }
00372 
00373    return 0;
00374 }
00375 
00376 
00377 /*! \brief
00378  * Convert char* parameter to udomain_t* pointer
00379  */
00380 static int domain_fixup(void** param, int param_no)
00381 {
00382    udomain_t* d;
00383 
00384    if (param_no == 1) {
00385       if (ul.register_udomain((char*)*param, &d) < 0) {
00386          LM_ERR("failed to register domain\n");
00387          return E_UNSPEC;
00388       }
00389 
00390       *param = (void*)d;
00391    }
00392    return 0;
00393 }
00394 
00395 /*! \brief
00396  * Convert char* parameter to udomain_t* pointer
00397  * Convert char* parameter to pv_elem_t* pointer
00398  */
00399 static int unreg_fixup(void** param, int param_no)
00400 {
00401    if (param_no == 1) {
00402       return domain_fixup(param, 1);
00403    } else if (param_no == 2) {
00404       return fixup_spve_null(param, 1);
00405    }
00406    return 0;
00407 }
00408 
00409 
00410 
00411 /*! \brief
00412  * Fixup for "save" function - both domain and flags
00413  */
00414 static int save_fixup(void** param, int param_no)
00415 {
00416    unsigned int flags;
00417    str s;
00418 
00419    if (param_no == 1) {
00420       return domain_fixup(param,param_no);
00421    } else {
00422       s.s = (char*)*param;
00423       s.len = strlen(s.s);
00424       flags = 0;
00425       if ( (strno2int(&s, &flags )<0) || (flags>REG_SAVE_ALL_FL) ) {
00426          LM_ERR("bad flags <%s>\n", (char *)(*param));
00427          return E_CFG;
00428       }
00429       if (ul.db_mode==DB_ONLY && flags&REG_SAVE_MEM_FL) {
00430          LM_ERR("MEM flag set while using the DB_ONLY mode in USRLOC\n");
00431          return E_CFG;
00432       }
00433       pkg_free(*param);
00434       *param = (void*)(unsigned long int)flags;
00435       return 0;
00436    }
00437 }
00438 
00439 /*! \brief
00440  * Convert char* parameter to udomain_t* pointer
00441  * Convert char* parameter to pv_elem_t* pointer
00442  * Convert char* parameter to str* pointer
00443  */
00444 static int fetchc_fixup(void** param, int param_no)
00445 {
00446    if (param_no == 1) {
00447       return domain_fixup(param, 1);
00448    } else if (param_no == 2) {
00449       return fixup_spve_null(param, 1);
00450    } else if (param_no == 3) {
00451       return fixup_str_null(param, 1);
00452    }
00453    return 0;
00454 }
00455 
00456 
00457 static void mod_destroy(void)
00458 {
00459    free_contact_buf();
00460 }
00461 
00462 
00463 #include "../../data_lump.h"
00464 #include "../../ip_addr.h"
00465 #include "../../ut.h"
00466 
00467 static int add_sock_hdr(struct sip_msg* msg, char *name, char *foo)
00468 {
00469    struct socket_info* si;
00470    struct lump* anchor;
00471    str *hdr_name;
00472    str hdr;
00473    char *p;
00474 
00475    hdr_name = (str*)name;
00476    si = msg->rcv.bind_address;
00477 
00478    if (parse_headers( msg, HDR_EOH_F, 0) == -1) {
00479       LM_ERR("failed to parse message\n");
00480       goto error;
00481    }
00482 
00483    anchor = anchor_lump( msg, msg->unparsed-msg->buf, 0, 0);
00484    if (anchor==0) {
00485       LM_ERR("can't get anchor\n");
00486       goto error;
00487    }
00488 
00489    hdr.len = hdr_name->len + 2 + si->sock_str.len + CRLF_LEN;
00490    if ( (hdr.s=(char*)pkg_malloc(hdr.len))==0 ) {
00491       LM_ERR("no more pkg mem\n");
00492       goto error;
00493    }
00494 
00495    p = hdr.s;
00496    memcpy( p, hdr_name->s, hdr_name->len);
00497    p += hdr_name->len;
00498    *(p++) = ':';
00499    *(p++) = ' ';
00500 
00501    memcpy( p, si->sock_str.s, si->sock_str.len);
00502    p += si->sock_str.len;
00503 
00504    memcpy( p, CRLF, CRLF_LEN);
00505    p += CRLF_LEN;
00506 
00507    if ( p-hdr.s!=hdr.len ) {
00508       LM_CRIT("buffer overflow (%d!=%d)\n", (int)(long)(p-hdr.s),hdr.len);
00509       goto error1;
00510    }
00511 
00512    if (insert_new_lump_before( anchor, hdr.s, hdr.len, 0) == 0) {
00513       LM_ERR("can't insert lump\n");
00514       goto error1;
00515    }
00516 
00517    return 1;
00518 error1:
00519    pkg_free(hdr.s);
00520 error:
00521    return -1;
00522 }
00523 

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