sl.c

Go to the documentation of this file.
00001 /*
00002  * $Id: sl.c 5605 2009-02-13 14:22:37Z 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-11  updated to the new module exports interface (andrei)
00025  *  2003-03-16  flags export parameter added (janakj)
00026  *  2003-03-19  all mallocs/frees replaced w/ pkg_malloc/pkg_free
00027  *  2005-03-01  force for stateless replies the incoming interface of
00028  *              the request (bogdan)
00029  *  2006-03-29  callbacks for sending replies added (bogdan)
00030  */
00031 
00032 /*!
00033  * \file
00034  * \brief SL :: module definitions
00035  * \ingroup sl
00036  * - Module: \ref sl
00037  */
00038 
00039 /*!
00040  * \defgroup sl SL :: The Kamailio SL Module
00041  *
00042  * The SL module allows Kamailio to act as a stateless UA server and
00043  * generate replies to SIP requests without keeping state. That is beneficial
00044  * in many scenarios, in which you wish not to burden server's memory and scale
00045  * well.
00046  */
00047 
00048 
00049 #include <stdio.h>
00050 #include <string.h>
00051 #include <stdlib.h>
00052 
00053 #include "../../sr_module.h"
00054 #include "../../dprint.h"
00055 #include "../../error.h"
00056 #include "../../ut.h"
00057 #include "../../script_cb.h"
00058 #include "../../mem/mem.h"
00059 #include "../../pvar.h"
00060 
00061 #include "../tm/tm_load.h"
00062 
00063 #include "sl_funcs.h"
00064 #include "sl_api.h"
00065 #include "sl_cb.h"
00066 
00067 MODULE_VERSION
00068 
00069 
00070 static int w_sl_send_reply(struct sip_msg* msg, char* str1, char* str2);
00071 static int w_send_reply(struct sip_msg* msg, char* str1, char* str2);
00072 static int w_sl_reply_error(struct sip_msg* msg, char* str1, char* str2);
00073 static int fixup_sl_send_reply(void** param, int param_no);
00074 static int mod_init(void);
00075 static void mod_destroy(void);
00076 /* module parameter */
00077 int sl_enable_stats = 1;
00078 int sl_bind_tm = 1;
00079 
00080 /* statistic variables */
00081 stat_var *tx_1xx_rpls;
00082 stat_var *tx_2xx_rpls;
00083 stat_var *tx_3xx_rpls;
00084 stat_var *tx_4xx_rpls;
00085 stat_var *tx_5xx_rpls;
00086 stat_var *tx_6xx_rpls;
00087 stat_var *sent_rpls;
00088 stat_var *sent_err_rpls;
00089 stat_var *rcv_acks;
00090 
00091 static struct tm_binds tmb;
00092 
00093 static cmd_export_t cmds[]={
00094    {"sl_send_reply",   (cmd_function)w_sl_send_reply,
00095       2,  fixup_sl_send_reply, 0,
00096       REQUEST_ROUTE | ERROR_ROUTE },
00097    {"send_reply",   (cmd_function)w_send_reply,
00098       2,  fixup_sl_send_reply, 0,
00099       REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE|ERROR_ROUTE },
00100    {"sl_reply_error",  (cmd_function)w_sl_reply_error,
00101       0,  0, 0, REQUEST_ROUTE},
00102    {"register_slcb",  (cmd_function)register_slcb,
00103       0,  0, 0,
00104       0},
00105    {"load_sl",        (cmd_function)load_sl,
00106       0,  0, 0,
00107       0},
00108    {0,0,0,0,0,0}
00109 };
00110 
00111 
00112 static param_export_t mod_params[]={
00113    { "enable_stats",  INT_PARAM, &sl_enable_stats },
00114    { "bind_tm",       INT_PARAM, &sl_bind_tm },
00115    { 0,0,0 }
00116 };
00117 
00118 
00119 stat_export_t mod_stats[] = {
00120    {"1xx_replies" ,       0,  &tx_1xx_rpls    },
00121    {"2xx_replies" ,       0,  &tx_2xx_rpls    },
00122    {"3xx_replies" ,       0,  &tx_3xx_rpls    },
00123    {"4xx_replies" ,       0,  &tx_4xx_rpls    },
00124    {"5xx_replies" ,       0,  &tx_5xx_rpls    },
00125    {"6xx_replies" ,       0,  &tx_6xx_rpls    },
00126    {"sent_replies" ,      0,  &sent_rpls      },
00127    {"sent_err_replies" ,  0,  &sent_err_rpls  },
00128    {"received_ACKs" ,     0,  &rcv_acks       },
00129    {0,0,0}
00130 };
00131 
00132 
00133 struct module_exports exports= {
00134    "sl",         /* module's name */
00135    DEFAULT_DLFLAGS, /* dlopen flags */
00136    cmds,         /* exported functions */
00137    mod_params,   /* param exports */
00138    mod_stats,    /* exported statistics */
00139    0,            /* exported MI functions */
00140    0,            /* exported pseudo-variables */
00141    0,            /* extra processes */
00142    mod_init,     /* module initialization function */
00143    0,            /* reply processing function */
00144    mod_destroy,
00145    0             /* per-child init function */
00146 };
00147 
00148 
00149 static int mod_init(void)
00150 {
00151    load_tm_f load_tm;
00152 
00153    /* if statistics are disabled, prevent their registration to core */
00154    if (sl_enable_stats==0)
00155       exports.stats = 0;
00156 
00157    /* filter all ACKs before script */
00158    if (register_script_cb(sl_filter_ACK, PRE_SCRIPT_CB|REQ_TYPE_CB, 0 )!=0) {
00159       LM_ERR("register_script_cb failed\n");
00160       return -1;
00161    }
00162 
00163    /* init internal SL stuff */
00164    if (sl_startup()!=0) {
00165       LM_ERR("sl_startup failed\n");
00166       return -1;
00167    }
00168 
00169    if(sl_bind_tm!=0)
00170    {
00171       if ( (load_tm=(load_tm_f)find_export("load_tm", 0, 0)))
00172       {
00173          load_tm( &tmb );
00174       } else {
00175          LM_INFO("could not bind tm module - only stateless mode available\n");
00176          sl_bind_tm=0;
00177       }
00178    }
00179 
00180    return 0;
00181 }
00182 
00183 
00184 static void mod_destroy(void)
00185 {
00186    sl_shutdown();
00187    destroy_slcb_lists();
00188 
00189 }
00190 
00191 /*!
00192  * \brief Fixup function for sl_send_reply
00193  */
00194 static int fixup_sl_send_reply(void** param, int param_no)
00195 {
00196    pv_elem_t *model=NULL;
00197    str s;
00198 
00199    /* convert to str */
00200    s.s = (char*)*param;
00201    s.len = strlen(s.s);
00202 
00203    model=NULL;
00204    if (param_no==1 || param_no==2)
00205    {
00206       if(s.len==0)
00207       {
00208          LM_ERR("no param %d!\n", param_no);
00209          return E_UNSPEC;
00210       }
00211 
00212       if(pv_parse_format(&s ,&model) || model==NULL)
00213       {
00214          LM_ERR("wrong format [%s] for param no %d!\n", s.s, param_no);
00215          return E_UNSPEC;
00216       }
00217       if(model->spec.getf==NULL)
00218       {
00219          if(param_no==1)
00220          {
00221             if(str2int(&s,
00222                (unsigned int*)&model->spec.pvp.pvn.u.isname.name.n)!=0
00223                   || model->spec.pvp.pvn.u.isname.name.n<100
00224                   || model->spec.pvp.pvn.u.isname.name.n>699)
00225             {
00226                LM_ERR("wrong value [%s] for param no %d!\n",
00227                   s.s, param_no);
00228                LM_ERR("allowed values: 1xx - 6xx only!\n");
00229                return E_UNSPEC;
00230             }
00231          }
00232       }
00233       *param = (void*)model;
00234    }
00235 
00236    return 0;
00237 }
00238 
00239 
00240 /*!
00241  * \brief Small wrapper around sl_send_reply
00242  */
00243 static int w_sl_reply_error( struct sip_msg* msg, char* str1, char* str2)
00244 {
00245    return sl_reply_error( msg );
00246 }
00247 
00248 
00249 /*!
00250  * \brief Wrapper around sl_send_reply
00251  *
00252  * Wrapper around sl_send_reply, evaluate pseudo-variables.
00253  */
00254 static int w_sl_send_reply(struct sip_msg* msg, char* str1, char* str2)
00255 {
00256    str code_s;
00257    unsigned int code_i;
00258 
00259    if(((pv_elem_p)str1)->spec.getf!=NULL)
00260    {
00261       if(pv_printf_s(msg, (pv_elem_p)str1, &code_s)!=0)
00262          return -1;
00263       if(str2int(&code_s, &code_i)!=0 || code_i<100 || code_i>699)
00264          return -1;
00265    } else {
00266       code_i = ((pv_elem_p)str1)->spec.pvp.pvn.u.isname.name.n;
00267    }
00268    
00269    if(((pv_elem_p)str2)->spec.getf!=NULL)
00270    {
00271       if(pv_printf_s(msg, (pv_elem_p)str2, &code_s)!=0 || code_s.len <=0)
00272          return -1;
00273    } else {
00274       code_s = ((pv_elem_p)str2)->text;
00275    }
00276 
00277    return sl_send_reply(msg, code_i, &code_s);
00278 }
00279 
00280 int send_reply(struct sip_msg *msg, int code, str *text)
00281 {
00282    struct cell * t;
00283    if(sl_bind_tm!=0)
00284    {
00285       t = tmb.t_gett();
00286       if(t!= NULL && t!=T_UNDEFINED)
00287       {
00288          if(tmb.t_reply(msg, code, text)< 0)
00289          {
00290             LM_ERR("failed to reply stateful (tm)\n");
00291             return -1;
00292          }
00293          LM_DBG("reply in stateful mode (tm)\n");
00294          return 1;
00295       }
00296    }
00297 
00298    LM_DBG("reply in stateless mode (sl)\n");
00299    return sl_send_reply(msg, code, text);
00300 }
00301 
00302 static int w_send_reply(struct sip_msg* msg, char* str1, char* str2)
00303 {
00304    str code_s;
00305    unsigned int code_i;
00306 
00307    if(((pv_elem_p)str1)->spec.getf!=NULL)
00308    {
00309       if(pv_printf_s(msg, (pv_elem_p)str1, &code_s)!=0)
00310          return -1;
00311       if(str2int(&code_s, &code_i)!=0 || code_i<100 || code_i>699)
00312          return -1;
00313    } else {
00314       code_i = ((pv_elem_p)str1)->spec.pvp.pvn.u.isname.name.n;
00315    }
00316    
00317    if(((pv_elem_p)str2)->spec.getf!=NULL)
00318    {
00319       if(pv_printf_s(msg, (pv_elem_p)str2, &code_s)!=0 || code_s.len <=0)
00320          return -1;
00321    } else {
00322       code_s = ((pv_elem_p)str2)->text;
00323    }
00324    return send_reply(msg, code_i, &code_s);
00325 }
00326 
00327 
00328 int get_reply_totag(struct sip_msg *msg, str *totag)
00329 {
00330    struct cell * t;
00331    if(msg==NULL || totag==NULL)
00332       return -1;
00333    if(sl_bind_tm!=0)
00334    {
00335       t = tmb.t_gett();
00336       if(t!= NULL && t!=T_UNDEFINED)
00337       {
00338          if(tmb.t_get_reply_totag(msg, totag)< 0)
00339          {
00340             LM_ERR("failed to get totag (tm)\n");
00341             return -1;
00342          }
00343          LM_DBG("totag stateful mode (tm)\n");
00344          return 1;
00345       }
00346    }
00347 
00348    LM_DBG("totag stateless mode (sl)\n");
00349    return sl_get_reply_totag(msg, totag);
00350 }
00351 
00352 /*!
00353  * \brief Helper function for loading the SL API
00354  * \param slb sl_bind structure
00355  * \return -1 on parameter errors, 1 otherwise
00356  */
00357 int load_sl( struct sl_binds *slb)
00358 {
00359    if(slb==NULL)
00360       return -1;
00361 
00362    slb->reply      = sl_send_reply;
00363    slb->reply_dlg  = sl_send_reply_dlg;
00364    slb->sl_get_reply_totag = sl_get_reply_totag;
00365    slb->send_reply = send_reply;
00366    slb->get_reply_totag = get_reply_totag;
00367 
00368 
00369    return 1;
00370 }

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