Coverage Report

Created: 2026-10-17 06:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opensips/net/net_tcp.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2014-2015 OpenSIPS Project
3
 * Copyright (C) 2001-2003 FhG Fokus
4
 *
5
 * This file is part of opensips, a free SIP server.
6
 *
7
 * opensips is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 2 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * opensips is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20
 *
21
 *
22
 * history:
23
 * ---------
24
 *  2015-01-xx  created (razvanc)
25
 */
26
27
#include <sys/types.h>
28
#include <sys/socket.h>
29
#include <netinet/in.h>
30
#include <netinet/in_systm.h>
31
#include <netinet/ip.h>
32
#include <netinet/tcp.h>
33
#include <sys/uio.h>  /* writev*/
34
#include <netdb.h>
35
#include <stdlib.h> /*exit() */
36
#include <time.h>   /*time() */
37
#include <unistd.h>
38
#include <errno.h>
39
#include <string.h>
40
#include <pthread.h>
41
#include <stdint.h>
42
43
#include "../mem/mem.h"
44
#include "../mem/shm_mem.h"
45
#include "../globals.h"
46
#include "../locking.h"
47
#include "../socket_info.h"
48
#include "../ut.h"
49
#include "../pt.h"
50
#include "../pt_load.h"
51
#include "../daemonize.h"
52
#include "../status_report.h"
53
#include "../reactor.h"
54
#include "../timer.h"
55
#include "../ipc.h"
56
#include "../receive.h"
57
#include "../lib/cond.h"
58
#include "../cfg_reload.h"
59
60
#include "tcp_passfd.h"
61
#include "net_tcp_proc.h"
62
#include "net_tcp_report.h"
63
#include "net_tcp.h"
64
#include "tcp_common.h"
65
#include "tcp_conn.h"
66
#include "tcp_conn_profile.h"
67
#include "trans.h"
68
#include "net_tcp_dbg.h"
69
70
struct struct_hist_list *con_hist;
71
72
enum tcp_worker_state { STATE_INACTIVE=0, STATE_ACTIVE, STATE_DRAINING};
73
74
static int tcpconn_prepare_write(struct tcp_connection *tcpconn);
75
76
/* definition of a TCP worker - the array of these TCP workers is
77
 * mainly intended to be used by the TCP main, to keep track of the
78
 * workers, about their load and so. Nevertheless, since the addition
79
 * of the process auto-scaling, other processes may need access to this
80
 * data, thus it's relocation in SHM (versus initial PKG). For example,
81
 * the attendant process is the one forking new TCP workers (scaling up),
82
 * so it must be able to set the ENABLE state for the TCP worker (and being
83
 * (seen by the TCP main proc). Similar, when a TCP worker shuts down, it has
84
 * to mark itself as DISABLED and the TCP main must see that.
85
 * Again, 99% this array is intended for TCP Main ops, it is not lock
86
 * protected, so be very careful with any ops from other procs.
87
 */
88
struct tcp_worker {
89
  pid_t pid;
90
  int pt_idx;     /*!< Index in the main Process Table */
91
  enum tcp_worker_state state;
92
};
93
94
/* definition of a TCP partition */
95
struct tcp_partition {
96
  /*! \brief connection hash table (after ip&port), includes also aliases */
97
  struct tcp_conn_alias** tcpconn_aliases_hash;
98
  /*! \brief connection hash table (after connection id) */
99
  struct tcp_connection** tcpconn_id_hash;
100
  gen_lock_t* tcpconn_lock;
101
};
102
103
104
/* array of TCP workers - to be used only by TCP MAIN */
105
struct tcp_worker *tcp_workers=0;
106
static int tcp_dispatch_sock[2] = { -1, -1 };
107
108
/* unique for each connection, used for
109
 * quickly finding the corresponding connection for a reply */
110
static unsigned int* connection_id=0;
111
static int *tcp_main_proc_no = 0;
112
113
/* connections are created both by TCP main (on accept) and by any other
114
 * process (on connect), so the counter above must be incremented under lock -
115
 * otherwise concurrent creations may end up sharing the same connection ID */
116
static gen_lock_t* connection_id_lock=0;
117
118
/* array of TCP partitions */
119
static struct tcp_partition tcp_parts[TCP_PARTITION_SIZE];
120
121
/*!< current number of open connections */
122
static unsigned int *tcp_connections_no = 0;
123
static gen_lock_t *tcp_connections_lock = 0;
124
125
/*!< by default don't accept aliases */
126
int tcp_accept_aliases=0;
127
int tcp_connect_timeout=DEFAULT_TCP_CONNECT_TIMEOUT;
128
int tcp_con_lifetime=DEFAULT_TCP_CONNECTION_LIFETIME;
129
int tcp_socket_backlog=DEFAULT_TCP_SOCKET_BACKLOG;
130
/*!< by default choose the best method */
131
enum poll_types tcp_poll_method=0;
132
int tcp_max_connections=DEFAULT_TCP_MAX_CONNECTIONS;
133
/* the configured/starting number of TCP workers */
134
int tcp_workers_no = UDP_WORKERS_NO;
135
/* the maximum numbers of TCP workers */
136
int tcp_workers_max_no;
137
/* the name of the auto-scaling profile (optional) */
138
char* tcp_auto_scaling_profile = NULL;
139
/* Max number of seconds that we expect a full SIP message
140
 * to arrive in. Anything above will close the connection. */
141
int tcp_max_msg_time = TCP_CHILD_MAX_MSG_TIME;
142
#ifdef HAVE_SO_KEEPALIVE
143
    int tcp_keepalive = 1;
144
#else
145
    int tcp_keepalive = 0;
146
#endif
147
int tcp_keepcount = 0;
148
int tcp_keepidle = 0;
149
int tcp_keepinterval = 0;
150
151
/*!< should we allow opening a new TCP conn when sending data 
152
 * over UAC branches? - branch flag to be set in the SIP messages */
153
int tcp_no_new_conn_bflag = 0;
154
/*!< should we allow opening a new TCP conn when sending data 
155
 * back to UAS (replies)? - msg flag to be set in the SIP messages */
156
int tcp_no_new_conn_rplflag = 0;
157
/*!< should a new TCP conn be open if needed? - variable used to used for
158
 * signalizing between SIP layer (branch flag) and TCP layer (tcp_send func)*/
159
int tcp_no_new_conn = 0;
160
int tcp_threads = 0;
161
162
/* if the TCP net layer is on or off (if no TCP based protos are loaded) */
163
static int tcp_disabled = 1;
164
165
/* is the process TCP MAIN ? */
166
int is_tcp_main = 0;
167
168
/* the ID of the TCP conn used for the last send operation in the
169
 * current process - attention, this is a really ugly HACK here */
170
unsigned int last_outgoing_tcp_id = 0;
171
172
static struct scaling_profile *s_profile = NULL;
173
174
/****************************** helper functions *****************************/
175
extern void handle_sigs(void);
176
177
static inline int init_sock_keepalive(int s, const struct tcp_conn_profile *prof)
178
0
{
179
0
  int ka;
180
0
#if defined(HAVE_TCP_KEEPINTVL) || defined(HAVE_TCP_KEEPIDLE) || defined(HAVE_TCP_KEEPCNT)
181
0
  int optval;
182
0
#endif
183
184
0
  if (prof->keepinterval || prof->keepidle || prof->keepcount)
185
0
    ka = 1; /* force on */
186
0
  else
187
0
    ka = prof->keepalive;
188
189
0
#ifdef HAVE_SO_KEEPALIVE
190
0
  if (setsockopt(s,SOL_SOCKET,SO_KEEPALIVE,&ka,sizeof(ka))<0){
191
0
    LM_WARN("setsockopt failed to enable SO_KEEPALIVE: %s\n",
192
0
      strerror(errno));
193
0
    return -1;
194
0
  }
195
0
  LM_DBG("TCP keepalive enabled on socket %d\n",s);
196
0
#endif
197
0
#ifdef HAVE_TCP_KEEPINTVL
198
0
  if ((optval = prof->keepinterval)) {
199
0
    if (setsockopt(s,IPPROTO_TCP,TCP_KEEPINTVL,&optval,sizeof(optval))<0){
200
0
      LM_WARN("setsockopt failed to set keepalive probes interval: %s\n",
201
0
        strerror(errno));
202
0
    }
203
0
  }
204
0
#endif
205
0
#ifdef HAVE_TCP_KEEPIDLE
206
0
  if ((optval = prof->keepidle)) {
207
0
    if (setsockopt(s,IPPROTO_TCP,TCP_KEEPIDLE,&optval,sizeof(optval))<0){
208
0
      LM_WARN("setsockopt failed to set keepalive idle interval: %s\n",
209
0
        strerror(errno));
210
0
    }
211
0
  }
212
0
#endif
213
0
#ifdef HAVE_TCP_KEEPCNT
214
0
  if ((optval = prof->keepcount)) {
215
0
    if (setsockopt(s,IPPROTO_TCP,TCP_KEEPCNT,&optval,sizeof(optval))<0){
216
0
      LM_WARN("setsockopt failed to set maximum keepalive count: %s\n",
217
0
        strerror(errno));
218
0
    }
219
0
  }
220
0
#endif
221
0
  return 0;
222
0
}
223
224
static inline void set_sock_reuseport(int s)
225
0
{
226
0
  int yes = 1;
227
228
0
  if (setsockopt(s,SOL_SOCKET,SO_REUSEPORT,&yes,sizeof(yes))<0){
229
0
    LM_WARN("setsockopt failed to set SO_REUSEPORT: %s\n",
230
0
      strerror(errno));
231
0
  }
232
0
  if (setsockopt(s,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(yes))<0){
233
0
    LM_WARN("setsockopt failed to set SO_REUSEADDR: %s\n",
234
0
      strerror(errno));
235
0
  }
236
0
}
237
238
/*! \brief Set all socket/fd options:  disable nagle, tos lowdelay,
239
 * non-blocking
240
 * \return -1 on error */
241
int tcp_init_sock_opt(int s, const struct tcp_conn_profile *prof, enum si_flags socketflags, int sock_tos)
242
0
{
243
0
  int flags;
244
0
  int optval;
245
246
0
#ifdef DISABLE_NAGLE
247
0
  flags=1;
248
0
  if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &flags, sizeof(flags)) < 0){
249
0
    LM_WARN("could not disable Nagle: %s\n", strerror(errno));
250
0
  }
251
0
#endif
252
  /* tos*/
253
0
  optval = (sock_tos > 0) ? sock_tos : tos;
254
0
  if (optval > 0) {
255
0
    if (setsockopt(s, IPPROTO_IP, IP_TOS, (void*)&optval,sizeof(optval)) ==-1){
256
0
      LM_WARN("setsockopt tos: %s\n",  strerror(errno));
257
      /* continue since this is not critical */
258
0
    }
259
0
  }
260
261
0
  if (probe_max_sock_buff(s,1,MAX_SEND_BUFFER_SIZE,BUFFER_INCREMENT)) {
262
0
    LM_WARN("setsockopt tcp snd buff: %s\n", strerror(errno));
263
    /* continue since this is not critical */
264
0
  }
265
266
0
  init_sock_keepalive(s, prof);
267
0
  if (socketflags & SI_REUSEPORT)
268
0
    set_sock_reuseport(s);
269
270
  /* non-blocking */
271
0
  flags=fcntl(s, F_GETFL);
272
0
  if (flags==-1){
273
0
    LM_ERR("fcntl failed: (%d) %s\n", errno, strerror(errno));
274
0
    goto error;
275
0
  }
276
0
  if (fcntl(s, F_SETFL, flags|O_NONBLOCK)==-1){
277
0
    LM_ERR("set non-blocking failed: (%d) %s\n", errno, strerror(errno));
278
0
    goto error;
279
0
  }
280
0
  return 0;
281
0
error:
282
0
  return -1;
283
0
}
284
285
struct tcp_ipc_payload {
286
  struct receive_info rcv;
287
  struct tcp_connection *conn;
288
  int msg_len;
289
  int data_len;
290
  char msg_buf[0];
291
};
292
293
int tcp_dispatch_msg(char *msg, int len,
294
    struct receive_info *rcv, const void *data, int data_len)
295
0
{
296
0
  struct tcp_ipc_payload *payload;
297
0
  struct tcp_connection *conn = NULL;
298
0
  unsigned int alloc_len;
299
0
  int n;
300
0
  uintptr_t payload_ptr;
301
302
0
  if (len < 0) {
303
0
    LM_BUG("negative TCP message length: %d\n", len);
304
0
    return -1;
305
0
  }
306
0
  if (len && !msg) {
307
0
    LM_BUG("NULL TCP message buffer with non-zero length: %d\n", len);
308
0
    return -1;
309
0
  }
310
0
  if (data_len < 0) {
311
0
    LM_BUG("negative TCP dispatch data length: %d\n", data_len);
312
0
    return -1;
313
0
  }
314
0
  if (data_len && !data) {
315
0
    LM_BUG("missing TCP dispatch data buffer for %d bytes\n", data_len);
316
0
    return -1;
317
0
  }
318
319
0
  alloc_len = sizeof(*payload) + len + 1 + data_len;
320
0
  payload = shm_malloc(alloc_len);
321
0
  if (!payload) {
322
0
    LM_ERR("oom while allocating TCP IPC payload (%u bytes)\n", alloc_len);
323
0
    return -1;
324
0
  }
325
326
0
  memcpy(&payload->rcv, rcv, sizeof(payload->rcv));
327
0
  payload->conn = NULL;
328
0
  payload->msg_len = len;
329
0
  payload->data_len = data_len;
330
0
  memcpy(payload->msg_buf, msg, len);
331
0
  payload->msg_buf[len] = '\0';
332
0
  if (data_len)
333
0
    memcpy(payload->msg_buf + len + 1, data, data_len);
334
335
0
  if (rcv->proto_reserved1 &&
336
0
      tcp_conn_get(rcv->proto_reserved1, NULL, 0, PROTO_NONE,
337
0
        NULL, &conn, NULL) > 0) {
338
0
    payload->conn = conn;
339
0
  }
340
341
0
  payload_ptr = (uintptr_t)payload;
342
0
  n = send(tcp_dispatch_sock[1], &payload_ptr, sizeof(payload_ptr), 0);
343
0
  if (n != (int)sizeof(payload_ptr)) {
344
0
    LM_ERR("failed to dispatch TCP message to worker socket: %s\n",
345
0
      (n < 0) ? strerror(errno) : "short write");
346
0
    if (payload->conn)
347
0
      tcpconn_put(payload->conn);
348
0
    shm_free(payload);
349
0
    return -1;
350
0
  }
351
352
0
  return 0;
353
0
}
354
355
enum tcp_job_op {
356
  TCP_READ_JOB = 1,
357
  TCP_WRITE_JOB = 2,
358
  TCP_RUN_JOB = 3,
359
};
360
361
struct tcp_job {
362
  struct tcp_connection *conn;
363
  int op;
364
  tcp_thread_job_f run;
365
  void *data;
366
  long resp;
367
  int ret;
368
  struct tcp_job *next;
369
};
370
371
static struct tcp_pool {
372
  pthread_t *threads;
373
  int threads_no;
374
  int stop;
375
  struct tcp_job *task_head;
376
  struct tcp_job *task_tail;
377
378
  pthread_mutex_t done_lock;
379
  struct tcp_job *done_head;
380
  struct tcp_job *done_tail;
381
382
  int notify_pipe[2];
383
} tcp_pool = {
384
  .threads = NULL,
385
  .threads_no = 0,
386
  .stop = 0,
387
  .task_head = NULL,
388
  .task_tail = NULL,
389
  .done_lock = PTHREAD_MUTEX_INITIALIZER,
390
  .done_head = NULL,
391
  .done_tail = NULL,
392
  .notify_pipe = {-1, -1},
393
};
394
395
struct tcp_shared_write_queue {
396
  gen_cond_t cond;
397
  struct tcp_connection *head;
398
  struct tcp_connection *tail;
399
};
400
401
static struct tcp_shared_write_queue *tcp_write_queue = NULL;
402
403
static inline int tcp_threads_active(void)
404
0
{
405
0
  return tcp_pool.threads_no > 0;
406
0
}
407
408
int tcp_write_in_main(void)
409
0
{
410
  /* This is a process-independent policy: TCP writes are handled by the
411
   * dedicated TCP main process, regardless of the caller process. */
412
0
  return !tcp_disabled;
413
0
}
414
415
416
417
/********************** TCP conn management functions ************************/
418
419
/* initializes an already defined TCP listener */
420
int tcp_init_listener(struct socket_info *si)
421
0
{
422
0
  union sockaddr_union* addr = &si->su;
423
424
0
  if (init_su(addr, &si->address, si->port_no)<0){
425
0
    LM_ERR("could no init sockaddr_union\n");
426
0
    return -1;
427
0
  }
428
429
0
  return 0;
430
0
}
431
432
/* binding an defined TCP listener */
433
int tcp_bind_listener(struct socket_info *si)
434
0
{
435
0
  union sockaddr_union* addr;
436
0
  int optval;
437
0
#ifdef DISABLE_NAGLE
438
0
  int flag;
439
0
#endif
440
441
0
  addr = &si->su;
442
0
  si->socket = socket(AF2PF(addr->s.sa_family), SOCK_STREAM, 0);
443
0
  if (si->socket==-1){
444
0
    LM_ERR("socket failed with [%s]\n", strerror(errno));
445
0
    goto error;
446
0
  }
447
0
#ifdef DISABLE_NAGLE
448
0
  flag=1;
449
0
  if (setsockopt(si->socket, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag)) < 0){
450
0
    LM_ERR("could not disable Nagle: %s\n",strerror(errno));
451
0
  }
452
0
#endif
453
454
0
#if  !defined(TCP_DONT_REUSEADDR)
455
  /* Stevens, "Network Programming", Section 7.5, "Generic Socket
456
   * Options": "...server started,..a child continues..on existing
457
   * connection..listening server is restarted...call to bind fails
458
   * ... ALL TCP servers should specify the SO_REUSEADDRE option
459
   * to allow the server to be restarted in this situation
460
   */
461
0
  optval=1;
462
0
  if (setsockopt(si->socket, SOL_SOCKET, SO_REUSEADDR,
463
0
  (void*)&optval, sizeof(optval))==-1) {
464
0
    LM_ERR("setsockopt failed with [%s]\n", strerror(errno));
465
0
    goto error;
466
0
  }
467
0
#endif
468
  /* tos */
469
0
  optval = (si->tos > 0) ? si->tos : tos;
470
0
  if (optval > 0) {
471
0
    if (setsockopt(si->socket, IPPROTO_IP, IP_TOS, (void*)&optval,
472
0
    sizeof(optval)) ==-1){
473
0
      LM_WARN("setsockopt tos: %s\n", strerror(errno));
474
      /* continue since this is not critical */
475
0
    }
476
0
  }
477
478
0
  if (probe_max_sock_buff(si->socket,1,MAX_SEND_BUFFER_SIZE,
479
0
  BUFFER_INCREMENT)) {
480
0
    LM_WARN("setsockopt tcp snd buff: %s\n",strerror(errno));
481
    /* continue since this is not critical */
482
0
  }
483
484
0
  init_sock_keepalive(si->socket, &tcp_con_df_profile);
485
0
  if (si->flags & SI_REUSEPORT)
486
0
    set_sock_reuseport(si->socket);
487
0
  if (bind(si->socket, &addr->s, sockaddru_len(*addr))==-1){
488
0
    LM_ERR("bind(%x, %p, %d) on %s:%d : %s\n",
489
0
        si->socket, &addr->s,
490
0
        (unsigned)sockaddru_len(*addr),
491
0
        si->address_str.s,
492
0
        si->port_no,
493
0
        strerror(errno));
494
0
    goto error;
495
0
  }
496
0
  if (listen(si->socket, tcp_socket_backlog)==-1){
497
0
    LM_ERR("listen(%x, %p, %d) on %s: %s\n",
498
0
        si->socket, &addr->s,
499
0
        (unsigned)sockaddru_len(*addr),
500
0
        si->address_str.s,
501
0
        strerror(errno));
502
0
    goto error;
503
0
  }
504
505
0
  return 0;
506
0
error:
507
0
  if (si->socket!=-1){
508
0
    close(si->socket);
509
0
    si->socket=-1;
510
0
  }
511
0
  return -1;
512
0
}
513
514
515
/*! \brief finds a connection, if id=0 return NULL
516
 * \note WARNING: unprotected (locks) use tcpconn_get unless you really
517
 * know what you are doing */
518
static struct tcp_connection* _tcpconn_find(unsigned int id)
519
0
{
520
0
  struct tcp_connection *c;
521
0
  unsigned hash;
522
523
0
  if (id){
524
0
    hash=tcp_id_hash(id);
525
0
    for (c=TCP_PART(id).tcpconn_id_hash[hash]; c; c=c->id_next){
526
#ifdef EXTRA_DEBUG
527
      LM_DBG("c=%p, c->id=%u, port=%d\n",c, c->id, c->rcv.src_port);
528
      print_ip("ip=", &c->rcv.src_ip, "\n");
529
#endif
530
0
      if ((id==c->id) && c->state!=S_CONN_BAD &&
531
0
          !(c->flags & F_CONN_FORCE_CLOSED))
532
0
        return c;
533
0
    }
534
0
  }
535
0
  return 0;
536
0
}
537
538
539
/* returns the correlation ID of a TCP connection */
540
int tcp_get_correlation_id( unsigned int id, unsigned long long *cid)
541
0
{
542
0
  struct tcp_connection* c;
543
544
0
  TCPCONN_LOCK(id);
545
0
  if ( (c=_tcpconn_find(id))!=NULL ) {
546
0
    *cid = c->cid;
547
0
    TCPCONN_UNLOCK(id);
548
0
    return 0;
549
0
  }
550
0
  *cid = 0;
551
0
  TCPCONN_UNLOCK(id);
552
0
  return -1;
553
0
}
554
555
/* returns the correlation ID of a TCP connection */
556
int tcp_get_rcv( unsigned int id, struct receive_info *ri)
557
0
{
558
0
  struct tcp_connection* c;
559
560
0
  TCPCONN_LOCK(id);
561
0
  if ( (c=_tcpconn_find(id))!=NULL ) {
562
0
    memcpy(ri, &c->rcv, sizeof *ri);
563
0
    TCPCONN_UNLOCK(id);
564
0
    return 0;
565
0
  }
566
0
  TCPCONN_UNLOCK(id);
567
0
  return -1;
568
0
}
569
570
int tcp_get_main_proc_no(void)
571
0
{
572
0
  return tcp_main_proc_no ? *tcp_main_proc_no : -1;
573
0
}
574
575
576
/*! \brief _tcpconn_find with locks and acquire a shared connection reference */
577
int tcp_conn_get(unsigned int id, struct ip_addr* ip, int port,
578
    enum sip_protos proto, void *proto_extra_id,
579
    struct tcp_connection** conn, const struct socket_info* send_sock)
580
0
{
581
0
  struct tcp_connection* c;
582
0
  struct tcp_conn_alias* a;
583
0
  unsigned hash;
584
0
  unsigned int part;
585
586
  /* TCP may already be destroyed during late shutdown callbacks. */
587
0
  if (!tcp_parts[0].tcpconn_lock || !tcp_parts[0].tcpconn_id_hash ||
588
0
      !tcp_parts[0].tcpconn_aliases_hash) {
589
0
    *conn = NULL;
590
0
    return -1;
591
0
  }
592
593
0
  if (id) {
594
0
    part = id;
595
0
    TCPCONN_LOCK(part);
596
0
    if ( (c=_tcpconn_find(part))!=NULL )
597
0
      goto found;
598
0
    TCPCONN_UNLOCK(part);
599
0
  }
600
601
  /* continue search based on IP address + port + transport */
602
#ifdef EXTRA_DEBUG
603
  LM_DBG("%d  port %u\n",id, port);
604
  if (ip) print_ip("tcpconn_find: ip ", ip, "\n");
605
#endif
606
0
  if (ip){
607
0
    hash=tcp_addr_hash(ip, port);
608
0
    for( part=0 ; part<TCP_PARTITION_SIZE ; part++ ) {
609
0
      TCPCONN_LOCK(part);
610
0
      for (a=TCP_PART(part).tcpconn_aliases_hash[hash]; a; a=a->next) {
611
#ifdef EXTRA_DEBUG
612
        LM_DBG("a=%p, c=%p, c->id=%u, alias port= %d port=%d\n",
613
          a, a->parent, a->parent->id, a->port,
614
          a->parent->rcv.src_port);
615
        print_ip("ip=",&a->parent->rcv.src_ip,"\n");
616
        if (send_sock && a->parent->rcv.bind_address) {
617
          print_ip("requested send_sock ip=", &send_sock->address,"\n");
618
          print_ip("found send_sock ip=", &a->parent->rcv.bind_address->address,"\n");
619
        }
620
#endif
621
0
        c = a->parent;
622
0
        if (c->state != S_CONN_BAD &&
623
0
            !(c->flags & F_CONN_FORCE_CLOSED) &&
624
0
            ((c->flags & F_CONN_INIT) ||
625
0
             (c->state == S_CONN_CONNECTING && c->fd == -1)) &&
626
0
            (send_sock==NULL || send_sock == a->parent->rcv.bind_address) &&
627
0
            port == a->port &&
628
0
            proto == c->type &&
629
0
            ip_addr_cmp(ip, &c->rcv.src_ip) &&
630
0
            (proto_extra_id == NULL ||
631
0
             ((c->flags & F_CONN_INIT) &&
632
0
              (protos[proto].net.stream.conn.match == NULL ||
633
0
               protos[proto].net.stream.conn.match(c, proto_extra_id)))) )
634
0
            goto found;
635
0
        }
636
0
      TCPCONN_UNLOCK(part);
637
0
    }
638
0
  }
639
640
  /* not found */
641
0
  *conn = NULL;
642
0
  return 0;
643
644
0
found:
645
0
  c->refcnt++;
646
0
  TCPCONN_UNLOCK(part);
647
0
  sh_log(c->hist, TCP_REF, "tcp_conn_get, (%d)", c->refcnt);
648
649
0
  LM_DBG("con found in state %d\n",c->state);
650
651
0
  *conn = c;
652
0
  return 1;
653
0
}
654
655
656
/* used to tune the tcp_connection attributes - not to be used inside the
657
   network layer, but onlu from the above layer (otherwise we may end up
658
   in strange deadlocks!) */
659
int tcp_conn_fcntl(struct receive_info *rcv, int attr, void *value)
660
0
{
661
0
  struct tcp_connection *con;
662
663
0
  switch (attr) {
664
0
  case DST_FCNTL_SET_LIFETIME:
665
    /* set connection timeout */
666
0
    TCPCONN_LOCK(rcv->proto_reserved1);
667
0
    con =_tcpconn_find(rcv->proto_reserved1);
668
0
    if (!con) {
669
0
      LM_ERR("Strange, tcp conn not found (id=%u)\n",
670
0
        rcv->proto_reserved1);
671
0
    } else {
672
0
      tcp_conn_set_lifetime( con, (int)(long)(value));
673
0
    }
674
0
    TCPCONN_UNLOCK(rcv->proto_reserved1);
675
0
    return 0;
676
0
  default:
677
0
    LM_ERR("unsupported operation %d on conn\n",attr);
678
0
    return -1;
679
0
  }
680
0
  return -1;
681
0
}
682
683
684
static struct tcp_connection* tcpconn_add(struct tcp_connection *c)
685
0
{
686
0
  unsigned hash;
687
688
0
  if (c){
689
0
    TCPCONN_LOCK(c->id);
690
    /* add it at the beginning of the list*/
691
0
    hash=tcp_id_hash(c->id);
692
0
    c->id_hash=hash;
693
0
    tcpconn_listadd(TCP_PART(c->id).tcpconn_id_hash[hash], c, id_next,
694
0
      id_prev);
695
696
0
    hash=tcp_addr_hash(&c->rcv.src_ip, c->rcv.src_port);
697
    /* set the first alias */
698
0
    c->con_aliases[0].port=c->rcv.src_port;
699
0
    c->con_aliases[0].hash=hash;
700
0
    c->con_aliases[0].parent=c;
701
0
    tcpconn_listadd(TCP_PART(c->id).tcpconn_aliases_hash[hash],
702
0
      &c->con_aliases[0], next, prev);
703
0
    c->aliases++;
704
0
    c->flags |= F_CONN_HASHED;
705
0
    TCPCONN_UNLOCK(c->id);
706
0
    LM_DBG("hashes: %d, %d\n", hash, c->id_hash);
707
0
    return c;
708
0
  }else{
709
0
    LM_CRIT("null connection pointer\n");
710
0
    return 0;
711
0
  }
712
0
}
713
714
static str e_tcp_src_ip = str_init("src_ip");
715
static str e_tcp_src_port = str_init("src_port");
716
static str e_tcp_dst_ip = str_init("dst_ip");
717
static str e_tcp_dst_port = str_init("dst_port");
718
static str e_tcp_c_proto = str_init("proto");
719
720
static void tcp_disconnect_event_raise(struct tcp_connection* c)
721
0
{
722
0
  evi_params_p list = 0;
723
0
  str src_ip,dst_ip, proto;
724
0
  int src_port,dst_port;
725
0
  char src_ip_buf[IP_ADDR_MAX_STR_SIZE],dst_ip_buf[IP_ADDR_MAX_STR_SIZE];
726
727
  // event has to be triggered - check for subscribers
728
0
  if (!evi_probe_event(EVI_TCP_DISCONNECT)) {
729
0
    goto end;
730
0
  }
731
732
0
  if (!(list = evi_get_params()))
733
0
    goto end;
734
735
0
  src_ip.s = ip_addr2a( &c->rcv.src_ip );
736
0
  memcpy(src_ip_buf,src_ip.s,IP_ADDR_MAX_STR_SIZE);
737
0
  src_ip.s = src_ip_buf;
738
0
  src_ip.len = strlen(src_ip.s);
739
740
0
  if (evi_param_add_str(list, &e_tcp_src_ip, &src_ip)) {
741
0
    LM_ERR("unable to add parameter\n");
742
0
    goto end;
743
0
  }
744
745
0
  src_port = c->rcv.src_port;
746
747
0
  if (evi_param_add_int(list, &e_tcp_src_port, &src_port)) {
748
0
    LM_ERR("unable to add parameter\n");
749
0
    goto end;
750
0
  }
751
752
0
  dst_ip.s = ip_addr2a( &c->rcv.dst_ip );
753
0
  memcpy(dst_ip_buf,dst_ip.s,IP_ADDR_MAX_STR_SIZE);
754
0
  dst_ip.s = dst_ip_buf;
755
0
  dst_ip.len = strlen(dst_ip.s);
756
757
0
  if (evi_param_add_str(list, &e_tcp_dst_ip, &dst_ip)) {
758
0
    LM_ERR("unable to add parameter\n");
759
0
    goto end;
760
0
  }
761
762
0
  dst_port = c->rcv.dst_port;
763
764
0
  if (evi_param_add_int(list, &e_tcp_dst_port, &dst_port)) {
765
0
    LM_ERR("unable to add parameter\n");
766
0
    goto end;
767
0
  }
768
769
0
  proto.s = protos[c->rcv.proto].name;
770
0
  proto.len = strlen(proto.s);
771
772
0
  if (evi_param_add_str(list, &e_tcp_c_proto, &proto)) {
773
0
    LM_ERR("unable to add parameter\n");
774
0
    goto end;
775
0
  }
776
777
0
  if (is_tcp_main) {
778
0
    if (evi_dispatch_event(EVI_TCP_DISCONNECT, list)) {
779
0
      LM_ERR("unable to dispatch tcp disconnect event\n");
780
0
    }
781
0
  } else {
782
0
    if (evi_raise_event(EVI_TCP_DISCONNECT, list)) {
783
0
      LM_ERR("unable to send tcp disconnect event\n");
784
0
    }
785
0
  }
786
0
  list = 0;
787
788
0
end:
789
0
  if (list)
790
0
    evi_free_params(list);
791
0
}
792
793
/* convenience macro to aid in shm_free() debugging */
794
#define _tcpconn_rm(c, ne) \
795
0
  do {\
796
0
    __tcpconn_rm(c, ne);\
797
0
    shm_free(c);\
798
0
  } while (0)
799
800
struct tcp_req *tcp_conn_get_req(struct tcp_connection *c)
801
0
{
802
0
  if (!c)
803
0
    return NULL;
804
805
0
  if (c->con_req)
806
0
    return c->con_req;
807
808
0
  c->con_req = thread_malloc(sizeof(*c->con_req));
809
0
  if (!c->con_req) {
810
0
    LM_ERR("failed to allocate TCP request buffer for connection %u\n",
811
0
      c->id);
812
0
    return NULL;
813
0
  }
814
0
  memset(c->con_req, 0, sizeof(*c->con_req));
815
816
0
  return c->con_req;
817
0
}
818
819
void tcp_conn_destroy_req(struct tcp_connection *c)
820
0
{
821
0
  if (!c || !c->con_req)
822
0
    return;
823
824
0
  thread_free(c->con_req);
825
0
  c->con_req = NULL;
826
0
}
827
828
/*! \brief unsafe tcpconn_rm version (nolocks) */
829
static void __tcpconn_rm(struct tcp_connection* c, int no_event)
830
0
{
831
0
  int r;
832
833
0
  if (c->flags & F_CONN_HASHED) {
834
0
    tcpconn_listrm(TCP_PART(c->id).tcpconn_id_hash[c->id_hash], c,
835
0
      id_next, id_prev);
836
    /* remove all the aliases */
837
0
    for (r=0; r<c->aliases; r++)
838
0
      tcpconn_listrm(TCP_PART(c->id).tcpconn_aliases_hash[
839
0
        c->con_aliases[r].hash], &c->con_aliases[r], next, prev);
840
0
    c->flags &= ~F_CONN_HASHED;
841
0
  }
842
0
  lock_destroy(&c->write_lock);
843
844
0
  if (c->async) {
845
0
    for (r = 0; r<c->async->pending; r++)
846
0
      shm_free(c->async->chunks[r]);
847
0
    shm_free(c->async);
848
0
    c->async = NULL;
849
0
  }
850
851
0
  lock_get(tcp_connections_lock);
852
0
  (*tcp_connections_no)--;
853
0
  lock_release(tcp_connections_lock);
854
855
  /* Only TCP main has valid process-private connection state. */
856
0
  if (is_tcp_main) {
857
0
    if (c->proto_req)
858
0
      thread_free(c->proto_req);
859
0
    c->proto_req = NULL;
860
0
    tcp_conn_destroy_req(c);
861
862
0
    if (protos[c->type].net.stream.conn.clean)
863
0
      protos[c->type].net.stream.conn.clean(c);
864
0
  }
865
866
0
  if (!no_event) tcp_disconnect_event_raise(c);
867
868
#ifdef DBG_TCPCON
869
  sh_log(c->hist, TCP_DESTROY, "type=%d", c->type);
870
  sh_unref(c->hist);
871
  c->hist = NULL;
872
#endif
873
874
  /* shm_free(c); -- freed by _tcpconn_rm() */
875
0
}
876
877
/*! \brief add port as an alias for the "id" connection
878
 * \return 0 on success,-1 on failure */
879
int tcpconn_add_alias(struct sip_msg *msg, unsigned int id, int port, int proto)
880
0
{
881
0
  struct tcp_connection* c;
882
0
  unsigned hash;
883
0
  struct tcp_conn_alias* a;
884
885
0
  a=0;
886
  /* fix the port */
887
0
  port=port ? port : protos[proto].default_port ;
888
0
  TCPCONN_LOCK(id);
889
  /* check if alias already exists */
890
0
  c=_tcpconn_find(id);
891
0
  if (c) {
892
0
    if (msg && !(c->profile.alias_mode == TCP_ALIAS_ALWAYS
893
0
                   || (c->profile.alias_mode == TCP_ALIAS_RFC_5923
894
0
                       && msg->via1->alias))) {
895
0
      LM_DBG("refusing to add alias (alias_mode: %u, via 'alias': %u)\n",
896
0
              c->profile.alias_mode, !!msg->via1->alias);
897
0
      TCPCONN_UNLOCK(id);
898
0
      return 0;
899
0
    }
900
901
0
    hash=tcp_addr_hash(&c->rcv.src_ip, port);
902
    /* search the aliases for an already existing one */
903
0
    for (a=TCP_PART(id).tcpconn_aliases_hash[hash]; a; a=a->next) {
904
0
      if (a->parent->state != S_CONN_BAD &&
905
0
          port == a->port &&
906
0
          proto == a->parent->type &&
907
0
          ip_addr_cmp(&c->rcv.src_ip, &a->parent->rcv.src_ip)) {
908
        /* found */
909
0
        if (a->parent!=c) goto error_sec;
910
0
        else goto ok;
911
0
      }
912
0
    }
913
0
    if (c->aliases>=TCP_CON_MAX_ALIASES) goto error_aliases;
914
0
    c->con_aliases[c->aliases].parent=c;
915
0
    c->con_aliases[c->aliases].port=port;
916
0
    c->con_aliases[c->aliases].hash=hash;
917
0
    tcpconn_listadd(TCP_PART(id).tcpconn_aliases_hash[hash],
918
0
                &c->con_aliases[c->aliases], next, prev);
919
0
    c->aliases++;
920
0
  }else goto error_not_found;
921
0
ok:
922
0
  TCPCONN_UNLOCK(id);
923
#ifdef EXTRA_DEBUG
924
  if (a) LM_DBG("alias already present\n");
925
  else   LM_DBG("alias port %d for hash %d, id %u\n", port, hash, id);
926
#endif
927
0
  return 0;
928
0
error_aliases:
929
0
  TCPCONN_UNLOCK(id);
930
0
  LM_ERR("too many aliases for connection %p (%u)\n", c, id);
931
0
  return -1;
932
0
error_not_found:
933
0
  TCPCONN_UNLOCK(id);
934
0
  LM_ERR("no connection found for id %u\n",id);
935
0
  return -1;
936
0
error_sec:
937
0
  LM_WARN("possible port hijack attempt\n");
938
0
  LM_WARN("alias already present and points to another connection "
939
0
      "(%d : %d and %u : %d)\n", a->parent->id,  port, id, port);
940
0
  TCPCONN_UNLOCK(id);
941
0
  return -1;
942
0
}
943
944
945
static void tcpconn_put_rpc(int pid, void *param)
946
0
{
947
0
  tcpconn_put(param);
948
0
}
949
950
951
void tcpconn_put(struct tcp_connection* c)
952
0
{
953
0
  int destroy = 0;
954
0
  int release_in_main = 0;
955
0
  int tcp_main_proc;
956
957
0
  TCPCONN_LOCK(c->id);
958
0
  if ((c->flags & F_CONN_HASHED) == 0) {
959
0
    if (!is_tcp_main && c->refcnt == 1) {
960
      /* Keep the last reference until TCP main accepts ownership. */
961
0
      release_in_main = 1;
962
0
    } else {
963
0
      c->refcnt--;
964
0
      if (c->refcnt == 0)
965
0
        destroy = 1;
966
0
    }
967
0
  } else {
968
    /* Hashed connections are destroyed by TCP main lifetime handling. */
969
0
    c->refcnt--;
970
0
  }
971
0
  TCPCONN_UNLOCK(c->id);
972
973
0
  if (release_in_main) {
974
0
    tcp_main_proc = tcp_get_main_proc_no();
975
0
    if (tcp_main_proc < 0 ||
976
0
        ipc_send_rpc(tcp_main_proc, tcpconn_put_rpc, c) < 0)
977
0
      LM_ERR("failed to release connection %p (%u) in TCP main; "
978
0
        "leaving its final reference intact\n", c, c->id);
979
0
  } else if (destroy) {
980
0
    _tcpconn_rm(c, 1);
981
0
  }
982
0
}
983
984
985
static inline void tcpconn_ref(struct tcp_connection* c)
986
0
{
987
0
  TCPCONN_LOCK(c->id);
988
0
  c->refcnt++;
989
0
  TCPCONN_UNLOCK(c->id);
990
0
}
991
992
993
static inline unsigned int tcpconn_next_id(void)
994
0
{
995
0
  unsigned int id;
996
997
0
  lock_get(connection_id_lock);
998
0
  id = (*connection_id)++;
999
0
  lock_release(connection_id_lock);
1000
1001
0
  return id;
1002
0
}
1003
1004
1005
static struct tcp_connection* tcpconn_new(int sock, const union sockaddr_union* su,
1006
                    const struct socket_info* si, const struct tcp_conn_profile *prof,
1007
                    int state, int flags)
1008
0
{
1009
0
  struct tcp_connection *c;
1010
0
  union sockaddr_union local_su;
1011
0
  unsigned int su_size;
1012
0
  int counted = 0;
1013
1014
0
  lock_get(tcp_connections_lock);
1015
0
  if (*tcp_connections_no >= (unsigned int)tcp_max_connections) {
1016
0
    lock_release(tcp_connections_lock);
1017
0
    LM_ERR("maximum number of connections exceeded: %u/%d\n",
1018
0
      *tcp_connections_no, tcp_max_connections);
1019
0
    return 0;
1020
0
  }
1021
0
  (*tcp_connections_no)++;
1022
0
  lock_release(tcp_connections_lock);
1023
0
  counted = 1;
1024
1025
0
  c=(struct tcp_connection*)shm_malloc(sizeof(struct tcp_connection));
1026
0
  if (c==0){
1027
0
    LM_ERR("shared memory allocation failure\n");
1028
0
    goto error_count;
1029
0
  }
1030
0
  memset(c, 0, sizeof(struct tcp_connection)); /* zero init */
1031
0
  c->fd=sock;
1032
0
  if (lock_init(&c->write_lock)==0){
1033
0
    LM_ERR("init lock failed\n");
1034
0
    goto error0;
1035
0
  }
1036
1037
0
  c->rcv.src_su=*su;
1038
1039
0
  c->refcnt=0;
1040
0
  su2ip_addr(&c->rcv.src_ip, su);
1041
0
  c->rcv.src_port=su_getport(su);
1042
0
  c->rcv.bind_address = si;
1043
0
  c->rcv.dst_ip = si->address;
1044
0
  if (sock >= 0) {
1045
0
    su_size = sockaddru_len(*su);
1046
0
    if (getsockname(sock, (struct sockaddr *)&local_su, &su_size)<0) {
1047
0
      LM_ERR("failed to get info on received interface/IP %d/%s\n",
1048
0
        errno, strerror(errno));
1049
0
      goto error;
1050
0
    }
1051
0
    c->rcv.dst_port = su_getport(&local_su);
1052
0
  } else {
1053
0
    c->rcv.dst_port = (si->flags & SI_REUSEPORT) ? su_getport(&si->su) : 0;
1054
0
  }
1055
0
  print_ip("tcpconn_new: new tcp connection to: ", &c->rcv.src_ip, "\n");
1056
0
  LM_DBG("on port %d, proto %d\n", c->rcv.src_port, si->proto);
1057
0
  c->id=tcpconn_next_id();
1058
0
  c->cid = (unsigned long long)c->id
1059
0
        | ( (unsigned long long)(startup_time&0xFFFFFF) << 32 )
1060
0
          | ( (unsigned long long)(rand()&0xFF) << 56 );
1061
1062
0
  c->rcv.proto_reserved1=0; /* this will be filled before receive_message*/
1063
0
  c->rcv.proto_reserved2=0;
1064
0
  c->state=state;
1065
0
  c->extra_data=0;
1066
0
  c->type = si->proto;
1067
0
  c->rcv.proto = si->proto;
1068
  /* start with the default conn lifetime */
1069
0
  c->lifetime = get_ticks() + prof->con_lifetime;
1070
0
  c->timeout = c->lifetime;
1071
0
  c->profile = *prof;
1072
0
  c->flags = flags;
1073
0
  c->main_flags = F_TCP_MAIN_REMOVED;
1074
#ifdef DBG_TCPCON
1075
  c->hist = sh_push(c, con_hist);
1076
#endif
1077
1078
0
  if (protos[si->proto].net.stream.async_chunks) {
1079
0
    c->async = shm_malloc(sizeof(struct tcp_async_data) +
1080
0
        protos[si->proto].net.stream.async_chunks *
1081
0
        sizeof(struct tcp_async_chunk));
1082
0
    if (c->async) {
1083
0
      c->async->allocated = protos[si->proto].net.stream.async_chunks;
1084
0
      c->async->oldest = 0;
1085
0
      c->async->pending = 0;
1086
0
    } else {
1087
0
      LM_ERR("could not allocate async data for con!\n");
1088
0
      goto error;
1089
0
    }
1090
0
  }
1091
0
  if (sock >= 0) {
1092
0
    if (protos[si->proto].net.stream.conn.init &&
1093
0
        protos[si->proto].net.stream.conn.init(c) < 0) {
1094
0
      LM_ERR("failed to do proto %d specific init for conn %p\n",
1095
0
          c->type, c);
1096
0
      goto error;
1097
0
    }
1098
0
    c->flags |= F_CONN_INIT;
1099
0
  }
1100
0
  return c;
1101
1102
0
error:
1103
0
  lock_destroy(&c->write_lock);
1104
0
error0:
1105
0
  shm_free(c);
1106
0
error_count:
1107
0
  if (counted) {
1108
0
    lock_get(tcp_connections_lock);
1109
0
    (*tcp_connections_no)--;
1110
0
    lock_release(tcp_connections_lock);
1111
0
  }
1112
0
  return 0;
1113
0
}
1114
1115
1116
/* creates a new tcp connection structure
1117
 * for an outgoing connection request; local private state is initialized later
1118
 * a +1 ref is set for the new conn !
1119
 * IMPORTANT - the function assumes you want to create a new TCP conn as
1120
 * a result of a connect operation - the conn will be set as connect !!
1121
 * Accepted connection are triggered internally only */
1122
struct tcp_connection* tcp_conn_create(const union sockaddr_union* su,
1123
    const struct socket_info* si, struct tcp_conn_profile *prof,
1124
    int state)
1125
0
{
1126
0
  struct tcp_connection *c;
1127
0
  struct tcp_conn_profile default_prof;
1128
1129
0
  if (!prof) {
1130
0
    tcp_con_get_profile(su, &si->su, si->proto, &default_prof);
1131
0
    prof = &default_prof;
1132
0
  }
1133
1134
  /* create the connection structure */
1135
0
  c = tcpconn_new(-1, su, si, prof, state, 0);
1136
0
  if (c==NULL) {
1137
0
    LM_ERR("tcpconn_new failed\n");
1138
0
    return NULL;
1139
0
  }
1140
1141
0
  c->refcnt++; /* safe to do it w/o locking, it's not yet
1142
          available to the rest of the world */
1143
0
  sh_log(c->hist, TCP_REF, "connect, (%d)", c->refcnt);
1144
0
  return c;
1145
0
}
1146
1147
1148
static inline void tcpconn_destroy(struct tcp_connection* tcpconn)
1149
0
{
1150
0
  int fd;
1151
0
  int unsigned id = tcpconn->id;
1152
0
  int hashed;
1153
1154
0
  TCPCONN_LOCK(id); /*avoid races w/ tcp_send*/
1155
0
  tcpconn->refcnt--;
1156
0
  if (tcpconn->refcnt==0){
1157
0
    LM_DBG("destroying connection %p, flags %04x\n",
1158
0
        tcpconn, tcpconn->flags);
1159
0
    fd=tcpconn->fd;
1160
    /* no reporting here - the tcpconn_destroy() function is called
1161
     * from the TCP_MAIN reactor when handling connectioned received
1162
     * from a worker; and we generate the CLOSE reports from WORKERs */
1163
0
    hashed = (tcpconn->flags & F_CONN_HASHED);
1164
0
    _tcpconn_rm(tcpconn, hashed ? 0 : 1);
1165
0
    if (fd >= 0)
1166
0
      close(fd);
1167
0
  }else{
1168
    /* force timeout */
1169
0
    tcpconn->lifetime=0;
1170
0
    tcpconn->timeout=0;
1171
0
    tcpconn->state=S_CONN_BAD;
1172
0
    sh_log(tcpconn->hist, TCP_DEL_DELAY, "tcpconn_destroy delayed, (%d)",
1173
0
      tcpconn->refcnt);
1174
0
    LM_DBG("delaying (%p, flags %04x) ref = %d ...\n",
1175
0
        tcpconn, tcpconn->flags, tcpconn->refcnt);
1176
1177
0
  }
1178
0
  TCPCONN_UNLOCK(id);
1179
0
}
1180
1181
static void tcpconn_destroy_rpc(int _, void *param)
1182
0
{
1183
0
  tcpconn_destroy(param);
1184
0
}
1185
1186
/* wrapper to the internally used function */
1187
void tcp_conn_destroy(struct tcp_connection* tcpconn)
1188
0
{
1189
0
  int tcp_main_proc;
1190
1191
0
  tcp_trigger_report(tcpconn, TCP_REPORT_CLOSE,
1192
0
        "Closed by Proto layer");
1193
0
  sh_log(tcpconn->hist, TCP_UNREF, "tcp_conn_destroy, (%d)", tcpconn->refcnt);
1194
1195
0
  if (!is_tcp_main) {
1196
0
    tcp_main_proc = tcp_get_main_proc_no();
1197
0
    if (tcp_main_proc < 0 ||
1198
0
        ipc_send_rpc(tcp_main_proc, tcpconn_destroy_rpc, tcpconn) < 0)
1199
0
      LM_ERR("failed to destroy connection %p (%u) in TCP main; "
1200
0
        "leaving its reference intact\n", tcpconn, tcpconn->id);
1201
0
    return;
1202
0
  }
1203
1204
0
  tcpconn_destroy(tcpconn);
1205
0
}
1206
1207
static inline int tcp_set_nonblock(int fd)
1208
0
{
1209
0
  int flags;
1210
1211
0
  flags = fcntl(fd, F_GETFL);
1212
0
  if (flags == -1) {
1213
0
    LM_ERR("fcntl(F_GETFL) failed for %d: %s\n", fd, strerror(errno));
1214
0
    return -1;
1215
0
  }
1216
1217
0
  if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
1218
0
    LM_ERR("fcntl(F_SETFL) failed for %d: %s\n", fd, strerror(errno));
1219
0
    return -1;
1220
0
  }
1221
1222
0
  return 0;
1223
0
}
1224
1225
static void tcp_push_done_job(struct tcp_job *job)
1226
0
{
1227
0
  pthread_mutex_lock(&tcp_pool.done_lock);
1228
0
  if (tcp_pool.done_tail)
1229
0
    tcp_pool.done_tail->next = job;
1230
0
  else
1231
0
    tcp_pool.done_head = job;
1232
0
  tcp_pool.done_tail = job;
1233
0
  pthread_mutex_unlock(&tcp_pool.done_lock);
1234
0
}
1235
1236
static struct tcp_job *tcp_pop_done_job(void)
1237
0
{
1238
0
  struct tcp_job *job;
1239
1240
0
  pthread_mutex_lock(&tcp_pool.done_lock);
1241
0
  job = tcp_pool.done_head;
1242
0
  if (job) {
1243
0
    tcp_pool.done_head = job->next;
1244
0
    if (tcp_pool.done_head == NULL)
1245
0
      tcp_pool.done_tail = NULL;
1246
0
  }
1247
0
  pthread_mutex_unlock(&tcp_pool.done_lock);
1248
1249
0
  return job;
1250
0
}
1251
1252
static inline struct tcp_connection *tcp_pop_shared_write_conn_locked(void)
1253
0
{
1254
0
  struct tcp_connection *conn;
1255
1256
0
  conn = tcp_write_queue->head;
1257
0
  if (conn) {
1258
0
    tcp_write_queue->head = conn->wq_next;
1259
0
    if (tcp_write_queue->head == NULL)
1260
0
      tcp_write_queue->tail = NULL;
1261
0
    conn->wq_next = NULL;
1262
0
  }
1263
1264
0
  return conn;
1265
0
}
1266
1267
/* tcp_write_queue->cond must be held and conn->write_queued must be set. */
1268
static inline void tcp_push_shared_write_conn_locked(
1269
    struct tcp_connection *conn)
1270
0
{
1271
0
  conn->wq_next = NULL;
1272
0
  if (tcp_write_queue->tail)
1273
0
    tcp_write_queue->tail->wq_next = conn;
1274
0
  else
1275
0
    tcp_write_queue->head = conn;
1276
0
  tcp_write_queue->tail = conn;
1277
0
  cond_signal(&tcp_write_queue->cond);
1278
0
}
1279
1280
static void *tcp_thread_routine(void *arg)
1281
0
{
1282
0
  struct tcp_job *job;
1283
0
  struct tcp_connection *conn;
1284
0
  char wake = 'x';
1285
0
  int rc;
1286
1287
0
  (void)arg;
1288
1289
  /* Reactor operations stay in TCP main; IO threads only run read/write
1290
   * callbacks and notify completion back to the main thread. */
1291
0
  while (1) {
1292
0
    cond_lock(&tcp_write_queue->cond);
1293
0
    while (!tcp_pool.stop && tcp_pool.task_head == NULL &&
1294
0
        tcp_write_queue->head == NULL)
1295
0
      cond_wait(&tcp_write_queue->cond);
1296
1297
0
    if (tcp_pool.stop && tcp_pool.task_head == NULL &&
1298
0
        tcp_write_queue->head == NULL) {
1299
0
      cond_unlock(&tcp_write_queue->cond);
1300
0
      break;
1301
0
    }
1302
1303
0
    job = tcp_pool.task_head;
1304
0
    if (job) {
1305
0
      tcp_pool.task_head = job->next;
1306
0
      if (tcp_pool.task_head == NULL)
1307
0
        tcp_pool.task_tail = NULL;
1308
0
    } else if ((conn = tcp_pop_shared_write_conn_locked()) != NULL) {
1309
0
      job = thread_malloc(sizeof(*job));
1310
0
      if (!job) {
1311
0
        LM_ERR("oom while building shared TCP write job\n");
1312
0
        conn->write_queued = 0;
1313
0
        cond_unlock(&tcp_write_queue->cond);
1314
0
        tcpconn_put(conn);
1315
0
        continue;
1316
0
      }
1317
0
      job->conn = conn;
1318
0
      job->op = TCP_WRITE_JOB;
1319
0
      job->run = NULL;
1320
0
      job->data = NULL;
1321
0
      job->resp = 0;
1322
0
      job->ret = 0;
1323
0
      job->next = NULL;
1324
0
    }
1325
0
    cond_unlock(&tcp_write_queue->cond);
1326
1327
0
    conn = job->conn;
1328
0
    if (job->op == TCP_READ_JOB) {
1329
0
      if (conn->msg_attempts && get_ticks() > conn->timeout) {
1330
0
        job->ret = -1;
1331
0
        job->resp = -2;
1332
0
      } else if (protos[conn->type].net.stream.read) {
1333
0
        job->resp = protos[conn->type].net.stream.read(conn, &job->ret);
1334
0
      } else {
1335
0
        LM_ERR("missing stream.read callback for proto %d\n", conn->type);
1336
0
        job->ret = -1;
1337
0
        job->resp = -1;
1338
0
      }
1339
0
    } else if (job->op == TCP_WRITE_JOB) {
1340
0
      if (protos[conn->type].net.stream.write) {
1341
0
        if (tcpconn_prepare_write(conn) < 0) {
1342
0
          job->ret = -1;
1343
0
          job->resp = -1;
1344
0
          goto done_job;
1345
0
        }
1346
0
        lock_get(&conn->write_lock);
1347
0
        job->resp = protos[conn->type].net.stream.write(conn, conn->fd);
1348
0
        lock_release(&conn->write_lock);
1349
0
        job->ret = (job->resp < 0) ? -1 : 0;
1350
0
      } else {
1351
0
        LM_ERR("missing stream.write callback for proto %d\n", conn->type);
1352
0
        job->ret = -1;
1353
0
        job->resp = -1;
1354
0
      }
1355
0
    } else if (job->op == TCP_RUN_JOB) {
1356
0
      job->ret = job->run ? job->run(job->data) : -1;
1357
0
      thread_free(job);
1358
0
      continue;
1359
0
    } else {
1360
0
      LM_ERR("unknown TCP job op %d\n", job->op);
1361
0
      job->ret = -1;
1362
0
      job->resp = -1;
1363
0
    }
1364
1365
0
done_job:
1366
0
    job->next = NULL;
1367
0
    tcp_push_done_job(job);
1368
1369
0
    rc = write(tcp_pool.notify_pipe[1], &wake, 1);
1370
0
    if (rc < 0 && errno != EAGAIN && errno != EWOULDBLOCK)
1371
0
      LM_ERR("failed to notify TCP IO completion: %s\n", strerror(errno));
1372
0
  }
1373
1374
0
  return NULL;
1375
0
}
1376
1377
static int tcp_pool_init(void)
1378
0
{
1379
0
  int i;
1380
0
  int started = 0;
1381
0
  int threads_no;
1382
0
  long cpu_no;
1383
1384
0
  if (tcp_threads > 0)
1385
0
    threads_no = tcp_threads;
1386
0
  else {
1387
0
    cpu_no = sysconf(_SC_NPROCESSORS_ONLN);
1388
0
    if (cpu_no > 0)
1389
0
      threads_no = (int)cpu_no;
1390
0
    else if (tcp_workers_no > 0)
1391
0
      threads_no = tcp_workers_no;
1392
0
    else
1393
0
      threads_no = 1;
1394
0
  }
1395
1396
0
  if (pipe(tcp_pool.notify_pipe) < 0) {
1397
0
    LM_ERR("failed to create TCP IO notification pipe: %s\n", strerror(errno));
1398
0
    goto error;
1399
0
  }
1400
1401
0
  if (tcp_set_nonblock(tcp_pool.notify_pipe[0]) < 0 ||
1402
0
      tcp_set_nonblock(tcp_pool.notify_pipe[1]) < 0)
1403
0
    goto error;
1404
1405
0
  if (reactor_add_reader(tcp_pool.notify_pipe[0],
1406
0
    F_TCP_NOTIFY, RCT_PRIO_PROC, NULL) < 0) {
1407
0
    LM_ERR("failed to add TCP IO notify pipe to reactor\n");
1408
0
    goto error;
1409
0
  }
1410
1411
0
  tcp_pool.threads = pkg_malloc(sizeof(*tcp_pool.threads) * threads_no);
1412
0
  if (!tcp_pool.threads) {
1413
0
    LM_ERR("oom while allocating TCP IO threads array\n");
1414
0
    goto error;
1415
0
  }
1416
1417
0
  tcp_pool.stop = 0;
1418
0
  tcp_pool.threads_no = threads_no;
1419
1420
0
  for (i = 0; i < threads_no; i++) {
1421
0
    if (pthread_create(&tcp_pool.threads[i], NULL,
1422
0
        tcp_thread_routine, NULL) != 0) {
1423
0
      LM_ERR("failed to start TCP IO thread %d/%d\n", i + 1, threads_no);
1424
0
      goto error;
1425
0
    }
1426
0
    started++;
1427
0
  }
1428
1429
0
  LM_NOTICE("TCP single IO mode started with %d threads\n", threads_no);
1430
0
  return 0;
1431
1432
0
error:
1433
0
  cond_lock(&tcp_write_queue->cond);
1434
0
  tcp_pool.stop = 1;
1435
0
  cond_broadcast(&tcp_write_queue->cond);
1436
0
  cond_unlock(&tcp_write_queue->cond);
1437
1438
0
  if (tcp_pool.threads) {
1439
0
    for (i = 0; i < started; i++)
1440
0
      pthread_join(tcp_pool.threads[i], NULL);
1441
0
    pkg_free(tcp_pool.threads);
1442
0
    tcp_pool.threads = NULL;
1443
0
  }
1444
0
  tcp_pool.threads_no = 0;
1445
1446
0
  if (tcp_pool.notify_pipe[0] >= 0) {
1447
0
    reactor_del_reader(tcp_pool.notify_pipe[0], -1, 0);
1448
0
    close(tcp_pool.notify_pipe[0]);
1449
0
    tcp_pool.notify_pipe[0] = -1;
1450
0
  }
1451
0
  if (tcp_pool.notify_pipe[1] >= 0) {
1452
0
    close(tcp_pool.notify_pipe[1]);
1453
0
    tcp_pool.notify_pipe[1] = -1;
1454
0
  }
1455
1456
0
  return -1;
1457
0
}
1458
1459
static void tcp_pool_destroy(void)
1460
0
{
1461
0
  int i;
1462
0
  struct tcp_job *job;
1463
0
  struct tcp_job *next;
1464
0
  struct tcp_connection *conn;
1465
1466
0
  if (!tcp_threads_active() && tcp_pool.notify_pipe[0] < 0)
1467
0
    return;
1468
1469
0
  cond_lock(&tcp_write_queue->cond);
1470
0
  tcp_pool.stop = 1;
1471
0
  cond_broadcast(&tcp_write_queue->cond);
1472
0
  cond_unlock(&tcp_write_queue->cond);
1473
1474
0
  for (i = 0; i < tcp_pool.threads_no; i++)
1475
0
    pthread_join(tcp_pool.threads[i], NULL);
1476
1477
0
  if (tcp_pool.threads) {
1478
0
    pkg_free(tcp_pool.threads);
1479
0
    tcp_pool.threads = NULL;
1480
0
  }
1481
0
  tcp_pool.threads_no = 0;
1482
1483
0
  if (tcp_pool.notify_pipe[0] >= 0) {
1484
0
    reactor_del_reader(tcp_pool.notify_pipe[0], -1, 0);
1485
0
    close(tcp_pool.notify_pipe[0]);
1486
0
    tcp_pool.notify_pipe[0] = -1;
1487
0
  }
1488
0
  if (tcp_pool.notify_pipe[1] >= 0) {
1489
0
    close(tcp_pool.notify_pipe[1]);
1490
0
    tcp_pool.notify_pipe[1] = -1;
1491
0
  }
1492
1493
0
  cond_lock(&tcp_write_queue->cond);
1494
0
  for (job = tcp_pool.task_head; job; job = next) {
1495
0
    next = job->next;
1496
0
    if (job->conn)
1497
0
      tcpconn_put(job->conn);
1498
0
    thread_free(job);
1499
0
  }
1500
0
  tcp_pool.task_head = tcp_pool.task_tail = NULL;
1501
0
  while ((conn = tcp_pop_shared_write_conn_locked()) != NULL) {
1502
0
    conn->write_queued = 0;
1503
0
    tcpconn_put(conn);
1504
0
  }
1505
0
  cond_unlock(&tcp_write_queue->cond);
1506
1507
0
  pthread_mutex_lock(&tcp_pool.done_lock);
1508
0
  for (job = tcp_pool.done_head; job; job = next) {
1509
0
    next = job->next;
1510
0
    if (job->conn)
1511
0
      tcpconn_put(job->conn);
1512
0
    thread_free(job);
1513
0
  }
1514
0
  tcp_pool.done_head = tcp_pool.done_tail = NULL;
1515
0
  pthread_mutex_unlock(&tcp_pool.done_lock);
1516
0
}
1517
1518
static int tcp_queue_job(struct tcp_connection *tcpconn, int op)
1519
0
{
1520
0
  struct tcp_job *job;
1521
1522
0
  if (!tcp_threads_active())
1523
0
    return -1;
1524
1525
0
  job = thread_malloc(sizeof(*job));
1526
0
  if (!job) {
1527
0
    LM_ERR("oom while queuing TCP IO job\n");
1528
0
    return -1;
1529
0
  }
1530
1531
0
  job->conn = tcpconn;
1532
0
  job->op = op;
1533
0
  job->run = NULL;
1534
0
  job->data = NULL;
1535
0
  job->resp = 0;
1536
0
  job->ret = 0;
1537
0
  job->next = NULL;
1538
1539
0
  cond_lock(&tcp_write_queue->cond);
1540
0
  if (tcp_pool.task_tail)
1541
0
    tcp_pool.task_tail->next = job;
1542
0
  else
1543
0
    tcp_pool.task_head = job;
1544
0
  tcp_pool.task_tail = job;
1545
0
  cond_signal(&tcp_write_queue->cond);
1546
0
  cond_unlock(&tcp_write_queue->cond);
1547
1548
0
  return 0;
1549
0
}
1550
1551
int tcp_async_write_job(struct tcp_connection *tcpconn)
1552
0
{
1553
0
  if (!tcp_write_queue)
1554
0
    return -1;
1555
0
  if ((tcpconn->flags & F_CONN_HASHED) == 0)
1556
0
    tcpconn_add(tcpconn);
1557
1558
0
  cond_lock(&tcp_write_queue->cond);
1559
0
  if (tcpconn->write_queued) {
1560
0
    cond_unlock(&tcp_write_queue->cond);
1561
    /* a write job is already queued for this connection and it owns
1562
     * exactly one reference, which it releases on completion; our
1563
     * callers treat success as a transfer of their own reference, so
1564
     * it has to be released here, otherwise it leaks and the
1565
     * connection can never be destroyed */
1566
0
    tcpconn_put(tcpconn);
1567
0
    return 0;
1568
0
  }
1569
1570
0
  tcpconn->write_queued = 1;
1571
0
  tcp_push_shared_write_conn_locked(tcpconn);
1572
0
  cond_unlock(&tcp_write_queue->cond);
1573
0
  return 0;
1574
0
}
1575
1576
int tcp_run_task(tcp_thread_job_f run, void *data)
1577
0
{
1578
0
  struct tcp_job *job;
1579
1580
0
  if (!run)
1581
0
    return -1;
1582
1583
0
  if (!tcp_threads_active()) {
1584
0
    run(data);
1585
0
    return 0;
1586
0
  }
1587
1588
0
  job = thread_malloc(sizeof(*job));
1589
0
  if (!job) {
1590
0
    LM_ERR("oom while queuing TCP run job\n");
1591
0
    return -1;
1592
0
  }
1593
1594
0
  job->conn = NULL;
1595
0
  job->op = TCP_RUN_JOB;
1596
0
  job->run = run;
1597
0
  job->data = data;
1598
0
  job->resp = 0;
1599
0
  job->ret = -1;
1600
0
  job->next = NULL;
1601
1602
0
  cond_lock(&tcp_write_queue->cond);
1603
0
  if (tcp_pool.task_tail)
1604
0
    tcp_pool.task_tail->next = job;
1605
0
  else
1606
0
    tcp_pool.task_head = job;
1607
0
  tcp_pool.task_tail = job;
1608
0
  cond_signal(&tcp_write_queue->cond);
1609
0
  cond_unlock(&tcp_write_queue->cond);
1610
1611
0
  return 0;
1612
0
}
1613
1614
static inline int tcp_queue_write_job(struct tcp_connection *tcpconn)
1615
0
{
1616
0
  if (!(tcpconn->main_flags & F_TCP_MAIN_REMOVED_READ) &&
1617
0
      tcpconn->fd != -1) {
1618
0
    if (reactor_del_reader(tcpconn->fd, -1, 0) == -1)
1619
0
      return -1;
1620
0
    tcpconn->main_flags |= F_TCP_MAIN_REMOVED_READ;
1621
0
  }
1622
1623
0
  if (tcp_async_write_job(tcpconn) < 0)
1624
0
    return -1;
1625
1626
0
  return 0;
1627
0
}
1628
1629
static inline void tcp_fail_conn(struct tcp_connection *tcpconn,
1630
    const char *reason, int report)
1631
0
{
1632
0
  if ((tcpconn->main_flags & F_TCP_MAIN_REMOVED) !=
1633
0
      F_TCP_MAIN_REMOVED &&
1634
0
      tcpconn->fd != -1) {
1635
0
    reactor_del_all(tcpconn->fd, -1, IO_FD_CLOSING);
1636
0
    tcpconn->main_flags |= F_TCP_MAIN_REMOVED;
1637
0
  }
1638
1639
0
  if (report)
1640
0
    tcp_trigger_report(tcpconn, TCP_REPORT_CLOSE, (void *)reason);
1641
1642
0
  tcpconn_destroy(tcpconn);
1643
0
}
1644
1645
static inline void tcp_complete_read(struct tcp_job *job)
1646
0
{
1647
0
  struct tcp_connection *tcpconn;
1648
1649
0
  tcpconn = job->conn;
1650
1651
0
  tcpconn->main_flags &= ~F_TCP_MAIN_READ_QUEUED;
1652
1653
0
  if (job->resp == -2) {
1654
0
    tcp_fail_conn(tcpconn, "Timeout waiting for a complete message", 1);
1655
0
    return;
1656
0
  }
1657
1658
0
  if (job->resp < 0 || tcpconn->state == S_CONN_BAD) {
1659
0
    tcp_fail_conn(tcpconn, "Read error", 1);
1660
0
    return;
1661
0
  }
1662
1663
0
  if (tcpconn->state == S_CONN_EOF) {
1664
0
    tcp_fail_conn(tcpconn, "EOF received", 1);
1665
0
    return;
1666
0
  }
1667
1668
0
  if (tcpconn->main_flags & F_TCP_MAIN_REMOVED_READ) {
1669
0
    if (reactor_add_reader(tcpconn->fd, F_TCPCONN, RCT_PRIO_NET, tcpconn) < 0) {
1670
0
      LM_ERR("failed to re-add TCP conn %p for read events\n", tcpconn);
1671
0
      tcp_fail_conn(tcpconn, "Failed to re-arm read", 0);
1672
0
      return;
1673
0
    }
1674
0
    tcpconn->main_flags &= ~F_TCP_MAIN_REMOVED_READ;
1675
0
  }
1676
1677
0
  tcpconn_put(tcpconn);
1678
0
}
1679
1680
static inline void tcp_complete_write(struct tcp_job *job)
1681
0
{
1682
0
  struct tcp_connection *tcpconn;
1683
0
  int pending_chunks;
1684
1685
0
  tcpconn = job->conn;
1686
1687
0
  if (job->resp < 0 || tcpconn->state == S_CONN_BAD) {
1688
0
    tcp_fail_conn(tcpconn, "Write error", 1);
1689
0
    return;
1690
0
  }
1691
1692
0
  if ((tcpconn->main_flags & F_TCP_MAIN_REMOVED_READ) &&
1693
0
      !(tcpconn->main_flags & F_TCP_MAIN_READ_QUEUED) &&
1694
0
      tcpconn->fd != -1) {
1695
0
    if (reactor_add_reader(tcpconn->fd, F_TCPCONN, RCT_PRIO_NET,
1696
0
        tcpconn) < 0) {
1697
0
      LM_ERR("failed to add TCP conn %p for read events\n", tcpconn);
1698
0
      tcp_fail_conn(tcpconn, "Failed to arm read", 0);
1699
0
      return;
1700
0
    }
1701
0
    tcpconn->main_flags &= ~F_TCP_MAIN_REMOVED_READ;
1702
0
  }
1703
1704
0
  if (job->resp == 1) {
1705
0
    if (reactor_add_writer(tcpconn->fd, F_TCPCONN, RCT_PRIO_NET, tcpconn) < 0) {
1706
0
      LM_ERR("failed to re-add TCP conn %p for write events\n", tcpconn);
1707
0
      tcp_fail_conn(tcpconn, "Failed to re-arm write", 0);
1708
0
      return;
1709
0
    }
1710
0
    tcpconn->main_flags &= ~F_TCP_MAIN_REMOVED_WRITE;
1711
0
    cond_lock(&tcp_write_queue->cond);
1712
0
    tcpconn->write_queued = 0;
1713
0
    cond_unlock(&tcp_write_queue->cond);
1714
0
    tcpconn_put(tcpconn);
1715
0
    return;
1716
0
  }
1717
1718
  /* Serialize the pending-data check with producers deciding whether they
1719
   * need to enqueue this connection.  Otherwise a producer may observe the
1720
   * old queued state after we checked an empty async queue, leaving its new
1721
   * chunk without either a queued job or a writer event. */
1722
0
  cond_lock(&tcp_write_queue->cond);
1723
0
  lock_get(&tcpconn->write_lock);
1724
0
  pending_chunks = (tcpconn->async && tcpconn->async->pending);
1725
0
  lock_release(&tcpconn->write_lock);
1726
1727
0
  if (pending_chunks) {
1728
0
    tcp_push_shared_write_conn_locked(tcpconn);
1729
0
    cond_unlock(&tcp_write_queue->cond);
1730
0
    return;
1731
0
  }
1732
1733
0
  tcpconn->write_queued = 0;
1734
0
  cond_unlock(&tcp_write_queue->cond);
1735
0
  tcpconn_put(tcpconn);
1736
0
}
1737
1738
static inline int handle_tcp_notify(int fd)
1739
0
{
1740
0
  char buf[64];
1741
0
  int n;
1742
0
  struct tcp_job *job;
1743
1744
0
  while ((n = read(fd, buf, sizeof(buf))) > 0)
1745
0
    ;
1746
0
  if (n < 0 && errno != EAGAIN && errno != EWOULDBLOCK)
1747
0
    LM_ERR("failed to read TCP IO notify fd: %s\n", strerror(errno));
1748
1749
0
  while ((job = tcp_pop_done_job()) != NULL) {
1750
0
    if (job->op == TCP_READ_JOB)
1751
0
      tcp_complete_read(job);
1752
0
    else
1753
0
      tcp_complete_write(job);
1754
0
    thread_free(job);
1755
0
  }
1756
1757
0
  return 0;
1758
0
}
1759
1760
1761
/************************ TCP MAIN process functions ************************/
1762
1763
/*! \brief
1764
 * handles a new connection, called internally by tcp_main_loop/handle_io.
1765
 * \param si - pointer to one of the tcp socket_info structures on which
1766
 *              an io event was detected (connection attempt)
1767
 * \return  handle_* return convention: -1 on error, 0 on EAGAIN (no more
1768
 *           io events queued), >0 on success. success/error refer only to
1769
 *           the accept.
1770
 */
1771
static inline int handle_new_connect(const struct socket_info* si)
1772
0
{
1773
0
  union sockaddr_union su;
1774
0
  struct tcp_connection* tcpconn;
1775
0
  struct tcp_conn_profile prof;
1776
0
  socklen_t su_len = sizeof(su);
1777
0
  int new_sock;
1778
0
  unsigned int id;
1779
1780
  /* coverity[overrun-buffer-arg: FALSE] - union has 28 bytes, CID #200070 */
1781
0
  new_sock = accept(si->socket, &(su.s), &su_len);
1782
0
  if (new_sock == -1) {
1783
0
    if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
1784
0
      return 0;
1785
0
    LM_ERR("failed to accept connection(%d): %s\n", errno, strerror(errno));
1786
0
    return -1;
1787
0
  }
1788
1789
0
  tcp_con_get_profile(&su, &si->su, si->proto, &prof);
1790
0
  if (tcp_init_sock_opt(new_sock, &prof, si->flags, si->tos) < 0) {
1791
0
    LM_ERR("tcp_init_sock_opt failed\n");
1792
0
    close(new_sock);
1793
0
    return 1; /* success, because the accept was successful */
1794
0
  }
1795
1796
  /* add socket to list */
1797
0
  tcpconn = tcpconn_new(new_sock, &su, si, &prof, S_CONN_OK,
1798
0
    F_CONN_ACCEPTED);
1799
0
  if (tcpconn) {
1800
    /* Safe: the connection is not yet visible outside TCP main. */
1801
0
    tcpconn->refcnt++;
1802
0
    sh_log(tcpconn->hist, TCP_REF, "accept, (%d)", tcpconn->refcnt);
1803
0
    tcpconn_add(tcpconn);
1804
0
    LM_DBG("new connection: %p %d flags: %04x\n",
1805
0
      tcpconn, tcpconn->fd, tcpconn->flags);
1806
0
    if (reactor_add_reader(tcpconn->fd, F_TCPCONN, RCT_PRIO_NET,
1807
0
        tcpconn) < 0) {
1808
0
      LM_ERR("failed to add accepted TCP conn to reactor\n");
1809
0
      id = tcpconn->id;
1810
0
      TCPCONN_LOCK(id);
1811
0
      tcpconn->refcnt--;
1812
0
      if (tcpconn->refcnt == 0) {
1813
0
        _tcpconn_rm(tcpconn, 1);
1814
0
        close(new_sock);
1815
0
      } else {
1816
0
        tcpconn->lifetime = 0;
1817
0
        tcpconn->timeout = 0;
1818
0
      }
1819
0
      TCPCONN_UNLOCK(id);
1820
0
    } else {
1821
0
      tcpconn->main_flags &= ~F_TCP_MAIN_REMOVED_READ;
1822
0
      tcpconn_put(tcpconn);
1823
0
    }
1824
0
  } else {
1825
0
    LM_ERR("tcpconn_new failed, closing socket\n");
1826
0
    close(new_sock);
1827
0
  }
1828
0
  return 1; /* accept() was successful */
1829
0
}
1830
1831
1832
/*! \brief
1833
 * handles an io event on one of the watched tcp connections
1834
 *
1835
 * \param    tcpconn - pointer to the tcp_connection for which we have an io ev.
1836
 * \param    fd_i    - index in the fd_array table (needed for delete)
1837
 * \return   handle_* return convention, but on success it always returns 0
1838
 */
1839
inline static int handle_tcpconn_ev(struct tcp_connection* tcpconn, int fd_i,
1840
    int event_type)
1841
0
{
1842
0
  int err;
1843
0
  unsigned int err_len;
1844
1845
0
  if (event_type == IO_WATCH_READ) {
1846
0
    LM_DBG("data available on %p %d\n", tcpconn, tcpconn->fd);
1847
0
    if (tcpconn->main_flags & F_TCP_MAIN_READ_QUEUED) {
1848
0
      LM_BUG("read job already queued for TCP conn %p\n", tcpconn);
1849
0
      if (!(tcpconn->main_flags & F_TCP_MAIN_REMOVED_READ) &&
1850
0
          tcpconn->fd != -1) {
1851
0
        if (reactor_del_reader(tcpconn->fd, fd_i, 0) == -1)
1852
0
          return -1;
1853
0
        tcpconn->main_flags |= F_TCP_MAIN_REMOVED_READ;
1854
0
      }
1855
0
      return 0;
1856
0
    }
1857
0
    if (reactor_del_reader(tcpconn->fd, fd_i, 0) == -1)
1858
0
      return -1;
1859
0
    tcpconn->main_flags |=
1860
0
        F_TCP_MAIN_REMOVED_READ|F_TCP_MAIN_READ_QUEUED;
1861
0
    tcpconn_ref(tcpconn); /* refcnt ++ */
1862
0
    sh_log(tcpconn->hist, TCP_REF, "tcp-main read queued, (%d)",
1863
0
      tcpconn->refcnt);
1864
0
    if (tcp_queue_job(tcpconn, TCP_READ_JOB) < 0) {
1865
0
      LM_ERR("failed queuing TCP read job\n");
1866
0
      tcpconn->main_flags &= ~F_TCP_MAIN_READ_QUEUED;
1867
0
      if (reactor_add_reader(tcpconn->fd, F_TCPCONN, RCT_PRIO_NET,
1868
0
          tcpconn) < 0) {
1869
0
        tcp_fail_conn(tcpconn, "Failed queueing read", 0);
1870
0
        return 0;
1871
0
      }
1872
0
      tcpconn->main_flags &= ~F_TCP_MAIN_REMOVED_READ;
1873
0
      tcpconn_put(tcpconn);
1874
0
    }
1875
0
    return 0;
1876
0
  } else {
1877
0
    LM_DBG("connection %p fd %d is now writable\n", tcpconn, tcpconn->fd);
1878
    /* we received a write event */
1879
0
    if (tcpconn->state == S_CONN_CONNECTING) {
1880
      /* we're coming from an async connect & write
1881
       * let's see if we connected successfully */
1882
0
      err_len = sizeof(err);
1883
0
      if (getsockopt(tcpconn->fd, SOL_SOCKET, SO_ERROR, &err, &err_len) < 0 ||
1884
0
          err != 0) {
1885
0
        LM_DBG("Failed connection attempt\n");
1886
0
        tcpconn_ref(tcpconn);
1887
0
        sh_log(tcpconn->hist, TCP_REF, "tcpconn connect, (%d)", tcpconn->refcnt);
1888
0
        reactor_del_all(tcpconn->fd, fd_i, IO_FD_CLOSING);
1889
0
        tcpconn->main_flags |= F_TCP_MAIN_REMOVED;
1890
0
        tcp_trigger_report(tcpconn, TCP_REPORT_CLOSE,
1891
0
          "Async connect failed");
1892
0
        sh_log(tcpconn->hist, TCP_UNREF, "tcpconn connect, (%d)", tcpconn->refcnt);
1893
0
        tcpconn_destroy(tcpconn);
1894
0
        return 0;
1895
0
      }
1896
1897
      /* we successfully connected - further treat this case as if we
1898
       * were coming from an async write */
1899
0
      tcpconn->state = S_CONN_OK;
1900
0
      LM_DBG("Successfully completed previous async connect\n");
1901
1902
      /* now that we completed the async connection, we also need to
1903
       * listen for READ events, otherwise these will get lost */
1904
0
      if ((tcpconn->main_flags & F_TCP_MAIN_REMOVED_READ) &&
1905
0
          !(tcpconn->main_flags & F_TCP_MAIN_READ_QUEUED)) {
1906
0
        if (reactor_add_reader(tcpconn->fd, F_TCPCONN, RCT_PRIO_NET,
1907
0
            tcpconn) < 0) {
1908
0
          LM_ERR("failed to re-arm TCP conn %p for read events\n",
1909
0
            tcpconn);
1910
0
          tcp_fail_conn(tcpconn, "Failed to re-arm read", 0);
1911
0
          return 0;
1912
0
        }
1913
0
        tcpconn->main_flags &= ~F_TCP_MAIN_REMOVED_READ;
1914
0
      }
1915
1916
0
      goto async_write;
1917
0
    } else {
1918
0
async_write:
1919
      /* no more write events for now */
1920
0
        if (reactor_del_writer(tcpconn->fd, fd_i, 0) == -1)
1921
0
          return -1;
1922
0
      tcpconn->main_flags |= F_TCP_MAIN_REMOVED_WRITE;
1923
0
      tcpconn_ref(tcpconn); /* refcnt ++ */
1924
0
      sh_log(tcpconn->hist, TCP_REF, "tcpconn write, (%d)",
1925
0
        tcpconn->refcnt);
1926
0
      if (tcp_queue_write_job(tcpconn) < 0) {
1927
0
        LM_ERR("failed queuing TCP write job\n");
1928
0
        if (reactor_add_writer(tcpconn->fd, F_TCPCONN, RCT_PRIO_NET,
1929
0
            tcpconn) < 0) {
1930
0
          tcp_fail_conn(tcpconn, "Failed queueing write", 0);
1931
0
          return 0;
1932
0
        }
1933
0
        tcpconn->main_flags &= ~F_TCP_MAIN_REMOVED_WRITE;
1934
0
        tcpconn_put(tcpconn);
1935
0
      }
1936
0
      return 0;
1937
0
    }
1938
0
  }
1939
0
}
1940
1941
1942
/*! \brief generic handle io routine, it will call the appropiate
1943
 *  handle_xxx() based on the fd_map type
1944
 *
1945
 * \param  fm  - pointer to a fd hash entry
1946
 * \param  idx - index in the fd_array (or -1 if not known)
1947
 * \return -1 on error
1948
 *          0 on EAGAIN or when by some other way it is known that no more
1949
 *            io events are queued on the fd (the receive buffer is empty).
1950
 *            Usefull to detect when there are no more io events queued for
1951
 *            sigio_rt, epoll_et, kqueue.
1952
 *         >0 on successful read from the fd (when there might be more io
1953
 *            queued -- the receive buffer might still be non-empty)
1954
 */
1955
inline static int handle_io(struct fd_map* fm, int idx,int event_type)
1956
0
{
1957
0
  int ret = 0;
1958
1959
0
  pt_become_active();
1960
  /* for now we do not do any profiling here as all ops here are
1961
     only internals related to TCP passing beetween processing, no real
1962
     processing
1963
   */
1964
0
  switch(fm->type){
1965
0
    case F_TCP_LISTENER:
1966
0
      ret = handle_new_connect((const struct socket_info*)fm->data);
1967
0
      break;
1968
0
    case F_TCPCONN:
1969
0
      ret = handle_tcpconn_ev((struct tcp_connection*)fm->data, idx,
1970
0
        event_type);
1971
0
      break;
1972
0
    case F_TCP_NOTIFY:
1973
0
      ret = handle_tcp_notify(fm->fd);
1974
0
      break;
1975
0
    case F_IPC:
1976
0
      ipc_handle_job(fm->fd);
1977
0
      break;
1978
0
    case F_NONE:
1979
0
      LM_CRIT("empty fd map\n");
1980
0
      goto error;
1981
0
    default:
1982
0
      LM_CRIT("unknown fd type %d\n", fm->type);
1983
0
      goto error;
1984
0
  }
1985
0
  pt_become_idle();
1986
0
  return ret;
1987
0
error:
1988
0
  pt_become_idle();
1989
0
  return -1;
1990
0
}
1991
1992
1993
/*
1994
 * iterates through all TCP connections and closes expired ones
1995
 * Note: runs once per second at most
1996
 */
1997
#define tcpconn_lifetime(last_sec) \
1998
  do { \
1999
    int now; \
2000
    now = get_ticks(); \
2001
    if (last_sec != now) { \
2002
      last_sec = now; \
2003
      __tcpconn_lifetime(0); \
2004
    } \
2005
  } while (0)
2006
2007
2008
/*! \brief very inefficient for now - FIXME
2009
 * keep in sync with tcpconn_destroy, the "delete" part should be
2010
 * the same except for io_watch_del..
2011
 * \todo FIXME (very inefficient for now)
2012
 */
2013
static inline void __tcpconn_lifetime(int shutdown)
2014
0
{
2015
0
  struct tcp_connection *c, *next;
2016
0
  unsigned int ticks,part;
2017
0
  unsigned h;
2018
0
  int fd;
2019
0
  void *reason;
2020
2021
0
  if (have_ticks())
2022
0
    ticks=get_ticks();
2023
0
  else
2024
0
    ticks=0;
2025
2026
0
  for( part=0 ; part<TCP_PARTITION_SIZE ; part++ ) {
2027
0
    if (!shutdown) TCPCONN_LOCK(part); /* fixme: we can lock only on delete IMO */
2028
0
    for(h=0; h<TCP_ID_HASH_SIZE; h++){
2029
0
      c=TCP_PART(part).tcpconn_id_hash[h];
2030
0
      while(c){
2031
0
        next=c->id_next;
2032
0
        if (shutdown || ((c->refcnt == 0) &&
2033
0
        ((ticks > c->lifetime) ||
2034
0
        (c->msg_attempts && ticks > c->timeout)))) {
2035
0
          if (!shutdown)
2036
0
            LM_DBG("timeout for hash=%d - %p"
2037
0
                " (%d > %d)\n", h, c, ticks, c->lifetime);
2038
0
          fd=c->fd;
2039
          /* report the closing of the connection . Note that
2040
           * there are connectioned that use an foced expire to 0
2041
           * as a way to be deleted - we are not interested in */
2042
          /* Also, do not trigger reporting when shutdown
2043
           * is done */
2044
0
          if (c->lifetime>0 && !shutdown) {
2045
0
            reason = (c->msg_attempts && ticks > c->timeout) ?
2046
0
              "Timeout waiting for a complete message" :
2047
0
              "Timeout on no traffic";
2048
0
            tcp_trigger_report(c, TCP_REPORT_CLOSE, reason);
2049
0
          }
2050
0
          if ((!shutdown)&&(fd>0)&&(c->refcnt==0)) {
2051
            /* if any of read or write are set, we need to remove
2052
             * the fd from the reactor */
2053
0
            if ((c->main_flags & F_TCP_MAIN_REMOVED) !=
2054
0
                F_TCP_MAIN_REMOVED) {
2055
0
              reactor_del_all( fd, -1, IO_FD_CLOSING);
2056
0
              c->main_flags |= F_TCP_MAIN_REMOVED;
2057
0
            }
2058
0
            close(fd);
2059
0
            c->fd = -1;
2060
0
            }
2061
0
            _tcpconn_rm(c, shutdown?1:0);
2062
0
          }
2063
0
          c=next;
2064
0
        }
2065
0
    }
2066
0
    if (!shutdown) TCPCONN_UNLOCK(part);
2067
0
  }
2068
0
}
2069
2070
2071
static void tcp_main_server(void)
2072
0
{
2073
0
  static unsigned int last_sec = 0;
2074
0
  struct socket_info_full* sif;
2075
0
  struct sr_module *m;
2076
0
  int n;
2077
2078
  /* instruct tls_mgm to initialize all TLS domains */
2079
0
  for (m=modules; m; m = m->next) {
2080
0
    if (strcmp(m->exports->name, "tls_mgm") == 0)
2081
0
      if (init_child(PROC_TCP_MAIN) < 0) {
2082
0
        LM_ERR("error in init_child for PROC_TCP_MAIN\n");
2083
0
        goto error;
2084
0
      }
2085
0
  }
2086
2087
  /* we run in a separate, dedicated process, with its own reactor
2088
   * (reactors are per process) */
2089
0
  if (init_worker_reactor("TCP_main", RCT_PRIO_MAX)<0)
2090
0
    goto error;
2091
2092
  /* now start watching all the fds */
2093
2094
  /* add all the sockets we listens on for connections */
2095
0
  for (n = PROTO_FIRST; n < PROTO_LAST; n++)
2096
0
    if (is_tcp_based_proto(n))
2097
0
      for (sif = protos[n].listeners; sif; sif = sif->next) {
2098
0
        struct socket_info* si = &sif->socket_info;
2099
0
        if (protos[n].tran.bind_listener &&
2100
0
            protos[n].tran.bind_listener(si) < 0) {
2101
0
          LM_ERR("failed to bind listener [%.*s], proto %s\n",
2102
0
            si->name.len, si->name.s, protos[n].name);
2103
0
          goto error;
2104
0
        }
2105
0
        if (si->socket != -1 &&
2106
0
            reactor_add_reader(si->socket, F_TCP_LISTENER,
2107
0
              RCT_PRIO_NET, si) < 0) {
2108
0
          LM_ERR("failed to add listen socket to reactor\n");
2109
0
          goto error;
2110
0
        }
2111
0
      }
2112
  /* init: start watching for the IPC jobs */
2113
0
  if (reactor_add_reader(IPC_FD_READ_SELF, F_IPC, RCT_PRIO_ASYNC, NULL)<0){
2114
0
    LM_CRIT("failed to add IPC pipe to reactor\n");
2115
0
    goto error;
2116
0
  }
2117
2118
0
  if (tcp_pool_init() < 0)
2119
0
    goto error;
2120
2121
0
  is_tcp_main = 1;
2122
2123
  /* main loop (requires "handle_io()" implementation) */
2124
0
  reactor_main_loop( TCP_MAIN_SELECT_TIMEOUT, error,
2125
0
      tcpconn_lifetime(last_sec) );
2126
2127
0
error:
2128
0
  tcp_pool_destroy();
2129
0
  destroy_worker_reactor();
2130
0
  LM_CRIT("exiting...");
2131
0
  exit(-1);
2132
0
}
2133
2134
2135
2136
/**************************** Control functions ******************************/
2137
2138
/* initializes the TCP network level in terms of data structures */
2139
int tcp_init(void)
2140
0
{
2141
0
  unsigned int i;
2142
2143
  /* first we do auto-detection to see if there are any TCP based
2144
   * protocols loaded */
2145
0
  for ( i=PROTO_FIRST ; i<PROTO_LAST ; i++ )
2146
0
    if (is_tcp_based_proto(i) && proto_has_listeners(i)) {
2147
0
      tcp_disabled=0;
2148
0
      break;
2149
0
    }
2150
2151
0
  tcp_init_con_profiles();
2152
2153
0
  if (tcp_disabled)
2154
0
    return 0;
2155
2156
#ifdef DBG_TCPCON
2157
  con_hist = shl_init("TCP con", 10000, 0);
2158
  if (!con_hist) {
2159
    LM_ERR("oom con hist\n");
2160
    goto error;
2161
  }
2162
#endif
2163
2164
0
  if (tcp_auto_scaling_profile) {
2165
0
    s_profile = get_scaling_profile(tcp_auto_scaling_profile);
2166
0
    if (s_profile==NULL) {
2167
0
      LM_WARN("TCP scaling profile <%s> not defined "
2168
0
        "-> ignoring it...\n", tcp_auto_scaling_profile);
2169
0
    } else {
2170
0
      auto_scaling_enabled = 1;
2171
0
    }
2172
0
  }
2173
2174
0
  tcp_workers_max_no = (s_profile && (tcp_workers_no<s_profile->max_procs)) ?
2175
0
    s_profile->max_procs : tcp_workers_no ;
2176
2177
  /* init tcp workers array */
2178
0
  tcp_workers = (struct tcp_worker*)shm_malloc
2179
0
    ( tcp_workers_max_no*sizeof(struct tcp_worker) );
2180
0
  if (tcp_workers==0) {
2181
0
    LM_CRIT("could not alloc tcp_workers array in shm memory\n");
2182
0
    goto error;
2183
0
  }
2184
0
  memset( tcp_workers, 0, tcp_workers_max_no*sizeof(struct tcp_worker));
2185
  /* init globals */
2186
0
  connection_id=(unsigned int*)shm_malloc(sizeof(unsigned int));
2187
0
  if (connection_id==0){
2188
0
    LM_CRIT("could not alloc globals in shm memory\n");
2189
0
    goto error;
2190
0
  }
2191
  // The  rand()  function returns a pseudo-random integer in the range 0 to
2192
  // RAND_MAX inclusive (i.e., the mathematical range [0, RAND_MAX]).
2193
0
  *connection_id=(unsigned int)rand();
2194
0
  connection_id_lock=lock_alloc();
2195
0
  if (connection_id_lock==0){
2196
0
    LM_CRIT("could not alloc connection ID lock\n");
2197
0
    goto error;
2198
0
  }
2199
0
  if (lock_init(connection_id_lock)==0){
2200
0
    LM_CRIT("could not init connection ID lock\n");
2201
0
    lock_dealloc((void*)connection_id_lock);
2202
0
    connection_id_lock=0;
2203
0
    goto error;
2204
0
  }
2205
0
  tcp_connections_no = (unsigned int *)shm_malloc(sizeof(*tcp_connections_no));
2206
0
  if (tcp_connections_no == 0) {
2207
0
    LM_CRIT("could not alloc tcp connection counter in shm memory\n");
2208
0
    goto error;
2209
0
  }
2210
0
  *tcp_connections_no = 0;
2211
0
  tcp_main_proc_no = (int *)shm_malloc(sizeof(*tcp_main_proc_no));
2212
0
  if (tcp_main_proc_no == 0) {
2213
0
    LM_CRIT("could not alloc tcp main proc slot in shm memory\n");
2214
0
    goto error;
2215
0
  }
2216
0
  *tcp_main_proc_no = -1;
2217
0
  tcp_write_queue = shm_malloc(sizeof(*tcp_write_queue));
2218
0
  if (tcp_write_queue == 0) {
2219
0
    LM_CRIT("could not alloc tcp shared write queue in shm memory\n");
2220
0
    goto error;
2221
0
  }
2222
0
  memset(tcp_write_queue, 0, sizeof(*tcp_write_queue));
2223
0
  if (cond_init(&tcp_write_queue->cond) != 0) {
2224
0
    LM_CRIT("could not init tcp shared write queue cond\n");
2225
0
    shm_free(tcp_write_queue);
2226
0
    tcp_write_queue = 0;
2227
0
    goto error;
2228
0
  }
2229
0
  tcp_connections_lock = lock_alloc();
2230
0
  if (tcp_connections_lock == 0) {
2231
0
    LM_CRIT("could not alloc tcp connection counter lock\n");
2232
0
    goto error;
2233
0
  }
2234
0
  if (lock_init(tcp_connections_lock) == 0) {
2235
0
    LM_CRIT("could not init tcp connection counter lock\n");
2236
0
    lock_dealloc((void *)tcp_connections_lock);
2237
0
    tcp_connections_lock = 0;
2238
0
    goto error;
2239
0
  }
2240
0
  memset( &tcp_parts, 0, TCP_PARTITION_SIZE*sizeof(struct tcp_partition));
2241
  /* init partitions */
2242
0
  for( i=0 ; i<TCP_PARTITION_SIZE ; i++ ) {
2243
    /* init lock */
2244
0
    tcp_parts[i].tcpconn_lock=lock_alloc();
2245
0
    if (tcp_parts[i].tcpconn_lock==0){
2246
0
      LM_CRIT("could not alloc lock\n");
2247
0
      goto error;
2248
0
    }
2249
0
    if (lock_init(tcp_parts[i].tcpconn_lock)==0){
2250
0
      LM_CRIT("could not init lock\n");
2251
0
      lock_dealloc((void*)tcp_parts[i].tcpconn_lock);
2252
0
      tcp_parts[i].tcpconn_lock=0;
2253
0
      goto error;
2254
0
    }
2255
    /* alloc hashtables*/
2256
0
    tcp_parts[i].tcpconn_aliases_hash=(struct tcp_conn_alias**)
2257
0
      shm_malloc(TCP_ALIAS_HASH_SIZE* sizeof(struct tcp_conn_alias*));
2258
0
    if (tcp_parts[i].tcpconn_aliases_hash==0){
2259
0
      LM_CRIT("could not alloc address hashtable in shm memory\n");
2260
0
      goto error;
2261
0
    }
2262
0
    tcp_parts[i].tcpconn_id_hash=(struct tcp_connection**)
2263
0
      shm_malloc(TCP_ID_HASH_SIZE*sizeof(struct tcp_connection*));
2264
0
    if (tcp_parts[i].tcpconn_id_hash==0){
2265
0
      LM_CRIT("could not alloc id hashtable in shm memory\n");
2266
0
      goto error;
2267
0
    }
2268
    /* init hashtables*/
2269
0
    memset((void*)tcp_parts[i].tcpconn_aliases_hash, 0,
2270
0
      TCP_ALIAS_HASH_SIZE * sizeof(struct tcp_conn_alias*));
2271
0
    memset((void*)tcp_parts[i].tcpconn_id_hash, 0,
2272
0
      TCP_ID_HASH_SIZE * sizeof(struct tcp_connection*));
2273
0
  }
2274
2275
0
  return 0;
2276
0
error:
2277
  /* clean-up */
2278
0
  tcp_destroy();
2279
0
  return -1;
2280
0
}
2281
2282
2283
/* destroys the TCP data */
2284
void tcp_destroy(void)
2285
0
{
2286
0
  int part;
2287
2288
0
  if (tcp_parts[0].tcpconn_id_hash)
2289
      /* force close/expire for all active tcpconns*/
2290
0
      __tcpconn_lifetime(1);
2291
2292
0
  if (connection_id){
2293
0
    shm_free(connection_id);
2294
0
    connection_id=0;
2295
0
  }
2296
2297
0
  if (tcp_connections_no) {
2298
0
    shm_free(tcp_connections_no);
2299
0
    tcp_connections_no = 0;
2300
0
  }
2301
2302
0
  if (tcp_main_proc_no) {
2303
0
    shm_free(tcp_main_proc_no);
2304
0
    tcp_main_proc_no = 0;
2305
0
  }
2306
2307
0
  if (tcp_dispatch_sock[0] >= 0) {
2308
0
    close(tcp_dispatch_sock[0]);
2309
0
    tcp_dispatch_sock[0] = -1;
2310
0
  }
2311
0
  if (tcp_dispatch_sock[1] >= 0) {
2312
0
    close(tcp_dispatch_sock[1]);
2313
0
    tcp_dispatch_sock[1] = -1;
2314
0
  }
2315
2316
0
  if (tcp_write_queue) {
2317
    /* Skip cond teardown during attendant shutdown. */
2318
    /* cond_destroy(&tcp_write_queue->cond); */
2319
0
    shm_free(tcp_write_queue);
2320
0
    tcp_write_queue = 0;
2321
0
  }
2322
2323
0
  if (tcp_connections_lock) {
2324
0
    lock_destroy(tcp_connections_lock);
2325
0
    lock_dealloc((void *)tcp_connections_lock);
2326
0
    tcp_connections_lock = 0;
2327
0
  }
2328
2329
0
  if (connection_id_lock){
2330
0
    lock_destroy(connection_id_lock);
2331
0
    lock_dealloc((void*)connection_id_lock);
2332
0
    connection_id_lock=0;
2333
0
  }
2334
2335
0
  for ( part=0 ; part<TCP_PARTITION_SIZE ; part++ ) {
2336
0
    if (tcp_parts[part].tcpconn_id_hash){
2337
0
      shm_free(tcp_parts[part].tcpconn_id_hash);
2338
0
      tcp_parts[part].tcpconn_id_hash=0;
2339
0
    }
2340
0
    if (tcp_parts[part].tcpconn_aliases_hash){
2341
0
      shm_free(tcp_parts[part].tcpconn_aliases_hash);
2342
0
      tcp_parts[part].tcpconn_aliases_hash=0;
2343
0
    }
2344
0
    if (tcp_parts[part].tcpconn_lock){
2345
0
      lock_destroy(tcp_parts[part].tcpconn_lock);
2346
0
      lock_dealloc((void*)tcp_parts[part].tcpconn_lock);
2347
0
      tcp_parts[part].tcpconn_lock=0;
2348
0
    }
2349
0
  }
2350
0
}
2351
2352
2353
static int _get_own_tcp_worker_id(void)
2354
0
{
2355
0
  pid_t pid;
2356
0
  int i;
2357
2358
0
  pid = getpid();
2359
0
  for( i=0 ; i<tcp_workers_max_no ; i++)
2360
0
    if(tcp_workers[i].pid==pid)
2361
0
      return i;
2362
2363
0
  return -1;
2364
0
}
2365
2366
2367
void tcp_reset_worker_slot(void)
2368
0
{
2369
0
  int i;
2370
2371
0
  if ((i=_get_own_tcp_worker_id())>=0) {
2372
0
    tcp_workers[i].state=STATE_INACTIVE;
2373
0
    tcp_workers[i].pid=0;
2374
0
    tcp_workers[i].pt_idx=0;
2375
0
  }
2376
0
}
2377
2378
2379
static int fork_dynamic_tcp_process(void *foo)
2380
0
{
2381
0
  int p_id;
2382
0
  int r;
2383
0
  const struct internal_fork_params ifp_sr_tcp = {
2384
0
    .proc_desc = "SIP receiver TCP",
2385
0
    .flags = OSS_PROC_DYNAMIC|OSS_PROC_NEEDS_SCRIPT,
2386
0
    .type = TYPE_TCP,
2387
0
  };
2388
2389
  /* search for a free slot in the TCP workers table */
2390
0
  for (r = 0; r < tcp_workers_max_no; r++)
2391
0
    if (tcp_workers[r].state == STATE_INACTIVE)
2392
0
      break;
2393
2394
0
  if (r == tcp_workers_max_no) {
2395
0
    LM_BUG("trying to fork one more TCP worker but no free slot in "
2396
0
      "the TCP table (size=%d)\n", tcp_workers_max_no);
2397
0
    return -1;
2398
0
  }
2399
2400
0
  if ((p_id = internal_fork(&ifp_sr_tcp)) < 0) {
2401
0
    LM_ERR("cannot fork dynamic TCP worker process\n");
2402
0
    return -1;
2403
0
  } else if (p_id == 0) {
2404
    /* new TCP worker process */
2405
0
    if (tcp_dispatch_sock[1] >= 0)
2406
0
      close(tcp_dispatch_sock[1]);
2407
0
    tcp_dispatch_sock[1] = -1;
2408
2409
0
    set_proc_attrs("TCP receiver");
2410
0
    tcp_workers[r].pid = getpid();
2411
2412
0
    if (tcp_worker_proc_reactor_init(tcp_dispatch_sock[0]) < 0 ||
2413
0
    init_child(20000) ||
2414
0
    self_update_routing_script() < 0)
2415
0
      goto error;
2416
2417
0
    report_conditional_status(1, 0);
2418
0
    clean_read_pipeend();
2419
2420
0
    tcp_worker_proc_loop();
2421
0
    destroy_worker_reactor();
2422
2423
0
error:
2424
0
    report_failure_status();
2425
0
    LM_ERR("initializing new TCP worker failed, exiting with error\n");
2426
0
    pt[process_no].flags |= OSS_PROC_SELFEXIT;
2427
0
    exit(-1);
2428
0
  } else {
2429
    /* parent/attendant */
2430
0
    tcp_workers[r].state = STATE_ACTIVE;
2431
0
    tcp_workers[r].pt_idx = p_id;
2432
0
    return p_id;
2433
0
  }
2434
2435
0
  return 0;
2436
0
}
2437
2438
2439
static void tcp_process_graceful_terminate(int sender, void *param)
2440
0
{
2441
0
  int i;
2442
2443
  /* accept this only from the attendant process */
2444
0
  if (sender != 0) {
2445
0
    LM_BUG("graceful terminate received from a non-main process\n");
2446
0
    return;
2447
0
  }
2448
0
  LM_NOTICE("process %d received RPC to terminate from Main\n", process_no);
2449
2450
  /* reserve this slot until tcp_terminate_worker() detaches the process
2451
   * from the shared dispatch queue and completes its pending async work */
2452
0
  if ((i = _get_own_tcp_worker_id()) >= 0)
2453
0
    tcp_workers[i].state = STATE_DRAINING;
2454
2455
0
  tcp_terminate_worker();
2456
0
}
2457
2458
2459
/* counts the number of TCP processes to start with; this number may
2460
 * change during runtime due auto-scaling */
2461
int tcp_count_processes(unsigned int *extra)
2462
0
{
2463
0
  if (extra) *extra = 0;
2464
2465
0
  if (tcp_disabled)
2466
0
    return 0;
2467
2468
0
  if (s_profile && extra && s_profile->max_procs > tcp_workers_no)
2469
0
    *extra = s_profile->max_procs - tcp_workers_no;
2470
2471
0
  return 1 /* tcp main / IO process */ + tcp_workers_no /* dispatch workers */;
2472
0
}
2473
2474
2475
int tcp_start_processes(int *chd_rank, int *startup_done)
2476
0
{
2477
0
  int r, p_id, flags;
2478
0
  const struct internal_fork_params ifp_sr_tcp = {
2479
0
    .proc_desc = "SIP receiver TCP",
2480
0
    .flags = OSS_PROC_NEEDS_SCRIPT,
2481
0
    .type = TYPE_TCP,
2482
0
  };
2483
2484
0
  if (tcp_disabled)
2485
0
    return 0;
2486
2487
  /* create the shared dispatch socket from TCP main to TCP workers */
2488
0
  if (socketpair(AF_UNIX, SOCK_DGRAM, 0, tcp_dispatch_sock) < 0) {
2489
0
    LM_ERR("socketpair failed for TCP worker dispatch: %s\n",
2490
0
      strerror(errno));
2491
0
    goto error;
2492
0
  }
2493
0
  flags = fcntl(tcp_dispatch_sock[0], F_GETFL);
2494
0
  if (flags == -1) {
2495
0
    LM_ERR("fcntl failed for TCP worker dispatch socket: %s\n",
2496
0
      strerror(errno));
2497
0
    goto error;
2498
0
  }
2499
0
  if (fcntl(tcp_dispatch_sock[0], F_SETFL, flags | O_NONBLOCK) == -1) {
2500
0
    LM_ERR("failed to set non-blocking on TCP worker dispatch socket: %s\n",
2501
0
      strerror(errno));
2502
0
    goto error;
2503
0
  }
2504
0
  flags = fcntl(tcp_dispatch_sock[1], F_GETFL);
2505
0
  if (flags == -1) {
2506
0
    LM_ERR("fcntl failed for TCP worker dispatch socket: %s\n",
2507
0
      strerror(errno));
2508
0
    goto error;
2509
0
  }
2510
0
  if (fcntl(tcp_dispatch_sock[1], F_SETFL, flags | O_NONBLOCK) == -1) {
2511
0
    LM_ERR("failed to set non-blocking on TCP worker dispatch socket: %s\n",
2512
0
      strerror(errno));
2513
0
    goto error;
2514
0
  }
2515
2516
0
  if (auto_scaling_enabled && s_profile &&
2517
0
  create_process_group(TYPE_TCP, NULL, s_profile,
2518
0
    fork_dynamic_tcp_process, tcp_process_graceful_terminate) != 0)
2519
0
    LM_ERR("failed to create TCP auto-scaling process group; "
2520
0
      "automatic scaling will not be possible\n");
2521
2522
0
  for (r = 0; r < tcp_workers_no; r++) {
2523
0
    (*chd_rank)++;
2524
0
    p_id = internal_fork(&ifp_sr_tcp);
2525
0
    if (p_id < 0) {
2526
0
      LM_ERR("cannot fork TCP worker process %d\n", r);
2527
0
      goto error;
2528
0
    } else if (p_id > 0) {
2529
      /* parent */
2530
0
      tcp_workers[r].state = STATE_ACTIVE;
2531
0
      tcp_workers[r].pt_idx = p_id;
2532
0
      continue;
2533
0
    }
2534
2535
    /* child */
2536
0
    if (tcp_dispatch_sock[1] >= 0)
2537
0
      close(tcp_dispatch_sock[1]);
2538
0
    tcp_dispatch_sock[1] = -1;
2539
2540
0
    set_proc_attrs("TCP receiver");
2541
0
    tcp_workers[r].pid = getpid();
2542
2543
0
    if (tcp_worker_proc_reactor_init(tcp_dispatch_sock[0]) < 0 ||
2544
0
        init_child(*chd_rank) < 0) {
2545
0
      LM_ERR("init_child failed for TCP worker %d\n", r);
2546
0
      report_failure_status();
2547
0
      if (startup_done)
2548
0
        *startup_done = -1;
2549
0
      exit(-1);
2550
0
    }
2551
2552
    /* first TCP worker runs startup_route if not already run */
2553
0
    if (startup_done && *startup_done == 0 && r == 0) {
2554
0
      LM_DBG("running startup route for first TCP worker\n");
2555
0
      if (run_startup_route() < 0) {
2556
0
        LM_ERR("startup route processing failed in TCP worker\n");
2557
0
        report_failure_status();
2558
0
        *startup_done = -1;
2559
0
        exit(-1);
2560
0
      }
2561
0
      *startup_done = 1;
2562
0
    }
2563
2564
0
    report_conditional_status((!no_daemon_mode), 0);
2565
0
    tcp_worker_proc_loop();
2566
0
  }
2567
2568
  /* Keep the worker endpoint in the attendant when auto-scaling is enabled,
2569
   * so dynamically forked TCP workers can inherit the shared queue. */
2570
0
  if (!s_profile && tcp_dispatch_sock[0] >= 0) {
2571
0
    close(tcp_dispatch_sock[0]);
2572
0
    tcp_dispatch_sock[0] = -1;
2573
0
  }
2574
2575
0
  if (startup_done && tcp_workers_no > 0)
2576
0
    while (!(*startup_done)) {
2577
0
      usleep(5);
2578
0
      handle_sigs();
2579
0
    }
2580
2581
0
  return 0;
2582
0
error:
2583
0
  if (tcp_dispatch_sock[0] >= 0) {
2584
0
    close(tcp_dispatch_sock[0]);
2585
0
    tcp_dispatch_sock[0] = -1;
2586
0
  }
2587
0
  if (tcp_dispatch_sock[1] >= 0) {
2588
0
    close(tcp_dispatch_sock[1]);
2589
0
    tcp_dispatch_sock[1] = -1;
2590
0
  }
2591
0
  return -1;
2592
0
}
2593
2594
static int tcpconn_update_local_port(struct tcp_connection *tcpconn)
2595
0
{
2596
0
  union sockaddr_union local_su;
2597
0
  socklen_t su_size;
2598
2599
0
  su_size = sockaddru_len(tcpconn->rcv.src_su);
2600
0
  if (getsockname(tcpconn->fd, (struct sockaddr *)&local_su, &su_size) < 0) {
2601
0
    LM_ERR("failed to get local socket info on conn %u: %s\n",
2602
0
      tcpconn->id, strerror(errno));
2603
0
    return -1;
2604
0
  }
2605
2606
0
  tcpconn->rcv.dst_port = su_getport(&local_su);
2607
0
  return 0;
2608
0
}
2609
2610
static int tcpconn_prepare_write(struct tcp_connection *tcpconn)
2611
0
{
2612
0
  int fd;
2613
0
  int connected = 0;
2614
2615
0
  if ((tcpconn->flags & F_CONN_INIT) == 0) {
2616
0
    if (protos[tcpconn->type].net.stream.conn.init &&
2617
0
        protos[tcpconn->type].net.stream.conn.init(tcpconn) < 0) {
2618
0
      LM_ERR("failed to init proto %d conn %p in TCP main\n",
2619
0
        tcpconn->type, tcpconn);
2620
0
      return -1;
2621
0
    }
2622
0
    tcpconn->flags |= F_CONN_INIT;
2623
0
  }
2624
2625
0
  if (tcpconn->fd < 0) {
2626
0
    if (!tcpconn->rcv.bind_address) {
2627
0
      LM_ERR("missing bind_address for outbound conn %u\n", tcpconn->id);
2628
0
      return -1;
2629
0
    }
2630
2631
0
    fd = tcp_sync_connect_fd(&tcpconn->rcv.bind_address->su,
2632
0
        &tcpconn->rcv.src_su, tcpconn->type, &tcpconn->profile,
2633
0
        tcpconn->rcv.bind_address->flags,
2634
0
        tcpconn->rcv.bind_address->tos);
2635
0
    if (fd < 0)
2636
0
      return -1;
2637
2638
0
    tcpconn->fd = fd;
2639
0
    if (tcpconn_update_local_port(tcpconn) < 0) {
2640
0
      close(fd);
2641
0
      tcpconn->fd = -1;
2642
0
      return -1;
2643
0
    }
2644
2645
0
    tcpconn->state = S_CONN_OK;
2646
0
    connected = 1;
2647
0
  }
2648
2649
0
  if (connected && protos[tcpconn->type].net.stream.conn.connect) {
2650
0
    if (protos[tcpconn->type].net.stream.conn.connect(tcpconn) < 0) {
2651
0
      LM_ERR("failed to finish proto %d connect on conn %u\n",
2652
0
        tcpconn->type, tcpconn->id);
2653
0
      return -1;
2654
0
    }
2655
0
  }
2656
2657
0
  return 0;
2658
0
}
2659
2660
2661
int tcp_start_listener(void)
2662
0
{
2663
0
  int p_id;
2664
0
  const struct internal_fork_params ifp_tcp_main = {
2665
0
    .proc_desc = "TCP main",
2666
0
    .flags = 0,
2667
0
    .type = TYPE_NONE,
2668
0
  };
2669
2670
0
  if (tcp_disabled)
2671
0
    return 0;
2672
2673
  /* start the TCP manager process */
2674
0
  if ( (p_id=internal_fork(&ifp_tcp_main))<0 ) {
2675
0
    LM_CRIT("cannot fork tcp main process\n");
2676
0
    goto error;
2677
0
  }else if (p_id==0){
2678
      /* child */
2679
0
    report_conditional_status( (!no_daemon_mode), 0);
2680
2681
0
    tcp_main_server();
2682
0
    exit(-1);
2683
0
  }
2684
0
  *tcp_main_proc_no = p_id;
2685
2686
0
  return 0;
2687
0
error:
2688
0
  return -1;
2689
0
}
2690
2691
int tcp_has_async_write(void)
2692
0
{
2693
0
  return reactor_has_async();
2694
0
}
2695
2696
static int tcp_close_conn_run(void *data)
2697
0
{
2698
0
  struct tcp_connection *conn = data;
2699
2700
0
  if (!conn)
2701
0
    return -1;
2702
2703
  /* take the fd out of the reactor before it is closed, as every other
2704
   * TCP main destroy path does - otherwise the stale entry captures the
2705
   * next connection that reuses the fd number */
2706
0
  if ((conn->main_flags & F_TCP_MAIN_REMOVED) !=
2707
0
      F_TCP_MAIN_REMOVED &&
2708
0
      conn->fd != -1) {
2709
0
    reactor_del_all(conn->fd, -1, IO_FD_CLOSING);
2710
0
    conn->main_flags |= F_TCP_MAIN_REMOVED;
2711
0
  }
2712
2713
0
  tcp_conn_destroy(conn);
2714
0
  return 0;
2715
0
}
2716
2717
static void tcp_close_conn_rpc(int pid, void *param)
2718
0
{
2719
0
  tcp_close_conn_run(param);
2720
0
}
2721
2722
int tcp_close_connection(str *ipport)
2723
0
{
2724
0
  struct tcp_connection *conn = NULL;
2725
0
  struct ip_addr *ip;
2726
0
  str host;
2727
0
  unsigned int id;
2728
0
  int port, proto, rc, tcp_main_proc;
2729
0
  int start_proto, end_proto;
2730
0
  unsigned int p;
2731
0
  char *sep;
2732
2733
0
  if (tcp_disabled)
2734
0
    return 0;
2735
2736
0
  sep = q_memchr(ipport->s, ':', ipport->len);
2737
0
  if (!sep) {
2738
0
    if (str2int(ipport, &id) < 0) {
2739
0
      LM_ERR("failed to parse tcp connection [%.*s]\n",
2740
0
        ipport->len, ipport->s);
2741
0
      return -1;
2742
0
    }
2743
2744
0
    switch (tcp_conn_get(id, NULL, 0, PROTO_NONE, NULL, &conn, NULL)) {
2745
0
    case 1:
2746
0
      goto found;
2747
0
    case -1:
2748
0
      return -1;
2749
0
    default:
2750
0
      return 0;
2751
0
    }
2752
0
  }
2753
2754
0
  if (parse_phostport(ipport->s, ipport->len, &host.s, &host.len,
2755
0
  &port, &proto) != 0 || port <= 0) {
2756
0
    LM_ERR("failed to parse tcp connection [%.*s]\n",
2757
0
      ipport->len, ipport->s);
2758
0
    return -1;
2759
0
  }
2760
2761
0
  ip = str2ip(&host);
2762
0
  if (!ip)
2763
0
    ip = str2ip6(&host);
2764
0
  if (!ip) {
2765
0
    LM_ERR("invalid IP in tcp connection [%.*s]\n",
2766
0
      ipport->len, ipport->s);
2767
0
    return -1;
2768
0
  }
2769
2770
0
  if (proto != PROTO_NONE) {
2771
0
    if (!is_tcp_based_proto(proto)) {
2772
0
      LM_ERR("protocol %d is not TCP based for [%.*s]\n",
2773
0
        proto, ipport->len, ipport->s);
2774
0
      return -1;
2775
0
    }
2776
0
    start_proto = proto;
2777
0
    end_proto = proto + 1;
2778
0
  } else {
2779
0
    start_proto = 0;
2780
0
    end_proto = PROTO_LAST;
2781
0
  }
2782
2783
0
  for (p = start_proto; p < (unsigned int)end_proto; p++) {
2784
0
    if (!is_tcp_based_proto(p))
2785
0
      continue;
2786
2787
0
    switch (tcp_conn_get(0, ip, port, p, NULL, &conn, NULL)) {
2788
0
    case 1:
2789
0
      goto found;
2790
0
    case -1:
2791
0
      return -1;
2792
0
    }
2793
0
  }
2794
2795
0
  return 0;
2796
2797
0
found:
2798
0
  TCPCONN_LOCK(conn->id);
2799
0
  conn->flags |= F_CONN_FORCE_CLOSED;
2800
0
  TCPCONN_UNLOCK(conn->id);
2801
2802
0
  tcp_main_proc = tcp_get_main_proc_no();
2803
0
  if (tcp_main_proc < 0)
2804
0
    rc = -1;
2805
0
  else if (process_no == tcp_main_proc)
2806
0
    rc = tcp_close_conn_run(conn);
2807
0
  else
2808
0
    rc = ipc_send_rpc(tcp_main_proc, tcp_close_conn_rpc, conn);
2809
2810
0
  if (rc < 0) {
2811
0
    TCPCONN_LOCK(conn->id);
2812
0
    conn->flags &= ~F_CONN_FORCE_CLOSED;
2813
0
    TCPCONN_UNLOCK(conn->id);
2814
0
    tcp_conn_release(conn, 0);
2815
0
    return -1;
2816
0
  }
2817
2818
0
  return 1;
2819
0
}
2820
2821
2822
int tcp_conn_traverse(tcp_conn_traverse_f cb, void *arg)
2823
0
{
2824
0
  struct tcp_connection *conn;
2825
0
  unsigned int part, i;
2826
0
  int rc;
2827
2828
0
  if (!cb || tcp_disabled)
2829
0
    return 0;
2830
2831
0
  for (part = 0; part < TCP_PARTITION_SIZE; part++) {
2832
0
    TCPCONN_LOCK(part);
2833
0
    for (i = 0; i < TCP_ID_HASH_SIZE; i++) {
2834
0
      for (conn = TCP_PART(part).tcpconn_id_hash[i]; conn;
2835
0
          conn = conn->id_next) {
2836
0
        rc = cb(conn, arg);
2837
0
        if (rc) {
2838
0
          TCPCONN_UNLOCK(part);
2839
0
          return rc;
2840
0
        }
2841
0
      }
2842
0
    }
2843
0
    TCPCONN_UNLOCK(part);
2844
0
  }
2845
2846
0
  return 0;
2847
0
}
2848
2849
2850
/***************************** MI functions **********************************/
2851
2852
mi_response_t *mi_tcp_list_conns(const mi_params_t *params,
2853
            struct mi_handler *async_hdl)
2854
0
{
2855
0
  mi_response_t *resp;
2856
0
  mi_item_t *resp_obj;
2857
0
  mi_item_t *conns_arr, *conn_item;
2858
0
  struct tcp_connection *conn;
2859
0
  time_t _ts;
2860
0
  char date_buf[MI_DATE_BUF_LEN];
2861
0
  int date_buf_len;
2862
0
  unsigned int i,j,part;
2863
0
  char proto_buf[PROTO_NAME_MAX_SIZE];
2864
0
  char *proto_s;
2865
0
  int proto_len;
2866
0
  int proto_filter = PROTO_NONE;
2867
0
  int filter_by_proto = 0;
2868
0
  str proto_name;
2869
0
  struct tm ltime;
2870
0
  char *p;
2871
2872
0
  if (tcp_disabled)
2873
0
    return init_mi_result_null();
2874
2875
0
  switch (try_get_mi_string_param(params, "proto", &proto_s, &proto_len)) {
2876
0
  case 0:
2877
0
    proto_name.s = proto_s;
2878
0
    proto_name.len = proto_len;
2879
2880
0
    if (proto_len == 3 && str_strcasecmp(&proto_name, _str("any")) == 0)
2881
0
      ;
2882
0
    else if (parse_proto((unsigned char *)proto_s, proto_len,
2883
0
        (int *)&proto_filter) < 0)
2884
0
      return init_mi_error(400, MI_SSTR("Bad protocol"));
2885
0
    else
2886
0
      filter_by_proto = 1;
2887
0
    break;
2888
0
  case -1:
2889
0
    break;
2890
0
  default:
2891
0
    return init_mi_param_error();
2892
0
  }
2893
2894
0
  resp = init_mi_result_object(&resp_obj);
2895
0
  if (!resp)
2896
0
    return 0;
2897
2898
0
  conns_arr = add_mi_array(resp_obj, MI_SSTR("Connections"));
2899
0
  if (!conns_arr) {
2900
0
    free_mi_response(resp);
2901
0
    return 0;
2902
0
  }
2903
2904
0
  for( part=0 ; part<TCP_PARTITION_SIZE ; part++) {
2905
0
    TCPCONN_LOCK(part);
2906
0
    for( i=0; i<TCP_ID_HASH_SIZE ; i++ ) {
2907
0
      for(conn=TCP_PART(part).tcpconn_id_hash[i];conn;conn=conn->id_next){
2908
0
        if (filter_by_proto && conn->type != proto_filter)
2909
0
          continue;
2910
2911
        /* add one object fo each conn */
2912
0
        conn_item = add_mi_object(conns_arr, 0, 0);
2913
0
        if (!conn_item)
2914
0
          goto error;
2915
2916
        /* add ID */
2917
0
        if (add_mi_number(conn_item, MI_SSTR("ID"), conn->id) < 0)
2918
0
          goto error;
2919
2920
        /* add type/proto */
2921
0
        p = proto2str(conn->type, proto_buf);
2922
0
        if (add_mi_string(conn_item, MI_SSTR("Type"), proto_buf,
2923
0
          (int)(long)(p-proto_buf)) < 0)
2924
0
          goto error;
2925
2926
        /* add state */
2927
0
        if (add_mi_number(conn_item, MI_SSTR("State"), conn->state) < 0)
2928
0
          goto error;
2929
2930
        /* add Remote IP:Port */
2931
0
        if (add_mi_string_fmt(conn_item, MI_SSTR("Remote"), "%s:%d",
2932
0
          ip_addr2a(&conn->rcv.src_ip), conn->rcv.src_port) < 0)
2933
0
          goto error;
2934
2935
        /* add Local IP:Port */
2936
0
        if (add_mi_string_fmt(conn_item, MI_SSTR("Local"), "%s:%d",
2937
0
          ip_addr2a(&conn->rcv.dst_ip), conn->rcv.dst_port) < 0)
2938
0
          goto error;
2939
2940
0
        if (protos[conn->type].net.stream.conn.dump &&
2941
0
            protos[conn->type].net.stream.conn.dump(conn,
2942
0
              conn_item) < 0)
2943
0
          goto error;
2944
2945
        /* add lifetime */
2946
0
        _ts = (time_t)conn->lifetime + startup_time;
2947
0
        localtime_r(&_ts, &ltime);
2948
0
        date_buf_len = strftime(date_buf, MI_DATE_BUF_LEN - 1,
2949
0
                    "%Y-%m-%d %H:%M:%S", &ltime);
2950
0
        if (date_buf_len != 0) {
2951
0
          if (add_mi_string(conn_item, MI_SSTR("Lifetime"),
2952
0
            date_buf, date_buf_len) < 0)
2953
0
            goto error;
2954
0
        } else {
2955
0
          if (add_mi_number(conn_item, MI_SSTR("Lifetime"), _ts) < 0)
2956
0
            goto error;
2957
0
        }
2958
2959
        /* add the port-aliases */
2960
0
        for( j=0 ; j<conn->aliases ; j++ )
2961
          /* add one node for each conn */
2962
0
          add_mi_number( conn_item, MI_SSTR("Alias port"),
2963
0
            conn->con_aliases[j].port );
2964
2965
0
      }
2966
0
    }
2967
2968
0
    TCPCONN_UNLOCK(part);
2969
0
  }
2970
2971
0
  return resp;
2972
2973
0
error:
2974
0
  TCPCONN_UNLOCK(part);
2975
0
  LM_ERR("failed to add MI item\n");
2976
0
  free_mi_response(resp);
2977
0
  return 0;
2978
0
}
2979
2980
2981
mi_response_t *mi_tcp_close_conn(const mi_params_t *params,
2982
            struct mi_handler *_)
2983
0
{
2984
0
  str ipport;
2985
0
  int rc;
2986
2987
0
  if (get_mi_string_param(params, "ipport", &ipport.s, &ipport.len) < 0)
2988
0
    return init_mi_param_error();
2989
2990
0
  rc = tcp_close_connection(&ipport);
2991
0
  if (rc < 0)
2992
0
    return init_mi_error(400, MI_SSTR("Bad tcp connection"));
2993
0
  if (rc == 0)
2994
0
    return init_mi_result_null();
2995
2996
0
  return init_mi_result_ok();
2997
0
}