Coverage Report

Created: 2024-02-25 06:34

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