ring.c

Go to the documentation of this file.
00001 /*
00002  * $Id: ring.c 5215 2008-11-18 11:38:25Z henningw $
00003  *
00004  * Copyright (C) 2008-2009 1&1 Internet AG
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 
00023 /**
00024  * \file
00025  * \brief Only allow one 183 message per call-id
00026  * \ingroup utils
00027  * - Module; \ref utils
00028  */
00029 
00030 /*!
00031  * \defgroup utils UTILS :: Ringing functionality
00032  * In a parallel forking scenario you get several 183s with SDP. You don't want
00033  * that your customers hear more than one ringtone or answer machine in parallel
00034  * on the phone. So its necessary to drop the 183 in this cases and send a 180 instead.
00035  */
00036 
00037 
00038 #include <stdio.h>
00039 #include <string.h>
00040 #include <stdlib.h>
00041 #include <assert.h>
00042 
00043 #include "../../parser/msg_parser.h"
00044 #include "../../dprint.h"
00045 #include "../../error.h"
00046 #include "../../ut.h"
00047 #include "../../mem/mem.h"
00048 #include "../../mem/shm_mem.h"
00049 #include "../../timer.h"
00050 #include "../../locking.h"
00051 #include "../../md5.h"
00052 
00053 #include "ring.h"
00054 
00055 
00056 /*! list of calls for ringing functionality */
00057 struct ring_record_t {
00058    struct ring_record_t *next;
00059    unsigned int time; /*!< timeout value */
00060    char callid[MAXCALLIDLEN+1]; /*!< callid of this call */
00061 };
00062 
00063 /*! hashtable for ringing records */
00064 struct hashtable_entry_t {
00065    struct ring_record_t *head;
00066    struct ring_record_t *tail;
00067 };
00068 
00069 typedef struct hashtable_entry_t hashtable_t[HASHTABLESIZE];
00070 
00071 /*! global hashtable */
00072 static hashtable_t *hashtable = NULL;
00073 
00074 static void insert(str callid);
00075 
00076 static int contains(str callid);
00077 
00078 
00079 /*!
00080  * \brief  Inserts callid of message into hashtable
00081  *
00082  * Inserts callid of message into hashtable. Any 183 messages with
00083  * this callid that occur in the next ring_timeout seconds, will be
00084  * converted to 180.
00085  * \param msg SIP message
00086  * \param unused1 unused
00087  * \param unused2 unused
00088  * \return 1 on success, -1 otherwise
00089  */
00090 int ring_insert_callid(struct sip_msg *msg, char *unused1, char *unused2)
00091 {
00092    /* could fail, eg if already parsed don't care about result */
00093    parse_headers(msg, HDR_CALLID_F, 0);
00094 
00095    if (msg->callid) {
00096       lock_get(ring_lock);
00097       if (!contains(msg->callid->body)) insert(msg->callid->body);
00098       lock_release(ring_lock);
00099    } else {
00100       LM_ERR("no callid\n");
00101       return -1;
00102    }
00103 
00104    return 1;
00105 }
00106 
00107 
00108 /*!
00109  * \brief Initialize the ring hashtable in shared memory
00110  */
00111 void ring_init_hashtable(void)
00112 {
00113    int i;
00114 
00115    hashtable = shm_malloc(sizeof(hashtable_t));
00116    assert(hashtable);
00117    for (i=0; i<HASHTABLESIZE; i++) {
00118       (*hashtable)[i].head = NULL;
00119       (*hashtable)[i].tail = NULL;
00120    }
00121 }
00122 
00123 
00124 /*!
00125  * \brief Destroy the ring hashtable
00126  */
00127 void ring_destroy_hashtable(void)
00128 {
00129    int i;
00130 
00131    if (hashtable) {
00132       for (i=0; i<HASHTABLESIZE; i++) {
00133          while ((*hashtable)[i].head) {
00134             struct ring_record_t* rr = (*hashtable)[i].head;
00135             (*hashtable)[i].head = rr->next;
00136             shm_free(rr);
00137          }
00138          (*hashtable)[i].tail = NULL;
00139       }
00140 
00141       shm_free(hashtable);
00142    }
00143 }
00144 
00145 
00146 /*!
00147  * \brief Hash helper function
00148  * \param buf hashed buffer
00149  * \param len length of buffer
00150  * \return hash value, can be 0
00151  */
00152 static unsigned int hash(char *buf, int len)
00153 {
00154    int i;
00155    unsigned int retval = 0;
00156    MD5_CTX md5context;
00157    char digest[16];
00158    
00159    MD5Init(&md5context);
00160    MD5Update(&md5context, buf, len);
00161    MD5Final(digest, &md5context);
00162 
00163    for (i=0; i<16; i++) {
00164       retval ^= ((unsigned int)((unsigned char)buf[i])) << i;
00165    }
00166 
00167    return retval;
00168 }
00169 
00170 
00171 /*!
00172  * \brief Expire entries on the hashtable
00173  * \param index array index that should expired
00174  */
00175 static void remove_timeout(unsigned int index)
00176 {
00177    while ((*hashtable)[index].head && ((*hashtable)[index].head)->time + ring_timeout < get_ticks()) {
00178       struct ring_record_t* rr = (*hashtable)[index].head;
00179       (*hashtable)[index].head = rr->next;
00180       if ((*hashtable)[index].head == NULL) (*hashtable)[index].tail = NULL;
00181       LM_DBG("deleting ticks=%d %s\n", get_ticks(), rr->callid);
00182       shm_free(rr);
00183    }
00184 }
00185 
00186 
00187 /*!
00188  * \brief Insert a new entry on the hashtable
00189  * \param callid Call-ID string
00190  */
00191 static void insert(str callid)
00192 {
00193    unsigned int index = hash(callid.s, callid.len) & HASHTABLEMASK;
00194 
00195    remove_timeout(index);
00196 
00197    struct ring_record_t* rr = shm_malloc(sizeof(struct ring_record_t));
00198    assert(rr);
00199 
00200    rr->next = NULL;
00201    rr->time = get_ticks();
00202    strncpy(rr->callid, callid.s, MIN(callid.len, MAXCALLIDLEN));
00203    rr->callid[MIN(callid.len, MAXCALLIDLEN)] = 0;
00204 
00205    if ((*hashtable)[index].tail) {
00206       (*hashtable)[index].tail->next = rr;
00207       (*hashtable)[index].tail = rr;
00208    }
00209    else {
00210       (*hashtable)[index].head = rr;
00211       (*hashtable)[index].tail = rr;
00212    }
00213 
00214    LM_DBG("inserting at %d %.*s ticks=%d\n", index, callid.len, callid.s, rr->time);
00215 }
00216 
00217 
00218 /*!
00219  * \brief Helper functions that checks if the hash table contains the callid
00220  * \param callid Call-ID that is searched
00221  * \return 1 when callid could be found, 0 when not found
00222  */
00223 static int contains(str callid)
00224 {
00225    unsigned int index = hash(callid.s, callid.len) & HASHTABLEMASK;
00226 
00227    remove_timeout(index);
00228 
00229    struct ring_record_t* rr = (*hashtable)[index].head;
00230    while (rr) {
00231       if (strncmp(rr->callid, callid.s, callid.len) == 0) return 1;
00232       rr = rr->next;
00233    }
00234    return 0;
00235 }
00236 
00237 
00238 /*!
00239  * \brief Convert a 180 to a 180 message.
00240  * \param msg SIP message
00241  */
00242 static int conv183(struct sip_msg *msg)
00243 {
00244    /* content-length and content-type headers are removed */
00245    char *del1_start = strstr(msg->buf, "Content-Length:");
00246    char *del2_start = strstr(msg->buf, "Content-Type:");
00247    if (del1_start>del2_start) {
00248       char *tmp = del1_start;
00249       del1_start = del2_start;
00250       del2_start = tmp;
00251    }
00252 
00253    char *del1_end = NULL;
00254    if (del1_start) {
00255       del1_end = strstr(del1_start, "\r\n");
00256       if (del1_end) del1_end+=2;
00257    }
00258    char *del2_end = NULL;
00259    if (del2_start) {
00260       del2_end = strstr(del2_start, "\r\n");
00261       if (del2_end) del2_end+=2;
00262    }
00263 
00264    /* 180 message does not need session description */
00265    char *eoh = strstr(msg->buf, "\r\n\r\n");
00266    if (eoh) eoh+=2;
00267 
00268    if ((!del1_start) || (!del2_start) || (!del1_end) || (!del2_end) || (!eoh)) {
00269       LM_ERR("got invalid 183 message\n");
00270       return -1;
00271    }
00272 
00273    /*
00274     * if message is parsed further than first deletion, offsets of parsed strings would
00275     * not be correct any more. In that case do not convert! If this error is reported,
00276     * check if other pre script callbacks are installed before the one of this module.
00277     */
00278    if (msg->unparsed>del1_start) {
00279       LM_ERR("183 message got parsed too far!\n");
00280       return -1;
00281    }
00282 
00283    /* setting new status */
00284    msg->first_line.u.reply.statuscode=180;
00285    msg->first_line.u.reply.status.s[2]='0';
00286    // don't change length of reason string
00287    strncpy(msg->first_line.u.reply.reason.s, "Ringing                                           ", msg->first_line.u.reply.reason.len);
00288 
00289    /* calculate addresses of chunks to be moved */
00290    char *chunk1_start = del1_end;
00291    int chunk1_len     = del2_start-del1_end;
00292    char *chunk1_dst   = del1_start;
00293 
00294    char *chunk2_start = del2_end;
00295    int chunk2_len     = eoh-del2_end;
00296    char *chunk2_dst   = chunk1_dst+chunk1_len;
00297 
00298    char *chunk3_start = "Content-Length: 0\r\n\r\n";
00299    int chunk3_len     = strlen(chunk3_start);
00300    char *chunk3_dst   = chunk2_dst+chunk2_len;
00301 
00302    // move chunks
00303    memmove(chunk1_dst, chunk1_start, chunk1_len);
00304    memmove(chunk2_dst, chunk2_start, chunk2_len);
00305    memmove(chunk3_dst, chunk3_start, chunk3_len);
00306 
00307    /* terminate string with zero */
00308    *(chunk3_dst+chunk3_len)='\0';
00309 
00310    /* update message length */
00311    msg->len = strlen(msg->buf);
00312 
00313    return 0;
00314 }
00315 
00316 
00317 /*!
00318  * \brief Callback function that does the work inside the server.
00319  * \param msg SIP message
00320  * \param bar unused
00321  * \return 1 on success, -1 on failure
00322  */
00323 int ring_filter(struct sip_msg *msg, void *bar)
00324 {
00325    int contains_callid;
00326 
00327    if (msg->first_line.type == SIP_REPLY && msg->first_line.u.reply.statuscode == 183) {
00328       /* could fail, eg if already parsed, don't care about result */
00329       parse_headers(msg, HDR_CALLID_F, 0);
00330 
00331       if (msg->callid) {
00332          lock_get(ring_lock);
00333          contains_callid=contains(msg->callid->body);
00334          lock_release(ring_lock);
00335 
00336          if (contains_callid) {
00337             LM_DBG("converting 183 to 180 for %.*s\n", msg->callid->body.len, msg->callid->body.s);
00338             if (conv183(msg)!=0) return -1;
00339          }
00340       } else {
00341          LM_ERR("no callid\n");
00342          return -1;
00343       }
00344    }
00345 
00346    return 1;
00347 }
00348 
00349 
00350 /*!
00351  * \brief Fixup function for the ring_insert_callid function
00352  * \param param unused
00353  * \param param_no unused
00354  * \return 0
00355  */
00356 int ring_fixup(void ** param, int param_no) {
00357    if (ring_timeout == 0) {
00358       LM_ERR("ring_insert_callid functionality deactivated, you need to set a positive ring_timeout\n");
00359       return -1;
00360    }
00361    return 0;
00362 }

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