modules/lcr: Fixed to/from_gw tests when proto parameter is 0 (ANY)
[sip-router] / tcp_options.c
1 /* 
2  * $Id$
3  * 
4  * Copyright (C) 2007 iptelorg GmbH
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 /*
19  * tcp options
20  *
21  * History:
22  * --------
23  *  2007-11-28  created by andrei
24  *  2009-03-05  use cfg framework (andrei)
25  */
26
27 /*!
28  * \file
29  * \brief SIP-router core :: 
30  * \ingroup core
31  * Module: \ref core
32  */
33
34 #include "tcp_options.h"
35 #include "dprint.h"
36 #include "globals.h"
37 #include "timer_ticks.h"
38 #include "cfg/cfg.h"
39 #include "tcp_init.h" /* DEFAULT* */
40
41
42
43 /* default/initial values for tcp config options
44    NOTE: all the options are initialized in init_tcp_options()
45    depending on compile time defines */
46 struct cfg_group_tcp tcp_default_cfg;
47
48
49
50 static int fix_connect_to(void* cfg_h, str* gname, str* name, void** val);
51 static int fix_send_to(void* cfg_h, str* gname, str* name, void** val);
52 static int fix_con_lt(void* cfg_h, str* gname, str* name, void** val);
53 static int fix_max_conns(void* cfg_h, str* gname, str* name, void** val);
54 static int fix_max_tls_conns(void* cfg_h, str* gname, str* name, void** val);
55
56
57
58 /* cfg_group_tcp description (for the config framework)*/
59 static cfg_def_t tcp_cfg_def[] = {
60         /*   name        , type |input type| chg type, min, max, fixup, proc. cbk 
61               description */
62         { "connect_timeout", CFG_VAR_INT | CFG_ATOMIC,  -1,
63                                                 TICKS_TO_S(MAX_TCP_CON_LIFETIME),  fix_connect_to,   0,
64                 "used only in non-async mode, in seconds"},
65         { "send_timeout", CFG_VAR_INT | CFG_ATOMIC,   -1,
66                                                 MAX_TCP_CON_LIFETIME,               fix_send_to,     0,
67                 "in seconds"},
68         { "connection_lifetime", CFG_VAR_INT | CFG_ATOMIC,   -1,
69                                                 MAX_TCP_CON_LIFETIME,               fix_con_lt,      0,
70                 "connection lifetime (in seconds)"},
71         { "max_connections", CFG_VAR_INT | CFG_ATOMIC, 0, (1U<<31)-1,
72                                                                                                                fix_max_conns,    0,
73                 "maximum tcp connections number, soft limit"},
74         { "max_tls_connections", CFG_VAR_INT | CFG_ATOMIC, 0, (1U<<31)-1,
75                                                                                                                fix_max_tls_conns,0,
76                 "maximum tls connections number, soft limit"},
77         { "no_connect",   CFG_VAR_INT | CFG_ATOMIC,      0,   1,      0,         0,
78                 "if set only accept new connections, never actively open new ones"},
79         { "fd_cache",     CFG_VAR_INT | CFG_READONLY,    0,   1,      0,         0,
80                 "file descriptor cache for tcp_send"},
81         /* tcp async options */
82         { "async",        CFG_VAR_INT | CFG_READONLY,    0,   1,      0,         0,
83                 "async mode for writes and connects"},
84         { "connect_wait", CFG_VAR_INT | CFG_READONLY,    0,   1,      0,         0,
85                 "parallel simultaneous connects to the same dst. (0) or one connect"},
86         { "conn_wq_max",  CFG_VAR_INT | CFG_ATOMIC,      0, 1024*1024, 0,        0,
87                 "maximum bytes queued for write per connection (depends on async)"},
88         { "wq_max",       CFG_VAR_INT | CFG_ATOMIC,      0,  1<<30,    0,        0,
89                 "maximum bytes queued for write allowed globally (depends on async)"},
90         /* see also send_timeout above */
91         /* tcp socket options */
92         { "defer_accept", CFG_VAR_INT | CFG_READONLY,    0,   3600,   0,         0,
93                 "0/1 on linux, seconds on freebsd (see docs)"},
94         { "delayed_ack",  CFG_VAR_INT | CFG_ATOMIC,      0,      1,   0,         0,
95                 "initial ack will be delayed and sent with the first data segment"},
96         { "syncnt",       CFG_VAR_INT | CFG_ATOMIC,      0,   1024,   0,         0,
97                 "number of syn retransmissions before aborting a connect (0=not set)"},
98         { "linger2",      CFG_VAR_INT | CFG_ATOMIC,      0,   3600,   0,         0,
99                 "lifetime of orphaned sockets in FIN_WAIT2 state in s (0=not set)"},
100         { "keepalive",    CFG_VAR_INT | CFG_ATOMIC,      0,      1,   0,         0,
101                 "enables/disables keepalives for tcp"},
102         { "keepidle",     CFG_VAR_INT | CFG_ATOMIC,      0, 24*3600,  0,         0,
103                 "time before sending a keepalive if the connection is idle (linux)"},
104         { "keepintvl",    CFG_VAR_INT | CFG_ATOMIC,      0, 24*3600,  0,         0,
105                 "time interval between keepalive probes on failure (linux)"},
106         { "keepcnt",     CFG_VAR_INT | CFG_ATOMIC,       0,    1<<10,  0,        0,
107                 "number of failed keepalives before dropping the connection (linux)"},
108         /* other options */
109         { "crlf_ping",   CFG_VAR_INT | CFG_ATOMIC,      0,        1,  0,         0,
110                 "enable responding to CRLF SIP-level keepalives "},
111         { "accept_aliases", CFG_VAR_INT | CFG_ATOMIC,   0,        1,  0,         0,
112                 "turn on/off tcp aliases (see tcp_accept_aliases) "},
113         { "alias_flags", CFG_VAR_INT | CFG_ATOMIC,      0,        2,  0,         0,
114                 "flags used for adding new aliases (FORCE_ADD:1 , REPLACE:2) "},
115         { "new_conn_alias_flags", CFG_VAR_INT | CFG_ATOMIC, 0,    2,  0,         0,
116                 "flags for the def. aliases for a new conn. (FORCE_ADD:1, REPLACE:2 "},
117         { "accept_no_cl",   CFG_VAR_INT | CFG_ATOMIC,   0,        1,  0,         0,
118                 "accept TCP messges without Content-Lenght "},
119         /* internal and/or "fixed" versions of some vars
120            (not supposed to be writeable, read will provide only debugging value*/
121         { "rd_buf_size", CFG_VAR_INT | CFG_ATOMIC,    512,    16777216,  0,         0,
122                 "internal read buffer size (should be > max. expected datagram)"},
123         { "wq_blk_size", CFG_VAR_INT | CFG_ATOMIC,    1,    65535,  0,         0,
124                 "internal async write block size (debugging use only for now)"},
125         {0, 0, 0, 0, 0, 0, 0}
126 };
127
128
129 void* tcp_cfg; /* tcp config handle */
130
131 /* set defaults */
132 void init_tcp_options()
133 {
134         tcp_default_cfg.connect_timeout_s=DEFAULT_TCP_CONNECT_TIMEOUT;
135         tcp_default_cfg.send_timeout=S_TO_TICKS(DEFAULT_TCP_SEND_TIMEOUT);
136         tcp_default_cfg.con_lifetime=S_TO_TICKS(DEFAULT_TCP_CONNECTION_LIFETIME_S);
137 #ifdef USE_TCP
138         tcp_default_cfg.max_connections=tcp_max_connections;
139         tcp_default_cfg.max_tls_connections=tls_max_connections;
140 #else /*USE_TCP*/
141         tcp_default_cfg.max_connections=0;
142         tcp_default_cfg.max_tls_connections=0;
143 #endif /*USE_TCP*/
144 #ifdef TCP_ASYNC
145         tcp_default_cfg.async=1;
146         tcp_default_cfg.tcpconn_wq_max=32*1024; /* 32 k */
147         tcp_default_cfg.tcp_wq_max=10*1024*1024; /* 10 MB */
148 #ifdef TCP_CONNECT_WAIT
149         tcp_default_cfg.tcp_connect_wait=1;
150 #endif /* TCP_CONNECT_WAIT */
151 #endif /* TCP_ASYNC */
152 #ifdef TCP_FD_CACHE
153         tcp_default_cfg.fd_cache=1;
154 #endif
155 #ifdef HAVE_SO_KEEPALIVE
156         tcp_default_cfg.keepalive=1;
157 #endif
158 /*
159 #if defined HAVE_TCP_DEFER_ACCEPT || defined HAVE_TCP_ACCEPT_FILTER
160         tcp_default_cfg.defer_accept=1;
161 #endif
162 */
163 #ifdef HAVE_TCP_QUICKACK
164         tcp_default_cfg.delayed_ack=1;
165 #endif
166         tcp_default_cfg.crlf_ping=1;
167         tcp_default_cfg.accept_aliases=0; /* don't accept aliases by default */
168         /* flags used for adding new aliases */
169         tcp_default_cfg.alias_flags=TCP_ALIAS_FORCE_ADD;
170         /* flags used for adding the default aliases of a new tcp connection */
171         tcp_default_cfg.new_conn_alias_flags=TCP_ALIAS_REPLACE;
172         tcp_default_cfg.rd_buf_size=DEFAULT_TCP_BUF_SIZE;
173         tcp_default_cfg.wq_blk_size=DEFAULT_TCP_WBUF_SIZE;
174 }
175
176
177
178 #define W_OPT_NC(option) \
179         if (tcp_default_cfg.option){\
180                 WARN("tcp_options: tcp_" #option \
181                                 " cannot be enabled (recompile needed)\n"); \
182                 tcp_default_cfg.option=0; \
183         }
184
185
186
187 #define W_OPT_NS(option) \
188         if (tcp_default_cfg.option){\
189                 WARN("tcp_options: tcp_" #option \
190                                 " cannot be enabled (no OS support)\n"); \
191                 tcp_default_cfg.option=0; \
192         }
193
194
195
196 /* if *to<0 to=default_val, else if to>max_val to=max_val */
197 static void fix_timeout(char* name, int* to, int default_val, unsigned max_val)
198 {
199         if (*to < 0) *to=default_val;
200         else if ((unsigned)*to > max_val){
201                 WARN("%s: timeout too big (%u), the maximum value is %u\n",
202                                 name, *to, max_val);
203                 *to=max_val;
204         }
205 }
206
207
208
209 static int fix_connect_to(void* cfg_h, str* gname, str* name, void** val)
210 {
211         int v;
212         v=(int)(long)*val;
213         fix_timeout("tcp_connect_timeout", &v, DEFAULT_TCP_CONNECT_TIMEOUT,
214                                                 TICKS_TO_S(MAX_TCP_CON_LIFETIME));
215         *val=(void*)(long)v;
216         return 0;
217 }
218
219
220 static int fix_send_to(void* cfg_h, str* gname, str* name, void** val)
221 {
222         int v;
223         v=S_TO_TICKS((int)(long)*val);
224         fix_timeout("tcp_send_timeout", &v, S_TO_TICKS(DEFAULT_TCP_SEND_TIMEOUT),
225                                                 MAX_TCP_CON_LIFETIME);
226         *val=(void*)(long)v;
227         return 0;
228 }
229
230
231 static int fix_con_lt(void* cfg_h, str* gname, str* name, void** val)
232 {
233         int v;
234         v=S_TO_TICKS((int)(long)*val);
235         fix_timeout("tcp_connection_lifetime", &v, 
236                                         MAX_TCP_CON_LIFETIME, MAX_TCP_CON_LIFETIME);
237         *val=(void*)(long)v;
238         return 0;
239 }
240
241
242 static int fix_max_conns(void* cfg_h, str* gname, str* name, void** val)
243 {
244         int v;
245         v=(int)(long)*val;
246 #ifdef USE_TCP
247         if (v>tcp_max_connections){
248                 INFO("cannot override hard tcp_max_connections limit, please"
249                                 " restart and increase tcp_max_connections in the cfg.\n");
250                 v=tcp_max_connections;
251         }
252 #else /* USE_TCP */
253         if (v){
254                 ERR("TCP support disabled at compile-time, tcp_max_connection is"
255                                 " hardwired to 0.\n");
256                 v=0;
257         }
258 #endif /*USE_TCP */
259         *val=(void*)(long)v;
260         return 0;
261 }
262
263 static int fix_max_tls_conns(void* cfg_h, str* gname, str* name, void** val)
264 {
265         int v;
266         v=(int)(long)*val;
267 #ifdef USE_TLS
268         if (v>tls_max_connections){
269                 INFO("cannot override hard tls_max_connections limit, please"
270                                 " restart and increase tls_max_connections in the cfg.\n");
271                 v=tls_max_connections;
272         }
273 #else /* USE_TLS */
274         if (v){
275                 ERR("TLS support disabled at compile-time, tls_max_connection is"
276                                 " hardwired to 0.\n");
277                 v=0;
278         }
279 #endif /*USE_TLS */
280         *val=(void*)(long)v;
281         return 0;
282 }
283
284
285
286 /** fix *val according to the cfg entry "name".
287  * (*val must be integer)
288  * 1. check if *val is between name min..max and if not change it to
289  *    the corresp. value
290  * 2. call fixup callback if defined in the cfg
291  * @return 0 on success
292  */
293 static int tcp_cfg_def_fix(char* name, int* val)
294 {
295         cfg_def_t* c;
296         str s;
297         
298         for (c=&tcp_cfg_def[0]; c->name; c++){
299                 if (strcmp(name, c->name)==0){
300                         /* found */
301                         if ((c->type & CFG_VAR_INT)  && (c->min || c->max)){
302                                 if (*val < c->min) *val=c->min;
303                                 else if (*val > c->max) *val=c->max;
304                                 if (c->on_change_cb){
305                                         s.s=c->name;
306                                         s.len=strlen(s.s);
307                                         return c->on_change_cb(&tcp_default_cfg, NULL, &s, (void*)val);
308                                 }
309                         }
310                         return 0;
311                 }
312         }
313         WARN("tcp config option \"%s\" not found\n", name);
314         return -1; /* not found */
315 }
316
317
318
319 /* checks & warns if some tcp_option cannot be enabled */
320 void tcp_options_check()
321 {
322 #ifndef TCP_FD_CACHE
323         W_OPT_NC(defer_accept);
324 #endif
325
326 #ifndef TCP_ASYNC
327         W_OPT_NC(async);
328         W_OPT_NC(tcpconn_wq_max);
329         W_OPT_NC(tcp_wq_max);
330 #endif /* TCP_ASYNC */
331 #ifndef TCP_CONNECT_WAIT
332         W_OPT_NC(tcp_connect_wait);
333 #endif /* TCP_CONNECT_WAIT */
334         
335         if (tcp_default_cfg.tcp_connect_wait && !tcp_default_cfg.async){
336                 tcp_default_cfg.tcp_connect_wait=0;
337         }
338         
339 #if ! defined HAVE_TCP_DEFER_ACCEPT && ! defined HAVE_TCP_ACCEPT_FILTER
340         W_OPT_NS(defer_accept);
341 #endif
342 #ifndef HAVE_TCP_SYNCNT
343         W_OPT_NS(syncnt);
344 #endif
345 #ifndef HAVE_TCP_LINGER2
346         W_OPT_NS(linger2);
347 #endif
348 #ifndef HAVE_TCP_KEEPINTVL
349         W_OPT_NS(keepintvl);
350 #endif
351 #ifndef HAVE_TCP_KEEPIDLE
352         W_OPT_NS(keepidle);
353 #endif
354 #ifndef HAVE_TCP_KEEPCNT
355         W_OPT_NS(keepcnt);
356 #endif
357         if (tcp_default_cfg.keepintvl || tcp_default_cfg.keepidle ||
358                         tcp_default_cfg.keepcnt){
359                 tcp_default_cfg.keepalive=1; /* force on */
360         }
361 #ifndef HAVE_SO_KEEPALIVE
362         W_OPT_NS(keepalive);
363 #endif
364 #ifndef HAVE_TCP_QUICKACK
365         W_OPT_NS(delayed_ack);
366 #endif
367         /* fix various timeouts */
368         fix_timeout("tcp_connect_timeout", &tcp_default_cfg.connect_timeout_s,
369                                                 DEFAULT_TCP_CONNECT_TIMEOUT,
370                                                 TICKS_TO_S(MAX_TCP_CON_LIFETIME));
371         fix_timeout("tcp_send_timeout", &tcp_default_cfg.send_timeout,
372                                                 S_TO_TICKS(DEFAULT_TCP_SEND_TIMEOUT),
373                                                 MAX_TCP_CON_LIFETIME);
374         fix_timeout("tcp_connection_lifetime", &tcp_default_cfg.con_lifetime,
375                                                 MAX_TCP_CON_LIFETIME, MAX_TCP_CON_LIFETIME);
376 #ifdef USE_TCP
377         tcp_default_cfg.max_connections=tcp_max_connections;
378         tcp_default_cfg.max_tls_connections=tls_max_connections;
379 #else /* USE_TCP */
380         tcp_default_cfg.max_connections=0;
381         tcp_default_cfg.max_tls_connections=0;
382 #endif /* USE_TCP */
383         tcp_cfg_def_fix("rd_buf_size", (int*)&tcp_default_cfg.rd_buf_size);
384         tcp_cfg_def_fix("wq_blk_size", (int*)&tcp_default_cfg.wq_blk_size);
385 }
386
387
388
389 void tcp_options_get(struct cfg_group_tcp* t)
390 {
391         *t=*(struct cfg_group_tcp*)tcp_cfg;
392 }
393
394
395
396 /** register tcp config into the configuration framework.
397  *  @return 0 on succes, -1 on error*/
398 int tcp_register_cfg()
399 {
400         if (cfg_declare("tcp", tcp_cfg_def, &tcp_default_cfg, cfg_sizeof(tcp),
401                                         &tcp_cfg))
402                 return -1;
403         if (tcp_cfg==0){
404                 BUG("null tcp cfg");
405                 return -1;
406         }
407         return 0;
408 }