sl_funcs.c

Go to the documentation of this file.
00001 /*
00002  * $Id: sl_funcs.c 5347 2008-12-13 18:56:49Z miconda $
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-02-11  modified sl_send_reply to use the transport independent
00025  *              msg_send  (andrei)
00026  * 2003-02-18  replaced TOTAG_LEN w/ TOTAG_VALUE_LEN (it was defined twice
00027  *              w/ different values!)  (andrei)
00028  * 2003-03-06  aligned to request2response use of tag bookmarks (jiri)
00029  * 2003-04-04  modified sl_send_reply to use src_port if rport is present
00030  *              in the topmost via (andrei)
00031  * 2003-09-11: updated to new build_lump_rpl() interface (bogdan)
00032  * 2003-09-11: sl_tag converted to str to fit to the new
00033  *               build_res_buf_from_sip_req() interface (bogdan)
00034  * 2003-11-11: build_lump_rpl() removed, add_lump_rpl() has flags (bogdan)
00035  * 2004-10-10: use of mhomed disabled for replies (jiri)
00036  * 2006-03-29: callbacks for sending replies added (bogdan)
00037  * 2006-11-28: Moved numerical code tracking out of sl_send_reply() and into
00038  *             update_sl_reply_stat(). Also added more detail stat collection.
00039  *             (Jeffrey Magder - SOMA Networks)
00040  */
00041 
00042 /*!
00043  * \file
00044  * \brief SL :: functions
00045  * \ingroup sl
00046  * - Module: \ref sl
00047  */
00048 
00049 #include "../../globals.h"
00050 #include "../../forward.h"
00051 #include "../../dprint.h"
00052 #include "../../md5utils.h"
00053 #include "../../msg_translator.h"
00054 #include "../../udp_server.h"
00055 #include "../../timer.h"
00056 #include "../../mem/mem.h"
00057 #include "../../mem/shm_mem.h"
00058 #include "../../crc.h"
00059 #include "../../dset.h"
00060 #include "../../data_lump_rpl.h"
00061 #include "../../action.h"
00062 #include "../../config.h"
00063 #include "../../tags.h"
00064 #include "sl.h"
00065 #include "sl_funcs.h"
00066 #include "sl_cb.h"
00067 #include "../../usr_avp.h"
00068 #include <string.h>
00069 /* to-tag including pre-calculated and fixed part */
00070 static char           sl_tag_buf[TOTAG_VALUE_LEN];
00071 static str            sl_tag = {sl_tag_buf,TOTAG_VALUE_LEN};
00072 /* from here, the variable prefix begins */
00073 static char           *tag_suffix;
00074 /* if we for this time did not send any stateless reply,
00075    we do not filter */
00076 static unsigned int  *sl_timeout = 0;
00077 
00078 
00079 /*! SL startup helper */
00080 int sl_startup(void)
00081 {
00082 
00083    init_tags( sl_tag.s, &tag_suffix,
00084          "Kamailio-stateless",
00085          SL_TOTAG_SEPARATOR );
00086 
00087    /*timeout*/
00088    sl_timeout = (unsigned int*)shm_malloc(sizeof(unsigned int));
00089    if (!sl_timeout)
00090    {
00091       LM_ERR("no more shm memory!\n");
00092       return -1;
00093    }
00094    *(sl_timeout)=get_ticks();
00095 
00096    return 0;
00097 }
00098 
00099 
00100 /*! SL shutdown helper */
00101 int sl_shutdown(void)
00102 {
00103    if (sl_timeout)
00104       shm_free(sl_timeout);
00105    return 1;
00106 }
00107 
00108 
00109 /*! Take care of the statistics associated with numerical codes and replies */
00110 static inline void update_sl_reply_stat(int code) 
00111 {
00112    stat_var *numerical_stat;
00113 
00114    /* If stats aren't enabled, just skip over this. */
00115    if (!sl_enable_stats) 
00116       return;
00117 
00118    /* Kamailio already kept track of the total number of 1xx, 2xx, replies.
00119    * There may be setups that still expect these variables to exist, so we
00120    * don't touch them */
00121    if (code < 200 ) {
00122       update_stat( tx_1xx_rpls , 1);
00123    } else if (code<300) {
00124       update_stat( tx_2xx_rpls , 1);
00125    } else if (code<400) {
00126       update_stat( tx_3xx_rpls , 1);
00127    } else if (code<500) {
00128       update_stat( tx_4xx_rpls , 1);
00129    } else if (code<600) {
00130       update_stat( tx_5xx_rpls , 1);
00131    } else {
00132       update_stat( tx_6xx_rpls , 1);
00133    }
00134 
00135    update_stat( sent_rpls , 1);
00136 
00137    numerical_stat = get_stat_var_from_num_code(code, 1);
00138 
00139    if (numerical_stat != NULL)
00140       update_stat(numerical_stat, 1);
00141 }
00142 
00143 int sl_get_reply_totag(struct sip_msg *msg, str *totag)
00144 {
00145    if(msg==NULL || totag==NULL)
00146       return -1;
00147    calc_crc_suffix(msg, tag_suffix);
00148    *totag = sl_tag;
00149    return 1;
00150 }
00151 
00152 /*! sl_send_reply helper function */
00153 int sl_send_reply_helper(struct sip_msg *msg ,int code, str *text, str *tag)
00154 {
00155    str buf;
00156    union sockaddr_union to;
00157    char *dset;
00158    int dset_len;
00159    struct bookmark dummy_bm;
00160    int backup_mhomed;
00161    int ret;
00162 
00163    if ( msg->first_line.u.request.method_value==METHOD_ACK)
00164       goto error;
00165 
00166    if (reply_to_via) {
00167       if (update_sock_struct_from_via(  &(to), msg, msg->via1 )==-1) {
00168          LM_ERR("cannot lookup reply dst: %s\n", msg->via1->host.s );
00169          goto error;
00170       }
00171    } else update_sock_struct_from_ip( &to, msg );
00172 
00173    /* if that is a redirection message, dump current message set to it */
00174    if (code>=300 && code<400) {
00175       dset=print_dset(msg, &dset_len);
00176       if (dset) {
00177          add_lump_rpl(msg, dset, dset_len, LUMP_RPL_HDR);
00178       }
00179    }
00180 
00181    /* add a to-tag if there is a To header field without it */
00182    if ( code>=180 &&
00183       (msg->to || (parse_headers(msg,HDR_TO_F, 0)!=-1 && msg->to))
00184       && (get_to(msg)->tag_value.s==0 || get_to(msg)->tag_value.len==0) ) 
00185    {
00186       if(tag!=NULL && tag->s!=NULL) {
00187          buf.s = build_res_buf_from_sip_req( code, text, tag,
00188                   msg, (unsigned int*)&buf.len, &dummy_bm);
00189       } else {
00190          calc_crc_suffix( msg, tag_suffix );
00191          buf.s = build_res_buf_from_sip_req( code, text, &sl_tag, msg,
00192             (unsigned int*)&buf.len, &dummy_bm);
00193       }
00194    } else {
00195       buf.s = build_res_buf_from_sip_req( code, text, 0, msg,
00196          (unsigned int*)&buf.len, &dummy_bm);
00197    }
00198    if (!buf.s) {
00199       LM_ERR("response building failed\n");
00200       goto error;
00201    }
00202 
00203    run_sl_callbacks( SLCB_REPLY_OUT, msg, &buf, code, text, &to );
00204 
00205    /* supress multhoming support when sending a reply back -- that makes sure
00206       that replies will come from where requests came in; good for NATs
00207       (there is no known use for mhomed for locally generated replies;
00208        note: forwarded cross-interface replies do benefit of mhomed!
00209    */
00210    backup_mhomed=mhomed;
00211    mhomed=0;
00212    /* use for sending the received interface -bogdan*/
00213    ret = msg_send( msg->rcv.bind_address, msg->rcv.proto, &to,
00214          msg->rcv.proto_reserved1, buf.s, buf.len);
00215    mhomed=backup_mhomed;
00216    pkg_free(buf.s);
00217 
00218    if (ret<0)
00219       goto error;
00220 
00221    *(sl_timeout) = get_ticks() + SL_RPL_WAIT_TIME;
00222 
00223    update_sl_reply_stat(code);
00224 
00225    return 1;
00226 
00227 error:
00228    return -1;
00229 }
00230 
00231 
00232 /*! small wrapper around sl_send_reply_helper */
00233 int sl_send_reply(struct sip_msg *msg ,int code, str *text)
00234 {
00235    return sl_send_reply_helper(msg, code, text, 0);
00236 }
00237 
00238 
00239 /*! small wrapper around sl_send_reply_helper */
00240 int sl_send_reply_dlg(struct sip_msg *msg ,int code, str *text, str *tag)
00241 {
00242    return sl_send_reply_helper(msg, code, text, tag);
00243 }
00244 
00245 
00246 /*! Reply an SIP error */
00247 int sl_reply_error(struct sip_msg *msg )
00248 {
00249    char err_buf[MAX_REASON_LEN];
00250    int sip_error;
00251    str text;
00252    int ret;
00253 
00254    ret = err2reason_phrase( prev_ser_error, &sip_error, 
00255       err_buf, sizeof(err_buf), "SL");
00256    if (ret<=0) {
00257       LM_ERR("err2reason failed\n");
00258       return -1;
00259    }
00260    text.len = ret;
00261    text.s = err_buf;
00262    LM_DBG("error text is %.*s\n",text.len,text.s);
00263 
00264    ret = sl_send_reply_helper( msg, sip_error, &text, 0);
00265    if (ret==-1)
00266       return -1;
00267    if_update_stat( sl_enable_stats, sent_err_rpls , 1);
00268    return ret;
00269 }
00270 
00271 
00272 
00273 /*!
00274  * Filter ACKs
00275  * \return 0 for ACKs to a local reply, -1 on error, 1 is not an ACK or a non-local ACK
00276  */
00277 int sl_filter_ACK(struct sip_msg *msg, void *bar )
00278 {
00279    str *tag_str;
00280 
00281    if (msg->first_line.u.request.method_value!=METHOD_ACK)
00282       goto pass_it;
00283 
00284    /*check the timeout value*/
00285    if ( *(sl_timeout)<= get_ticks() )
00286    {
00287       LM_DBG("to late to be a local ACK!\n");
00288       goto pass_it;
00289    }
00290 
00291    /*force to parse to header -> we need it for tag param*/
00292    if (parse_headers( msg, HDR_TO_F, 0 )==-1)
00293    {
00294       LM_ERR("unable to parse To header\n");
00295       return -1;
00296    }
00297 
00298    if (msg->to) {
00299       tag_str = &(get_to(msg)->tag_value);
00300       if ( tag_str->len==TOTAG_VALUE_LEN )
00301       {
00302          /* calculate the variable part of to-tag */  
00303          calc_crc_suffix(msg, tag_suffix);
00304          /* test whether to-tag equal now */
00305          if (memcmp(tag_str->s,sl_tag.s,sl_tag.len)==0) {
00306             LM_DBG("local ACK found -> dropping it!\n");
00307             if_update_stat( sl_enable_stats, rcv_acks, 1);
00308             run_sl_callbacks( SLCB_ACK_IN, msg, 0, 0, 0, 0 );
00309             return 0;
00310          }
00311       }
00312    }
00313 
00314 pass_it:
00315    return 1;
00316 }

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