tcp_options.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  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. #include "tcp_options.h"
  27. #include "dprint.h"
  28. #include "globals.h"
  29. #include "timer_ticks.h"
  30. #include "cfg/cfg.h"
  31. #include "tcp_init.h" /* DEFAULT* */
  32. /* default/initial values for tcp config options
  33. NOTE: all the options are initialized in init_tcp_options()
  34. depending on compile time defines */
  35. struct cfg_group_tcp tcp_default_cfg;
  36. static int fix_connect_to(void* cfg_h, str* gname, str* name, void** val);
  37. static int fix_send_to(void* cfg_h, str* gname, str* name, void** val);
  38. static int fix_con_lt(void* cfg_h, str* gname, str* name, void** val);
  39. static int fix_max_conns(void* cfg_h, str* gname, str* name, void** val);
  40. /* cfg_group_tcp description (for the config framework)*/
  41. static cfg_def_t tcp_cfg_def[] = {
  42. /* name , type |input type| chg type, min, max, fixup, proc. cbk
  43. description */
  44. { "connect_timeout", CFG_VAR_INT | CFG_ATOMIC, -1,
  45. TICKS_TO_S(MAX_TCP_CON_LIFETIME), fix_connect_to, 0,
  46. "used only in non-async mode, in seconds"},
  47. { "send_timeout", CFG_VAR_INT | CFG_ATOMIC, -1,
  48. MAX_TCP_CON_LIFETIME, fix_send_to, 0,
  49. "in seconds"},
  50. { "connection_lifetime", CFG_VAR_INT | CFG_ATOMIC, -1,
  51. MAX_TCP_CON_LIFETIME, fix_con_lt, 0,
  52. "connection lifetime (in seconds)"},
  53. { "max_connections", CFG_VAR_INT | CFG_ATOMIC, 0, (1U<<31)-1,
  54. fix_max_conns, 0,
  55. "maximum connection number, soft limit"},
  56. { "no_connect", CFG_VAR_INT | CFG_ATOMIC, 0, 1, 0, 0,
  57. "if set only accept new connections, never actively open new ones"},
  58. { "fd_cache", CFG_VAR_INT | CFG_READONLY, 0, 1, 0, 0,
  59. "file descriptor cache for tcp_send"},
  60. /* tcp async options */
  61. { "async", CFG_VAR_INT | CFG_READONLY, 0, 1, 0, 0,
  62. "async mode for writes and connects"},
  63. { "connect_wait", CFG_VAR_INT | CFG_READONLY, 0, 1, 0, 0,
  64. "parallel simultaneous connects to the same dst. (0) or one connect"},
  65. { "conn_wq_max", CFG_VAR_INT | CFG_ATOMIC, 0, 1024*1024, 0, 0,
  66. "maximum bytes queued for write per connection (depends on async)"},
  67. { "wq_max", CFG_VAR_INT | CFG_ATOMIC, 0, 1<<30, 0, 0,
  68. "maximum bytes queued for write allowed globally (depends on async)"},
  69. /* see also send_timeout above */
  70. /* tcp socket options */
  71. { "defer_accept", CFG_VAR_INT | CFG_READONLY, 0, 3600, 0, 0,
  72. "0/1 on linux, seconds on freebsd (see docs)"},
  73. { "delayed_ack", CFG_VAR_INT | CFG_ATOMIC, 0, 1, 0, 0,
  74. "initial ack will be delayed and sent with the first data segment"},
  75. { "syncnt", CFG_VAR_INT | CFG_ATOMIC, 0, 1024, 0, 0,
  76. "number of syn retransmissions before aborting a connect (0=not set)"},
  77. { "linger2", CFG_VAR_INT | CFG_ATOMIC, 0, 3600, 0, 0,
  78. "lifetime of orphaned sockets in FIN_WAIT2 state in s (0=not set)"},
  79. { "keepalive", CFG_VAR_INT | CFG_ATOMIC, 0, 1, 0, 0,
  80. "enables/disables keepalives for tcp"},
  81. { "keepidle", CFG_VAR_INT | CFG_ATOMIC, 0, 24*3600, 0, 0,
  82. "time before sending a keepalive if the connection is idle (linux)"},
  83. { "keepintvl", CFG_VAR_INT | CFG_ATOMIC, 0, 24*3600, 0, 0,
  84. "time interval between keepalive probes on failure (linux)"},
  85. { "keepcnt", CFG_VAR_INT | CFG_ATOMIC, 0, 1<<10, 0, 0,
  86. "number of failed keepalives before dropping the connection (linux)"},
  87. /* other options */
  88. { "crlf_ping", CFG_VAR_INT | CFG_ATOMIC, 0, 1, 0, 0,
  89. "enable responding to CRLF SIP-level keepalives "},
  90. { "accept_aliases", CFG_VAR_INT | CFG_ATOMIC, 0, 1, 0, 0,
  91. "turn on/off tcp aliases (see tcp_accept_aliases) "},
  92. { "alias_flags", CFG_VAR_INT | CFG_ATOMIC, 0, 2, 0, 0,
  93. "flags used for adding new aliases (FORCE_ADD:1 , REPLACE:2) "},
  94. { "new_conn_alias_flags", CFG_VAR_INT | CFG_ATOMIC, 0, 2, 0, 0,
  95. "flags for the def. aliases for a new conn. (FORCE_ADD:1, REPLACE:2 "},
  96. /* internal and/or "fixed" versions of some vars
  97. (not supposed to be writeable, read will provide only debugging value*/
  98. { "rd_buf_size", CFG_VAR_INT | CFG_ATOMIC, 512, 65536, 0, 0,
  99. "internal read buffer size (should be > max. expected datagram)"},
  100. { "wq_blk_size", CFG_VAR_INT | CFG_ATOMIC, 1, 65535, 0, 0,
  101. "internal async write block size (debugging use only for now)"},
  102. {0, 0, 0, 0, 0, 0, 0}
  103. };
  104. void* tcp_cfg; /* tcp config handle */
  105. /* set defaults */
  106. void init_tcp_options()
  107. {
  108. tcp_default_cfg.connect_timeout_s=DEFAULT_TCP_CONNECT_TIMEOUT;
  109. tcp_default_cfg.send_timeout=S_TO_TICKS(DEFAULT_TCP_SEND_TIMEOUT);
  110. tcp_default_cfg.con_lifetime=S_TO_TICKS(DEFAULT_TCP_CONNECTION_LIFETIME_S);
  111. tcp_default_cfg.max_connections=tcp_max_connections;
  112. #ifdef TCP_ASYNC
  113. tcp_default_cfg.async=1;
  114. tcp_default_cfg.tcpconn_wq_max=32*1024; /* 32 k */
  115. tcp_default_cfg.tcp_wq_max=10*1024*1024; /* 10 MB */
  116. #ifdef TCP_CONNECT_WAIT
  117. tcp_default_cfg.tcp_connect_wait=1;
  118. #endif /* TCP_CONNECT_WAIT */
  119. #endif /* TCP_ASYNC */
  120. #ifdef TCP_FD_CACHE
  121. tcp_default_cfg.fd_cache=1;
  122. #endif
  123. #ifdef HAVE_SO_KEEPALIVE
  124. tcp_default_cfg.keepalive=1;
  125. #endif
  126. /*
  127. #if defined HAVE_TCP_DEFER_ACCEPT || defined HAVE_TCP_ACCEPT_FILTER
  128. tcp_default_cfg.defer_accept=1;
  129. #endif
  130. */
  131. #ifdef HAVE_TCP_QUICKACK
  132. tcp_default_cfg.delayed_ack=1;
  133. #endif
  134. tcp_default_cfg.crlf_ping=1;
  135. tcp_default_cfg.accept_aliases=0; /* don't accept aliases by default */
  136. /* flags used for adding new aliases */
  137. tcp_default_cfg.alias_flags=TCP_ALIAS_FORCE_ADD;
  138. /* flags used for adding the default aliases of a new tcp connection */
  139. tcp_default_cfg.new_conn_alias_flags=TCP_ALIAS_REPLACE;
  140. tcp_default_cfg.rd_buf_size=DEFAULT_TCP_BUF_SIZE;
  141. tcp_default_cfg.wq_blk_size=DEFAULT_TCP_WBUF_SIZE;
  142. }
  143. #define W_OPT_NC(option) \
  144. if (tcp_default_cfg.option){\
  145. WARN("tcp_options: tcp_" #option \
  146. " cannot be enabled (recompile needed)\n"); \
  147. tcp_default_cfg.option=0; \
  148. }
  149. #define W_OPT_NS(option) \
  150. if (tcp_default_cfg.option){\
  151. WARN("tcp_options: tcp_" #option \
  152. " cannot be enabled (no OS support)\n"); \
  153. tcp_default_cfg.option=0; \
  154. }
  155. /* if *to<0 to=default_val, else if to>max_val to=max_val */
  156. static void fix_timeout(char* name, int* to, int default_val, unsigned max_val)
  157. {
  158. if (*to < 0) *to=default_val;
  159. else if ((unsigned)*to > max_val){
  160. WARN("%s: timeout too big (%u), the maximum value is %u\n",
  161. name, *to, max_val);
  162. *to=max_val;
  163. }
  164. }
  165. static int fix_connect_to(void* cfg_h, str* gname, str* name, void** val)
  166. {
  167. int v;
  168. v=(int)(long)*val;
  169. fix_timeout("tcp_connect_timeout", &v, DEFAULT_TCP_CONNECT_TIMEOUT,
  170. TICKS_TO_S(MAX_TCP_CON_LIFETIME));
  171. *val=(void*)(long)v;
  172. return 0;
  173. }
  174. static int fix_send_to(void* cfg_h, str* gname, str* name, void** val)
  175. {
  176. int v;
  177. v=S_TO_TICKS((int)(long)*val);
  178. fix_timeout("tcp_send_timeout", &v, S_TO_TICKS(DEFAULT_TCP_SEND_TIMEOUT),
  179. MAX_TCP_CON_LIFETIME);
  180. *val=(void*)(long)v;
  181. return 0;
  182. }
  183. static int fix_con_lt(void* cfg_h, str* gname, str* name, void** val)
  184. {
  185. int v;
  186. v=S_TO_TICKS((int)(long)*val);
  187. fix_timeout("tcp_connection_lifetime", &v,
  188. MAX_TCP_CON_LIFETIME, MAX_TCP_CON_LIFETIME);
  189. *val=(void*)(long)v;
  190. return 0;
  191. }
  192. static int fix_max_conns(void* cfg_h, str* gname, str* name, void** val)
  193. {
  194. int v;
  195. v=(int)(long)*val;
  196. if (v>tcp_max_connections){
  197. INFO("cannot override hard tcp_max_connections limit, please"
  198. " restart and increase tcp_max_connections in the cfg.\n");
  199. v=tcp_max_connections;
  200. }
  201. *val=(void*)(long)v;
  202. return 0;
  203. }
  204. /** fix *val according to the cfg entry "name".
  205. * (*val must be integer)
  206. * 1. check if *val is between name min..max and if not change it to
  207. * the corresp. value
  208. * 2. call fixup callback if defined in the cfg
  209. * @return 0 on success
  210. */
  211. static int tcp_cfg_def_fix(char* name, int* val)
  212. {
  213. cfg_def_t* c;
  214. str s;
  215. for (c=&tcp_cfg_def[0]; c->name; c++){
  216. if (strcmp(name, c->name)==0){
  217. /* found */
  218. if ((c->type & CFG_VAR_INT) && (c->min || c->max)){
  219. if (*val < c->min) *val=c->min;
  220. else if (*val > c->max) *val=c->max;
  221. if (c->on_change_cb){
  222. s.s=c->name;
  223. s.len=strlen(s.s);
  224. return c->on_change_cb(&tcp_default_cfg, NULL, &s, (void*)val);
  225. }
  226. }
  227. return 0;
  228. }
  229. }
  230. WARN("tcp config option \"%s\" not found\n", name);
  231. return -1; /* not found */
  232. }
  233. /* checks & warns if some tcp_option cannot be enabled */
  234. void tcp_options_check()
  235. {
  236. #ifndef TCP_FD_CACHE
  237. W_OPT_NC(defer_accept);
  238. #endif
  239. #ifndef TCP_ASYNC
  240. W_OPT_NC(async);
  241. W_OPT_NC(tcpconn_wq_max);
  242. W_OPT_NC(tcp_wq_max);
  243. #endif /* TCP_ASYNC */
  244. #ifndef TCP_CONNECT_WAIT
  245. W_OPT_NC(tcp_connect_wait);
  246. #endif /* TCP_CONNECT_WAIT */
  247. if (tcp_default_cfg.tcp_connect_wait && !tcp_default_cfg.async){
  248. tcp_default_cfg.tcp_connect_wait=0;
  249. }
  250. #if ! defined HAVE_TCP_DEFER_ACCEPT && ! defined HAVE_TCP_ACCEPT_FILTER
  251. W_OPT_NS(defer_accept);
  252. #endif
  253. #ifndef HAVE_TCP_SYNCNT
  254. W_OPT_NS(syncnt);
  255. #endif
  256. #ifndef HAVE_TCP_LINGER2
  257. W_OPT_NS(linger2);
  258. #endif
  259. #ifndef HAVE_TCP_KEEPINTVL
  260. W_OPT_NS(keepintvl);
  261. #endif
  262. #ifndef HAVE_TCP_KEEPIDLE
  263. W_OPT_NS(keepidle);
  264. #endif
  265. #ifndef HAVE_TCP_KEEPCNT
  266. W_OPT_NS(keepcnt);
  267. #endif
  268. if (tcp_default_cfg.keepintvl || tcp_default_cfg.keepidle ||
  269. tcp_default_cfg.keepcnt){
  270. tcp_default_cfg.keepalive=1; /* force on */
  271. }
  272. #ifndef HAVE_SO_KEEPALIVE
  273. W_OPT_NS(keepalive);
  274. #endif
  275. #ifndef HAVE_TCP_QUICKACK
  276. W_OPT_NS(delayed_ack);
  277. #endif
  278. /* fix various timeouts */
  279. fix_timeout("tcp_connect_timeout", &tcp_default_cfg.connect_timeout_s,
  280. DEFAULT_TCP_CONNECT_TIMEOUT,
  281. TICKS_TO_S(MAX_TCP_CON_LIFETIME));
  282. fix_timeout("tcp_send_timeout", &tcp_default_cfg.send_timeout,
  283. S_TO_TICKS(DEFAULT_TCP_SEND_TIMEOUT),
  284. MAX_TCP_CON_LIFETIME);
  285. fix_timeout("tcp_connection_lifetime", &tcp_default_cfg.con_lifetime,
  286. MAX_TCP_CON_LIFETIME, MAX_TCP_CON_LIFETIME);
  287. tcp_default_cfg.max_connections=tcp_max_connections;
  288. tcp_cfg_def_fix("rd_buf_size", (int*)&tcp_default_cfg.rd_buf_size);
  289. tcp_cfg_def_fix("wq_blk_size", (int*)&tcp_default_cfg.wq_blk_size);
  290. }
  291. void tcp_options_get(struct cfg_group_tcp* t)
  292. {
  293. *t=*(struct cfg_group_tcp*)tcp_cfg;
  294. }
  295. /** register tcp config into the configuration framework.
  296. * @return 0 on succes, -1 on error*/
  297. int tcp_register_cfg()
  298. {
  299. if (cfg_declare("tcp", tcp_cfg_def, &tcp_default_cfg, cfg_sizeof(tcp),
  300. &tcp_cfg))
  301. return -1;
  302. if (tcp_cfg==0){
  303. BUG("null tcp cfg");
  304. return -1;
  305. }
  306. return 0;
  307. }