prime_hash.c

Go to the documentation of this file.
00001 /*
00002  * $Id: prime_hash.c 5168 2008-11-05 10:27:42Z henningw $
00003  *
00004  * Copyright (C) 2007 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
00026  * Functions for determinung a pseudo random number over a message's
00027  * header field, based on CRC32 or a prime number algorithm.
00028  */
00029 
00030 #include "../../sr_module.h"
00031 #include "../../parser/parse_uri.h"
00032 #include "../../parser/parse_to.h"
00033 #include "../../parser/parse_from.h"
00034 #include "../../crc.h"
00035 
00036 #include <ctype.h>
00037 
00038 #include "prime_hash.h"
00039 
00040 
00041 static int determine_source(struct sip_msg *msg, enum hash_source source,
00042                             str *source_string);
00043 static int validate_msg(struct sip_msg * msg);
00044 static int determine_call_id (struct sip_msg *msg, str *source_string);
00045 static int determine_fromto_uri (struct to_body *fromto, str *source_string);
00046 static int determine_fromto_user (struct to_body *fromto, str *source_string);
00047 static int first_token (str *source_string);
00048 
00049 
00050 int hash_func (struct sip_msg * msg,
00051                          enum hash_source source, int denominator) {
00052    int ret;
00053    unsigned int hash;
00054    str source_string;
00055 
00056    if(determine_source (msg, source, &source_string) == -1) {
00057       return -1;
00058    }
00059    crc32_uint(&source_string, &hash);
00060 
00061    ret = hash % denominator;
00062    LM_DBG("hash: %u %% %i = %i\n", hash, denominator, ret);
00063    return ret;
00064 }
00065 
00066 int prime_hash_func(struct sip_msg * msg,
00067                               enum hash_source source, int denominator) {
00068    str source_string;
00069    if(source != shs_from_user && source != shs_to_user) {
00070       LM_ERR("chosen hash source not usable (may contain letters)\n");
00071       return -1;
00072    }
00073    if (determine_source (msg, source, &source_string) == -1) {
00074       return -1;
00075    }
00076 
00077    static const int INT_DIGIT_LIMIT = 18;
00078    static const int PRIME_NUMBER = 51797;
00079    uint64_t number = 0;
00080    uint64_t p10;
00081    int i, j, limit = 0;
00082    int ret;
00083    char source_number_s[INT_DIGIT_LIMIT + 1];
00084 
00085    i = INT_DIGIT_LIMIT - 1;
00086    j = source_string.len - 1;
00087    source_number_s[INT_DIGIT_LIMIT] ='\0';
00088 
00089    while(i >= 0 && j >= 0) {
00090       if(isdigit(source_string.s[j])) {
00091          source_number_s[i] = source_string.s[j];
00092          i--;
00093       }
00094       j--;
00095    }
00096    limit = i;
00097 
00098    for(i=INT_DIGIT_LIMIT - 1, p10=1; i>limit; i--, p10=p10*10) {
00099       number += (source_number_s[i] - '0') * p10;
00100    }
00101 
00102    LM_DBG("source_string is %.*s, source_number_s "
00103        "is: %s, number is %llu\n", source_string.len, source_string.s,
00104        source_number_s + (limit + 1), (long long unsigned int)number);
00105    ret = number % PRIME_NUMBER;
00106    ret = ret % denominator + 1;
00107    LM_DBG("calculated hash is: %i\n", ret);
00108    return ret;
00109 }
00110 
00111 static int determine_source (struct sip_msg *msg, enum hash_source source,
00112                              str *source_string) {
00113    source_string->s = NULL;
00114    source_string->len = 0;
00115 
00116    if(validate_msg(msg) < 0) {
00117       return -1;
00118    }
00119 
00120    switch (source) {
00121          case shs_call_id:
00122          return determine_call_id (msg, source_string);
00123          case shs_from_uri:
00124          return determine_fromto_uri (get_from(msg), source_string);
00125          case shs_from_user:
00126          return determine_fromto_user (get_from(msg), source_string);
00127          case shs_to_uri:
00128          return determine_fromto_uri (get_to(msg), source_string);
00129          case shs_to_user:
00130          return determine_fromto_user (get_to(msg), source_string);
00131          default:
00132          LM_ERR("unknown hash source %i.\n",
00133               (int) source);
00134          return -1;
00135    }
00136 }
00137 
00138 static int validate_msg(struct sip_msg * msg) {
00139    if(!msg->callid && ((parse_headers(msg, HDR_CALLID_F, 0) == -1) || !msg->callid)) {
00140       LM_ERR("Message has no Call-ID header\n");
00141       return -1;
00142    }
00143    if(!msg->to && ((parse_headers(msg, HDR_TO_F, 0) == -1) || !msg->to)) {
00144       LM_ERR("Message has no To header\n");
00145       return -1;
00146    }
00147    if(!msg->from && ((parse_headers(msg, HDR_FROM_F, 0) == -1) || !msg->from)) {
00148       LM_ERR("Message has no From header\n");
00149       return -1;
00150    }
00151    //TODO it would make more sense to do the parsing just if its needed
00152    //     but parse_from_header is smart enough, so its probably not a huge problem
00153    if (parse_from_header(msg) < 0) {
00154       LM_ERR("Error while parsing From header field\n");
00155       return -1;
00156    }
00157    return 0;
00158 }
00159 
00160 static int determine_call_id (struct sip_msg *msg, str *source_string) {
00161    source_string->s = msg->callid->body.s;
00162    source_string->len = msg->callid->body.len;
00163    first_token (source_string);
00164    return 0;
00165 }
00166 
00167 static int determine_fromto_uri (struct to_body *fromto, str *source_string) {
00168    if (fromto == NULL) {
00169       LM_ERR("fromto is NULL!\n");
00170       return -1;
00171    }
00172    source_string->s = fromto->uri.s;
00173    source_string->len = fromto->uri.len;
00174    return 0;
00175 }
00176 
00177 static int determine_fromto_user (struct to_body *fromto, str *source_string) {
00178    struct sip_uri uri;
00179 
00180    if (fromto == NULL) {
00181       LM_ERR("fromto is NULL!\n");
00182       return -1;
00183    }
00184    if (parse_uri (fromto->uri.s, fromto->uri.len, &uri) < 0) {
00185       LM_ERR("Failed to parse From or To URI.\n");
00186       return -1;
00187    }
00188    source_string->s = uri.user.s;
00189    source_string->len = uri.user.len;
00190    return 0;
00191 }
00192 
00193 static int first_token (str *source_string) {
00194    size_t len;
00195 
00196    if (source_string->s == NULL || source_string->len == 0) {
00197       return 0;
00198    }
00199 
00200    while (source_string->len > 0 && isspace (*source_string->s)) {
00201       ++source_string->s;
00202       --source_string->len;
00203    }
00204    for (len = 0; len < source_string->len; ++len) {
00205       if (isspace (source_string->s[len])) {
00206          source_string->len = len;
00207          break;
00208       }
00209    }
00210    return 0;
00211 }

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