prime_hash.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
00003  *
00004  * Copyright (C) 2007 1&1 Internet AG
00005  *
00006  * This file is part of SIP-router, a free SIP server.
00007  *
00008  * SIP-router 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  * SIP-router 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 
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 #include <stdio.h> /* for snprintf */
00038 #include <stdlib.h> /* for rand */
00039 
00040 #include "prime_hash.h"
00041 
00042 #define CR_RANDBUF_S 20
00043 static char cr_randbuf[CR_RANDBUF_S];
00044 
00045 static int determine_source(struct sip_msg *msg, enum hash_source source,
00046                             str *source_string);
00047 static int validate_msg(struct sip_msg * msg);
00048 static int determine_call_id (struct sip_msg *msg, str *source_string);
00049 static int determine_fromto_uri (struct to_body *fromto, str *source_string);
00050 static int determine_fromto_user (struct to_body *fromto, str *source_string);
00051 static int determine_fromrand(str* source_string);
00052 static int first_token (str *source_string);
00053 
00054 
00055 int hash_func (struct sip_msg * msg,
00056                          enum hash_source source, int denominator) {
00057         int ret;
00058         unsigned int hash;
00059         str source_string;
00060 
00061         if(determine_source (msg, source, &source_string) == -1) {
00062                 return -1;
00063         }
00064 
00065         crc32_uint(&source_string, &hash);
00066 
00067         ret = hash % denominator;
00068         LM_DBG("hash: %u %% %i = %i\n", hash, denominator, ret);
00069         return ret;
00070 }
00071 
00072 static int determine_source (struct sip_msg *msg, enum hash_source source,
00073                              str *source_string) {
00074         source_string->s = NULL;
00075         source_string->len = 0;
00076 
00077         if(validate_msg(msg) < 0) {
00078                 return -1;
00079         }
00080 
00081         switch (source) {
00082                         case shs_call_id:
00083                         return determine_call_id (msg, source_string);
00084                         case shs_from_uri:
00085                         return determine_fromto_uri (get_from(msg), source_string);
00086                         case shs_from_user:
00087                         return determine_fromto_user (get_from(msg), source_string);
00088                         case shs_to_uri:
00089                         return determine_fromto_uri (get_to(msg), source_string);
00090                         case shs_to_user:
00091                         return determine_fromto_user (get_to(msg), source_string);
00092                         case shs_rand:
00093                         return determine_fromrand(source_string); /* msg is not needed */
00094                         default:
00095                         LM_ERR("unknown hash source %i.\n",
00096                              (int) source);
00097                         return -1;
00098         }
00099 }
00100 
00101 static int validate_msg(struct sip_msg * msg) {
00102         if(!msg->callid && ((parse_headers(msg, HDR_CALLID_F, 0) == -1) || !msg->callid)) {
00103                 LM_ERR("Message has no Call-ID header\n");
00104                 return -1;
00105         }
00106         if(!msg->to && ((parse_headers(msg, HDR_TO_F, 0) == -1) || !msg->to)) {
00107                 LM_ERR("Message has no To header\n");
00108                 return -1;
00109         }
00110         if(!msg->from && ((parse_headers(msg, HDR_FROM_F, 0) == -1) || !msg->from)) {
00111                 LM_ERR("Message has no From header\n");
00112                 return -1;
00113         }
00114         //TODO it would make more sense to do the parsing just if its needed
00115         //     but parse_from_header is smart enough, so its probably not a huge problem
00116         if (parse_from_header(msg) < 0) {
00117                 LM_ERR("Error while parsing From header field\n");
00118                 return -1;
00119         }
00120         return 0;
00121 }
00122 
00123 static int determine_call_id (struct sip_msg *msg, str *source_string) {
00124         source_string->s = msg->callid->body.s;
00125         source_string->len = msg->callid->body.len;
00126         first_token (source_string);
00127         return 0;
00128 }
00129 
00130 static int determine_fromto_uri (struct to_body *fromto, str *source_string) {
00131         if (fromto == NULL) {
00132                 LM_ERR("fromto is NULL!\n");
00133                 return -1;
00134         }
00135         source_string->s = fromto->uri.s;
00136         source_string->len = fromto->uri.len;
00137         return 0;
00138 }
00139 
00140 static int determine_fromto_user (struct to_body *fromto, str *source_string) {
00141         struct sip_uri uri;
00142 
00143         if (fromto == NULL) {
00144                 LM_ERR("fromto is NULL!\n");
00145                 return -1;
00146         }
00147         if (parse_uri (fromto->uri.s, fromto->uri.len, &uri) < 0) {
00148                 LM_ERR("Failed to parse From or To URI.\n");
00149                 return -1;
00150         }
00151         source_string->s = uri.user.s;
00152         source_string->len = uri.user.len;
00153         return 0;
00154 }
00155 
00156 static int determine_fromrand(str* source_string){
00157 
00158         snprintf(&cr_randbuf[0], CR_RANDBUF_S , "%d", rand());
00159 
00160         LM_NOTICE("randbuf is %s\n", cr_randbuf);
00161         source_string->s = cr_randbuf;
00162         source_string->len = strlen(source_string->s);
00163 
00164         return 0;
00165 }
00166 
00167 static int first_token (str *source_string) {
00168         size_t len;
00169 
00170         if (source_string->s == NULL || source_string->len == 0) {
00171                 return 0;
00172         }
00173 
00174         while (source_string->len > 0 && isspace (*source_string->s)) {
00175                 ++source_string->s;
00176                 --source_string->len;
00177         }
00178         for (len = 0; len < source_string->len; ++len) {
00179                 if (isspace (source_string->s[len])) {
00180                         source_string->len = len;
00181                         break;
00182                 }
00183         }
00184         return 0;
00185 }