123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408 |
- /*
- * $Id$
- *
- * Copyright (C) 2007 iptelorg GmbH
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
- /*
- * tcp options
- *
- * History:
- * --------
- * 2007-11-28 created by andrei
- * 2009-03-05 use cfg framework (andrei)
- */
- /*!
- * \file
- * \brief SIP-router core ::
- * \ingroup core
- * Module: \ref core
- */
- #include "tcp_options.h"
- #include "dprint.h"
- #include "globals.h"
- #include "timer_ticks.h"
- #include "cfg/cfg.h"
- #include "tcp_init.h" /* DEFAULT* */
- /* default/initial values for tcp config options
- NOTE: all the options are initialized in init_tcp_options()
- depending on compile time defines */
- struct cfg_group_tcp tcp_default_cfg;
- static int fix_connect_to(void* cfg_h, str* gname, str* name, void** val);
- static int fix_send_to(void* cfg_h, str* gname, str* name, void** val);
- static int fix_con_lt(void* cfg_h, str* gname, str* name, void** val);
- static int fix_max_conns(void* cfg_h, str* gname, str* name, void** val);
- static int fix_max_tls_conns(void* cfg_h, str* gname, str* name, void** val);
- /* cfg_group_tcp description (for the config framework)*/
- static cfg_def_t tcp_cfg_def[] = {
- /* name , type |input type| chg type, min, max, fixup, proc. cbk
- description */
- { "connect_timeout", CFG_VAR_INT | CFG_ATOMIC, -1,
- TICKS_TO_S(MAX_TCP_CON_LIFETIME), fix_connect_to, 0,
- "used only in non-async mode, in seconds"},
- { "send_timeout", CFG_VAR_INT | CFG_ATOMIC, -1,
- MAX_TCP_CON_LIFETIME, fix_send_to, 0,
- "in seconds"},
- { "connection_lifetime", CFG_VAR_INT | CFG_ATOMIC, -1,
- MAX_TCP_CON_LIFETIME, fix_con_lt, 0,
- "connection lifetime (in seconds)"},
- { "max_connections", CFG_VAR_INT | CFG_ATOMIC, 0, (1U<<31)-1,
- fix_max_conns, 0,
- "maximum tcp connections number, soft limit"},
- { "max_tls_connections", CFG_VAR_INT | CFG_ATOMIC, 0, (1U<<31)-1,
- fix_max_tls_conns,0,
- "maximum tls connections number, soft limit"},
- { "no_connect", CFG_VAR_INT | CFG_ATOMIC, 0, 1, 0, 0,
- "if set only accept new connections, never actively open new ones"},
- { "fd_cache", CFG_VAR_INT | CFG_READONLY, 0, 1, 0, 0,
- "file descriptor cache for tcp_send"},
- /* tcp async options */
- { "async", CFG_VAR_INT | CFG_READONLY, 0, 1, 0, 0,
- "async mode for writes and connects"},
- { "connect_wait", CFG_VAR_INT | CFG_READONLY, 0, 1, 0, 0,
- "parallel simultaneous connects to the same dst. (0) or one connect"},
- { "conn_wq_max", CFG_VAR_INT | CFG_ATOMIC, 0, 1024*1024, 0, 0,
- "maximum bytes queued for write per connection (depends on async)"},
- { "wq_max", CFG_VAR_INT | CFG_ATOMIC, 0, 1<<30, 0, 0,
- "maximum bytes queued for write allowed globally (depends on async)"},
- /* see also send_timeout above */
- /* tcp socket options */
- { "defer_accept", CFG_VAR_INT | CFG_READONLY, 0, 3600, 0, 0,
- "0/1 on linux, seconds on freebsd (see docs)"},
- { "delayed_ack", CFG_VAR_INT | CFG_ATOMIC, 0, 1, 0, 0,
- "initial ack will be delayed and sent with the first data segment"},
- { "syncnt", CFG_VAR_INT | CFG_ATOMIC, 0, 1024, 0, 0,
- "number of syn retransmissions before aborting a connect (0=not set)"},
- { "linger2", CFG_VAR_INT | CFG_ATOMIC, 0, 3600, 0, 0,
- "lifetime of orphaned sockets in FIN_WAIT2 state in s (0=not set)"},
- { "keepalive", CFG_VAR_INT | CFG_ATOMIC, 0, 1, 0, 0,
- "enables/disables keepalives for tcp"},
- { "keepidle", CFG_VAR_INT | CFG_ATOMIC, 0, 24*3600, 0, 0,
- "time before sending a keepalive if the connection is idle (linux)"},
- { "keepintvl", CFG_VAR_INT | CFG_ATOMIC, 0, 24*3600, 0, 0,
- "time interval between keepalive probes on failure (linux)"},
- { "keepcnt", CFG_VAR_INT | CFG_ATOMIC, 0, 1<<10, 0, 0,
- "number of failed keepalives before dropping the connection (linux)"},
- /* other options */
- { "crlf_ping", CFG_VAR_INT | CFG_ATOMIC, 0, 1, 0, 0,
- "enable responding to CRLF SIP-level keepalives "},
- { "accept_aliases", CFG_VAR_INT | CFG_ATOMIC, 0, 1, 0, 0,
- "turn on/off tcp aliases (see tcp_accept_aliases) "},
- { "alias_flags", CFG_VAR_INT | CFG_ATOMIC, 0, 2, 0, 0,
- "flags used for adding new aliases (FORCE_ADD:1 , REPLACE:2) "},
- { "new_conn_alias_flags", CFG_VAR_INT | CFG_ATOMIC, 0, 2, 0, 0,
- "flags for the def. aliases for a new conn. (FORCE_ADD:1, REPLACE:2 "},
- { "accept_no_cl", CFG_VAR_INT | CFG_ATOMIC, 0, 1, 0, 0,
- "accept TCP messges without Content-Length "},
- /* internal and/or "fixed" versions of some vars
- (not supposed to be writeable, read will provide only debugging value*/
- { "rd_buf_size", CFG_VAR_INT | CFG_ATOMIC, 512, 16777216, 0, 0,
- "internal read buffer size (should be > max. expected datagram)"},
- { "wq_blk_size", CFG_VAR_INT | CFG_ATOMIC, 1, 65535, 0, 0,
- "internal async write block size (debugging use only for now)"},
- {0, 0, 0, 0, 0, 0, 0}
- };
- void* tcp_cfg; /* tcp config handle */
- /* set defaults */
- void init_tcp_options()
- {
- tcp_default_cfg.connect_timeout_s=DEFAULT_TCP_CONNECT_TIMEOUT;
- tcp_default_cfg.send_timeout=S_TO_TICKS(DEFAULT_TCP_SEND_TIMEOUT);
- tcp_default_cfg.con_lifetime=S_TO_TICKS(DEFAULT_TCP_CONNECTION_LIFETIME_S);
- #ifdef USE_TCP
- tcp_default_cfg.max_connections=tcp_max_connections;
- tcp_default_cfg.max_tls_connections=tls_max_connections;
- #else /*USE_TCP*/
- tcp_default_cfg.max_connections=0;
- tcp_default_cfg.max_tls_connections=0;
- #endif /*USE_TCP*/
- #ifdef TCP_ASYNC
- tcp_default_cfg.async=1;
- tcp_default_cfg.tcpconn_wq_max=32*1024; /* 32 k */
- tcp_default_cfg.tcp_wq_max=10*1024*1024; /* 10 MB */
- #ifdef TCP_CONNECT_WAIT
- tcp_default_cfg.tcp_connect_wait=1;
- #endif /* TCP_CONNECT_WAIT */
- #endif /* TCP_ASYNC */
- #ifdef TCP_FD_CACHE
- tcp_default_cfg.fd_cache=1;
- #endif
- #ifdef HAVE_SO_KEEPALIVE
- tcp_default_cfg.keepalive=1;
- #endif
- /*
- #if defined HAVE_TCP_DEFER_ACCEPT || defined HAVE_TCP_ACCEPT_FILTER
- tcp_default_cfg.defer_accept=1;
- #endif
- */
- #ifdef HAVE_TCP_QUICKACK
- tcp_default_cfg.delayed_ack=1;
- #endif
- tcp_default_cfg.crlf_ping=1;
- tcp_default_cfg.accept_aliases=0; /* don't accept aliases by default */
- /* flags used for adding new aliases */
- tcp_default_cfg.alias_flags=TCP_ALIAS_FORCE_ADD;
- /* flags used for adding the default aliases of a new tcp connection */
- tcp_default_cfg.new_conn_alias_flags=TCP_ALIAS_REPLACE;
- tcp_default_cfg.rd_buf_size=DEFAULT_TCP_BUF_SIZE;
- tcp_default_cfg.wq_blk_size=DEFAULT_TCP_WBUF_SIZE;
- }
- #define W_OPT_NC(option) \
- if (tcp_default_cfg.option){\
- WARN("tcp_options: tcp_" #option \
- " cannot be enabled (recompile needed)\n"); \
- tcp_default_cfg.option=0; \
- }
- #define W_OPT_NS(option) \
- if (tcp_default_cfg.option){\
- WARN("tcp_options: tcp_" #option \
- " cannot be enabled (no OS support)\n"); \
- tcp_default_cfg.option=0; \
- }
- /* if *to<0 to=default_val, else if to>max_val to=max_val */
- static void fix_timeout(char* name, int* to, int default_val, unsigned max_val)
- {
- if (*to < 0) *to=default_val;
- else if ((unsigned)*to > max_val){
- WARN("%s: timeout too big (%u), the maximum value is %u\n",
- name, *to, max_val);
- *to=max_val;
- }
- }
- static int fix_connect_to(void* cfg_h, str* gname, str* name, void** val)
- {
- int v;
- v=(int)(long)*val;
- fix_timeout("tcp_connect_timeout", &v, DEFAULT_TCP_CONNECT_TIMEOUT,
- TICKS_TO_S(MAX_TCP_CON_LIFETIME));
- *val=(void*)(long)v;
- return 0;
- }
- static int fix_send_to(void* cfg_h, str* gname, str* name, void** val)
- {
- int v;
- v=S_TO_TICKS((int)(long)*val);
- fix_timeout("tcp_send_timeout", &v, S_TO_TICKS(DEFAULT_TCP_SEND_TIMEOUT),
- MAX_TCP_CON_LIFETIME);
- *val=(void*)(long)v;
- return 0;
- }
- static int fix_con_lt(void* cfg_h, str* gname, str* name, void** val)
- {
- int v;
- v=S_TO_TICKS((int)(long)*val);
- fix_timeout("tcp_connection_lifetime", &v,
- MAX_TCP_CON_LIFETIME, MAX_TCP_CON_LIFETIME);
- *val=(void*)(long)v;
- return 0;
- }
- static int fix_max_conns(void* cfg_h, str* gname, str* name, void** val)
- {
- int v;
- v=(int)(long)*val;
- #ifdef USE_TCP
- if (v>tcp_max_connections){
- INFO("cannot override hard tcp_max_connections limit, please"
- " restart and increase tcp_max_connections in the cfg.\n");
- v=tcp_max_connections;
- }
- #else /* USE_TCP */
- if (v){
- ERR("TCP support disabled at compile-time, tcp_max_connection is"
- " hardwired to 0.\n");
- v=0;
- }
- #endif /*USE_TCP */
- *val=(void*)(long)v;
- return 0;
- }
- static int fix_max_tls_conns(void* cfg_h, str* gname, str* name, void** val)
- {
- int v;
- v=(int)(long)*val;
- #ifdef USE_TLS
- if (v>tls_max_connections){
- INFO("cannot override hard tls_max_connections limit, please"
- " restart and increase tls_max_connections in the cfg.\n");
- v=tls_max_connections;
- }
- #else /* USE_TLS */
- if (v){
- ERR("TLS support disabled at compile-time, tls_max_connection is"
- " hardwired to 0.\n");
- v=0;
- }
- #endif /*USE_TLS */
- *val=(void*)(long)v;
- return 0;
- }
- /** fix *val according to the cfg entry "name".
- * (*val must be integer)
- * 1. check if *val is between name min..max and if not change it to
- * the corresp. value
- * 2. call fixup callback if defined in the cfg
- * @return 0 on success
- */
- static int tcp_cfg_def_fix(char* name, int* val)
- {
- cfg_def_t* c;
- str s;
-
- for (c=&tcp_cfg_def[0]; c->name; c++){
- if (strcmp(name, c->name)==0){
- /* found */
- if ((c->type & CFG_VAR_INT) && (c->min || c->max)){
- if (*val < c->min) *val=c->min;
- else if (*val > c->max) *val=c->max;
- if (c->on_change_cb){
- s.s=c->name;
- s.len=strlen(s.s);
- return c->on_change_cb(&tcp_default_cfg, NULL, &s, (void*)val);
- }
- }
- return 0;
- }
- }
- WARN("tcp config option \"%s\" not found\n", name);
- return -1; /* not found */
- }
- /* checks & warns if some tcp_option cannot be enabled */
- void tcp_options_check()
- {
- #ifndef TCP_FD_CACHE
- W_OPT_NC(defer_accept);
- #endif
- #ifndef TCP_ASYNC
- W_OPT_NC(async);
- W_OPT_NC(tcpconn_wq_max);
- W_OPT_NC(tcp_wq_max);
- #endif /* TCP_ASYNC */
- #ifndef TCP_CONNECT_WAIT
- W_OPT_NC(tcp_connect_wait);
- #endif /* TCP_CONNECT_WAIT */
-
- if (tcp_default_cfg.tcp_connect_wait && !tcp_default_cfg.async){
- tcp_default_cfg.tcp_connect_wait=0;
- }
-
- #if ! defined HAVE_TCP_DEFER_ACCEPT && ! defined HAVE_TCP_ACCEPT_FILTER
- W_OPT_NS(defer_accept);
- #endif
- #ifndef HAVE_TCP_SYNCNT
- W_OPT_NS(syncnt);
- #endif
- #ifndef HAVE_TCP_LINGER2
- W_OPT_NS(linger2);
- #endif
- #ifndef HAVE_TCP_KEEPINTVL
- W_OPT_NS(keepintvl);
- #endif
- #ifndef HAVE_TCP_KEEPIDLE
- W_OPT_NS(keepidle);
- #endif
- #ifndef HAVE_TCP_KEEPCNT
- W_OPT_NS(keepcnt);
- #endif
- if (tcp_default_cfg.keepintvl || tcp_default_cfg.keepidle ||
- tcp_default_cfg.keepcnt){
- tcp_default_cfg.keepalive=1; /* force on */
- }
- #ifndef HAVE_SO_KEEPALIVE
- W_OPT_NS(keepalive);
- #endif
- #ifndef HAVE_TCP_QUICKACK
- W_OPT_NS(delayed_ack);
- #endif
- /* fix various timeouts */
- fix_timeout("tcp_connect_timeout", &tcp_default_cfg.connect_timeout_s,
- DEFAULT_TCP_CONNECT_TIMEOUT,
- TICKS_TO_S(MAX_TCP_CON_LIFETIME));
- fix_timeout("tcp_send_timeout", &tcp_default_cfg.send_timeout,
- S_TO_TICKS(DEFAULT_TCP_SEND_TIMEOUT),
- MAX_TCP_CON_LIFETIME);
- fix_timeout("tcp_connection_lifetime", &tcp_default_cfg.con_lifetime,
- MAX_TCP_CON_LIFETIME, MAX_TCP_CON_LIFETIME);
- #ifdef USE_TCP
- tcp_default_cfg.max_connections=tcp_max_connections;
- tcp_default_cfg.max_tls_connections=tls_max_connections;
- #else /* USE_TCP */
- tcp_default_cfg.max_connections=0;
- tcp_default_cfg.max_tls_connections=0;
- #endif /* USE_TCP */
- tcp_cfg_def_fix("rd_buf_size", (int*)&tcp_default_cfg.rd_buf_size);
- tcp_cfg_def_fix("wq_blk_size", (int*)&tcp_default_cfg.wq_blk_size);
- }
- void tcp_options_get(struct cfg_group_tcp* t)
- {
- *t=*(struct cfg_group_tcp*)tcp_cfg;
- }
- /** register tcp config into the configuration framework.
- * @return 0 on succes, -1 on error*/
- int tcp_register_cfg()
- {
- if (cfg_declare("tcp", tcp_cfg_def, &tcp_default_cfg, cfg_sizeof(tcp),
- &tcp_cfg))
- return -1;
- if (tcp_cfg==0){
- BUG("null tcp cfg");
- return -1;
- }
- return 0;
- }
|