- sock_lists completely re-organized
[sip-router] / modules / tm / callid.c
1 /*
2  * $Id$
3  *
4  * Fast Call-ID Generator
5  *
6  * Copyright (C) 2001-2003 Fhg Fokus
7  *
8  * This file is part of ser, a free SIP server.
9  *
10  * ser is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version
14  *
15  * For a license to use the ser software under conditions
16  * other than those described here, or to purchase support for this
17  * software, please contact iptel.org by e-mail at the following addresses:
18  *    info@iptel.org
19  *
20  * ser is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License 
26  * along with this program; if not, write to the Free Software 
27  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
28  *
29  * History:
30  * ----------
31  *  2003-04-09  Created by janakj
32  *  2003-10-24  updated to the new socket_info lists (andrei)
33  */
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include "../../dprint.h"
38 #include "../../pt.h"
39 #include "../../socket_info.h"
40 #include "callid.h"
41
42 #define CALLID_NR_LEN 20
43
44 /* Call-ID has the following form: <callid_nr>-<pid>@<ip>
45  * callid_nr is initialized as a random number and continually
46  * increases; -<pid>@<ip> is kept in callid_suffix
47  */
48 #define CALLID_SUFFIX_LEN ( 1 /* - */                                            + \
49                             5 /* pid */                                          + \
50                            42 /* embedded v4inv6 address can be looong '128.' */ + \
51                             2 /* parenthessis [] */                              + \
52                             1 /* ZT 0 */                                         + \
53                            16 /* one never knows ;-) */                            \
54                           )
55
56 #define CID_SEP '-' /* the character which separates random from constant part */
57
58 static unsigned long callid_nr;
59 static char callid_buf[CALLID_NR_LEN + CALLID_SUFFIX_LEN];
60
61 str callid_prefix;
62 str callid_suffix;
63
64
65 /*
66  * Initialize the Call-ID generator -- generates random prefix
67  */
68 int init_callid(void)
69 {
70         int rand_bits, i;
71
72              /* calculate the initial call-id */
73              /* how many bits and chars do we need to display the 
74               * whole ULONG number */
75         callid_prefix.len = sizeof(unsigned long) * 2;
76         callid_prefix.s = callid_buf;
77
78         if (callid_prefix.len > CALLID_NR_LEN) {
79                 LOG(L_ERR, "ERROR: Too small callid buffer\n");
80                 return -1;
81         }
82         
83         for(rand_bits = 1, i = RAND_MAX; i; i >>= 1, rand_bits++);  /* how long are the rand()s ? */
84         i = callid_prefix.len * 4 / rand_bits; /* how many rands() fit in the ULONG ? */
85
86              /* now fill in the callid with as many random
87               * numbers as you can + 1 */
88         callid_nr = rand(); /* this is the + 1 */
89
90         while(i--) {
91                 callid_nr <<= rand_bits;
92                 callid_nr |= rand();
93         }
94
95         i = snprintf(callid_prefix.s, callid_prefix.len + 1, "%0*lx", callid_prefix.len, callid_nr);
96         if ((i == -1) || (i > callid_prefix.len)) {
97                 LOG(L_CRIT, "BUG: SORRY, callid calculation failed\n");
98                 return -2;
99         }
100         
101         DBG("Call-ID initialization: '%.*s'\n", callid_prefix.len, callid_prefix.s);
102         return 0;
103 }
104
105
106 /*
107  * Child initialization -- generates suffix
108  */
109 int child_init_callid(int rank) 
110 {
111         struct socket_info *si;
112         
113         /* on tcp/tls bind_address is 0 so try to get the first address we listen
114          * on no matter the protocol */
115         si=bind_address?bind_address:get_first_socket();
116         if (si==0){
117                 LOG(L_CRIT, "BUG: child_init_callid: null socket list\n");
118                 return -1;
119         }
120         callid_suffix.s = callid_buf + callid_prefix.len;
121
122         callid_suffix.len = snprintf(callid_suffix.s, CALLID_SUFFIX_LEN,
123                                      "%c%d@%.*s", CID_SEP, my_pid(), 
124                                      si->address_str.len,
125                                      si->address_str.s);
126         if ((callid_suffix.len == -1) || (callid_suffix.len > CALLID_SUFFIX_LEN)) {
127                 LOG(L_ERR, "ERROR: child_init_callid: buffer too small\n");
128                 return -1;
129         }
130
131         DBG("DEBUG: callid: '%.*s'\n", callid_prefix.len + callid_suffix.len, callid_prefix.s);
132         return 0;
133 }
134
135
136 /*
137  * Increment a character in hex, return
138  * carry flag
139  */
140 static inline int inc_hexchar(char* _c)
141 {
142         if (*_c == '9') {
143                 *_c = 'a';
144                 return 0;
145         }
146
147         if (*_c == 'f') {
148                 *_c = '0';
149                 return 1;
150         }
151
152         (*_c)++;
153         return 0;
154 }
155
156
157 /*
158  * Get a unique Call-ID
159  */
160 void generate_callid(str* callid)
161 {
162         int i;
163
164         for(i = callid_prefix.len; i; i--) {
165                 if (!inc_hexchar(callid_prefix.s + i - 1)) break;
166         }
167         callid->s = callid_prefix.s;
168         callid->len = callid_prefix.len + callid_suffix.len;
169 }