source: verona/libeXosip2/src/eXtl_tcp.c @ 131:acaf0886270b

Last change on this file since 131:acaf0886270b was 131:acaf0886270b, checked in by Vadim Lebedev <vadim@…>, 2 years ago

BIG patch to bring old verona to the XXX level

File size: 28.5 KB
Line 
1/*
2  eXosip - This is the eXtended osip library.
3  Copyright (C) 2002,2003,2004,2005,2006,2007  Aymeric MOIZARD  - jack@atosc.org
4 
5  eXosip is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9 
10  eXosip is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program; if not, write to the Free Software
17  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18*/
19
20
21#ifdef ENABLE_MPATROL
22#include <mpatrol.h>
23#endif
24
25#include "eXosip2.h"
26#include "eXtransport.h"
27
28#ifdef HAVE_FCNTL_H
29#include <fcntl.h>
30#endif
31
32#ifdef WIN32
33#include <Mstcpip.h>
34#endif
35
36#if defined(_WIN32_WCE) || defined(WIN32)
37#define strerror(X) "-1"
38#define ex_errno WSAGetLastError()
39#else
40#define ex_errno errno
41#endif
42
43#ifndef EAGAIN
44#define EAGAIN WSAEWOULDBLOCK
45#endif
46#ifndef EWOULDBLOCK
47#define EWOULDBLOCK WSAEWOULDBLOCK
48#endif
49
50static int tcp_socket;
51static struct sockaddr_storage ai_addr;
52
53static char tcp_firewall_ip[64];
54static char tcp_firewall_port[10];
55
56/* persistent connection */
57struct _tcp_sockets {
58        int socket;
59        char remote_ip[65];
60        int remote_port;
61        char *previous_content;
62        int previous_content_len;
63};
64
65#define SOCKET_TIMEOUT 0
66
67#ifndef EXOSIP_MAX_SOCKETS
68#define EXOSIP_MAX_SOCKETS 100
69#endif
70
71static struct _tcp_sockets tcp_socket_tab[EXOSIP_MAX_SOCKETS];
72
73static int tcp_tl_init(void)
74{
75        tcp_socket = 0;
76        memset(&ai_addr, 0, sizeof(struct sockaddr_storage));
77        memset(&tcp_socket_tab, 0, sizeof(struct _tcp_sockets) * EXOSIP_MAX_SOCKETS);
78        memset(tcp_firewall_ip, 0, sizeof(tcp_firewall_ip));
79        memset(tcp_firewall_port, 0, sizeof(tcp_firewall_port));
80        return OSIP_SUCCESS;
81}
82
83static int tcp_tl_free(void)
84{
85        int pos;
86        memset(tcp_firewall_ip, 0, sizeof(tcp_firewall_ip));
87        memset(tcp_firewall_port, 0, sizeof(tcp_firewall_port));
88        memset(&ai_addr, 0, sizeof(struct sockaddr_storage));
89        if (tcp_socket > 0)
90                close(tcp_socket);
91
92        for (pos = 0; pos < EXOSIP_MAX_SOCKETS; pos++) {
93                if (tcp_socket_tab[pos].socket > 0) {
94                        close(tcp_socket_tab[pos].socket);
95                }
96        }
97        memset(&tcp_socket_tab, 0, sizeof(struct _tcp_sockets) * EXOSIP_MAX_SOCKETS);
98        return OSIP_SUCCESS;
99}
100
101static int tcp_tl_open(void)
102{
103        int res;
104        struct addrinfo *addrinfo = NULL;
105        struct addrinfo *curinfo;
106        int sock = -1;
107
108        if (eXtl_tcp.proto_port < 0)
109                eXtl_tcp.proto_port = 5060;
110
111
112        res = eXosip_get_addrinfo(&addrinfo,
113                                                          eXtl_tcp.proto_ifs,
114                                                          eXtl_tcp.proto_port, eXtl_tcp.proto_num);
115        if (res)
116                return -1;
117
118        for (curinfo = addrinfo; curinfo; curinfo = curinfo->ai_next) {
119                socklen_t len;
120
121                if (curinfo->ai_protocol && curinfo->ai_protocol != eXtl_tcp.proto_num) {
122                        OSIP_TRACE(osip_trace
123                                           (__FILE__, __LINE__, OSIP_INFO3, NULL,
124                                                "Skipping protocol %d\n", curinfo->ai_protocol));
125                        continue;
126                }
127
128                sock = (int) socket(curinfo->ai_family, curinfo->ai_socktype,
129                                                        curinfo->ai_protocol);
130                if (sock < 0) {
131                        OSIP_TRACE(osip_trace
132                                           (__FILE__, __LINE__, OSIP_ERROR, NULL,
133                                                "Cannot create socket %s!\n", strerror(ex_errno)));
134                        continue;
135                }
136
137                if (curinfo->ai_family == AF_INET6) {
138#ifdef IPV6_V6ONLY
139                        if (setsockopt_ipv6only(sock)) {
140                                close(sock);
141                                sock = -1;
142                                OSIP_TRACE(osip_trace
143                                                   (__FILE__, __LINE__, OSIP_ERROR, NULL,
144                                                        "Cannot set socket option %s!\n", strerror(ex_errno)));
145                                continue;
146                        }
147#endif                                                  /* IPV6_V6ONLY */
148                }
149
150                res = bind(sock, curinfo->ai_addr, curinfo->ai_addrlen);
151                if (res < 0) {
152                        OSIP_TRACE(osip_trace
153                                           (__FILE__, __LINE__, OSIP_ERROR, NULL,
154                                                "Cannot bind socket node:%s family:%d %s\n",
155                                                eXtl_tcp.proto_ifs, curinfo->ai_family,
156                                                strerror(ex_errno)));
157                        close(sock);
158                        sock = -1;
159                        continue;
160                }
161                len = sizeof(ai_addr);
162                res = getsockname(sock, (struct sockaddr *) &ai_addr, &len);
163                if (res != 0) {
164                        OSIP_TRACE(osip_trace
165                                           (__FILE__, __LINE__, OSIP_ERROR, NULL,
166                                                "Cannot get socket name (%s)\n", strerror(ex_errno)));
167                        memcpy(&ai_addr, curinfo->ai_addr, curinfo->ai_addrlen);
168                }
169
170                if (eXtl_tcp.proto_num == IPPROTO_TCP) {
171                        res = listen(sock, SOMAXCONN);
172                        if (res < 0) {
173                                OSIP_TRACE(osip_trace
174                                                   (__FILE__, __LINE__, OSIP_ERROR, NULL,
175                                                        "Cannot bind socket node:%s family:%d %s\n",
176                                                        eXtl_tcp.proto_ifs, curinfo->ai_family,
177                                                        strerror(ex_errno)));
178                                close(sock);
179                                sock = -1;
180                                continue;
181                        }
182                }
183
184                break;
185        }
186
187        eXosip_freeaddrinfo(addrinfo);
188
189        if (sock < 0) {
190                OSIP_TRACE(osip_trace
191                                   (__FILE__, __LINE__, OSIP_ERROR, NULL,
192                                        "Cannot bind on port: %i\n", eXtl_tcp.proto_port));
193                return -1;
194        }
195
196        tcp_socket = sock;
197
198        if (eXtl_tcp.proto_port == 0) {
199                /* get port number from socket */
200                if (eXtl_tcp.proto_family == AF_INET)
201                        eXtl_tcp.proto_port =
202                                ntohs(((struct sockaddr_in *) &ai_addr)->sin_port);
203                else
204                        eXtl_tcp.proto_port =
205                                ntohs(((struct sockaddr_in6 *) &ai_addr)->sin6_port);
206                OSIP_TRACE(osip_trace
207                                   (__FILE__, __LINE__, OSIP_INFO1, NULL,
208                                        "Binding on port %i!\n", eXtl_tcp.proto_port));
209        }
210
211        snprintf(tcp_firewall_port, sizeof(tcp_firewall_port), "%i",
212                         eXtl_tcp.proto_port);
213        return OSIP_SUCCESS;
214}
215
216static int tcp_tl_set_fdset(fd_set * osip_fdset, int *fd_max)
217{
218        int pos;
219        if (tcp_socket <= 0)
220                return -1;
221
222        eXFD_SET(tcp_socket, osip_fdset);
223
224        if (tcp_socket > *fd_max)
225                *fd_max = tcp_socket;
226
227        for (pos = 0; pos < EXOSIP_MAX_SOCKETS; pos++) {
228                if (tcp_socket_tab[pos].socket > 0) {
229                        eXFD_SET(tcp_socket_tab[pos].socket, osip_fdset);
230                        if (tcp_socket_tab[pos].socket > *fd_max)
231                                *fd_max = tcp_socket_tab[pos].socket;
232                }
233        }
234
235        return OSIP_SUCCESS;
236}
237
238static int tcp_tl_read_message(fd_set * osip_fdset)
239{
240        int pos = 0;
241        char *buf;
242
243        if (FD_ISSET(tcp_socket, osip_fdset)) {
244                /* accept incoming connection */
245                char src6host[NI_MAXHOST];
246                int recvport = 0;
247                struct sockaddr_storage sa;
248                int sock;
249                int i;
250
251#ifdef __linux
252                socklen_t slen;
253#else
254                int slen;
255#endif
256                if (eXtl_tcp.proto_family == AF_INET)
257                        slen = sizeof(struct sockaddr_in);
258                else
259                        slen = sizeof(struct sockaddr_in6);
260
261                for (pos = 0; pos < EXOSIP_MAX_SOCKETS; pos++) {
262                        if (tcp_socket_tab[pos].socket == 0)
263                                break;
264                }
265                OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_INFO3, NULL,
266                                                          "creating TCP socket at index: %i\n", pos));
267                sock = accept(tcp_socket, (struct sockaddr *) &sa, &slen);
268                if (sock < 0) {
269                        OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_ERROR, NULL,
270                                                                  "Error accepting TCP socket\n"));
271                } else {
272                        tcp_socket_tab[pos].socket = sock;
273                        OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_INFO1, NULL,
274                                                                  "New TCP connection accepted\n"));
275
276                        memset(src6host, 0, sizeof(src6host));
277
278                        if (eXtl_tcp.proto_family == AF_INET)
279                                recvport = ntohs(((struct sockaddr_in *) &sa)->sin_port);
280                        else
281                                recvport = ntohs(((struct sockaddr_in6 *) &sa)->sin6_port);
282
283#if defined(__arc__)
284                        {
285                                struct sockaddr_in *fromsa = (struct sockaddr_in *) &sa;
286                                char *tmp;
287                                tmp = inet_ntoa(fromsa->sin_addr);
288                                if (tmp == NULL) {
289                                        OSIP_TRACE(osip_trace
290                                                           (__FILE__, __LINE__, OSIP_ERROR, NULL,
291                                                                "Message received from: NULL:%i inet_ntoa failure\n",
292                                                                recvport));
293                                } else {
294                                        snprintf(src6host, sizeof(src6host), "%s", tmp);
295                                        OSIP_TRACE(osip_trace
296                                                           (__FILE__, __LINE__, OSIP_INFO1, NULL,
297                                                                "Message received from: %s:%i\n", src6host,
298                                                                recvport));
299                                        osip_strncpy(tcp_socket_tab[pos].remote_ip, src6host,
300                                                                 sizeof(tcp_socket_tab[pos].remote_ip) - 1);
301                                        tcp_socket_tab[pos].remote_port = recvport;
302                                }
303                        }
304#else
305                        i = getnameinfo((struct sockaddr *) &sa, slen,
306                                                        src6host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
307
308                        if (i != 0) {
309                                OSIP_TRACE(osip_trace
310                                                   (__FILE__, __LINE__, OSIP_ERROR, NULL,
311                                                        "Message received from: NULL:%i getnameinfo failure\n",
312                                                        recvport));
313                                snprintf(src6host, sizeof(src6host), "127.0.0.1");
314                        } else {
315                                OSIP_TRACE(osip_trace
316                                                   (__FILE__, __LINE__, OSIP_INFO1, NULL,
317                                                        "Message received from: %s:%i\n", src6host, recvport));
318                                osip_strncpy(tcp_socket_tab[pos].remote_ip, src6host,
319                                                         sizeof(tcp_socket_tab[pos].remote_ip) - 1);
320                                tcp_socket_tab[pos].remote_port = recvport;
321                        }
322#endif
323                }
324        }
325
326
327
328        buf = NULL;
329
330        for (pos = 0; pos < EXOSIP_MAX_SOCKETS; pos++) {
331                if (tcp_socket_tab[pos].socket > 0
332                        && FD_ISSET(tcp_socket_tab[pos].socket, osip_fdset)) {
333                        int i;
334
335                        if (buf == NULL)
336                                buf =
337                                        (char *) osip_malloc(SIP_MESSAGE_MAX_LENGTH * sizeof(char) +
338                                                                                 1);
339                        if (buf == NULL)
340                                return OSIP_NOMEM;
341
342                        i = recv(tcp_socket_tab[pos].socket, buf, SIP_MESSAGE_MAX_LENGTH, 0);
343
344#define TEST_CODE_FOR_FRAGMENTATION
345#ifdef TEST_CODE_FOR_FRAGMENTATION
346                        if (i > 0) {
347                                char *end_sip;
348                                char *cl_header;
349                                int cl_size;
350                                osip_strncpy(buf + i, "\0", 1);
351                                if (tcp_socket_tab[pos].previous_content != NULL) {
352                                        /* concat old data with new data */
353                                        tcp_socket_tab[pos].previous_content =
354                                                (char *) osip_realloc(tcp_socket_tab[pos].previous_content,
355                                                                                          tcp_socket_tab
356                                                                                          [pos].previous_content_len + i + 1);
357                                        if (tcp_socket_tab[pos].previous_content == NULL) {
358                                                OSIP_TRACE(osip_trace
359                                                                   (__FILE__, __LINE__, OSIP_ERROR, NULL,
360                                                                        "Reallocation error: (len=%i)",
361                                                                        tcp_socket_tab[pos].previous_content_len + i +
362                                                                        1));
363                                                tcp_socket_tab[pos].previous_content_len = 0;
364                                                continue;       /* give up: realloc issue */
365                                        }
366                                        osip_strncpy(tcp_socket_tab[pos].previous_content +
367                                                                 tcp_socket_tab[pos].previous_content_len, buf, i);
368                                        tcp_socket_tab[pos].previous_content_len =
369                                                tcp_socket_tab[pos].previous_content_len + i;
370                                }
371                                if (tcp_socket_tab[pos].previous_content == NULL) {
372                                        tcp_socket_tab[pos].previous_content =
373                                                (char *) osip_malloc(i + 1);
374                                        osip_strncpy(tcp_socket_tab[pos].previous_content, buf, i);
375                                        tcp_socket_tab[pos].previous_content_len = i;
376                                }
377
378                                end_sip = strstr(tcp_socket_tab[pos].previous_content, "\r\n\r\n");
379                                /* end_sip might be end of SIP headers */
380                                while (end_sip != NULL) {
381                                        /* a content-legnth MUST exist before the CRLFCRLF */
382                                        cl_header =
383                                                osip_strcasestr(tcp_socket_tab[pos].previous_content,
384                                                                                "\ncontent-length ");
385                                        if (cl_header == NULL || cl_header > end_sip)
386                                                cl_header =
387                                                        osip_strcasestr(tcp_socket_tab[pos].previous_content,
388                                                                                        "\ncontent-length:");
389                                        if (cl_header == NULL || cl_header > end_sip)
390                                                cl_header =
391                                                        osip_strcasestr(tcp_socket_tab[pos].previous_content,
392                                                                                        "\r\nl ");
393                                        if (cl_header == NULL || cl_header > end_sip)
394                                                cl_header =
395                                                        osip_strcasestr(tcp_socket_tab[pos].previous_content,
396                                                                                        "\r\nl:");
397
398                                        if (cl_header != NULL && cl_header < end_sip)
399                                                cl_header = strchr(cl_header, ':');
400                                        /* broken data */
401                                        if (cl_header == NULL || cl_header >= end_sip) {
402                                                /* remove data up to crlfcrlf and restart */
403                                                memmove(tcp_socket_tab[pos].previous_content,
404                                                                end_sip+4,
405                                                                tcp_socket_tab[pos].previous_content_len -
406                                                                (end_sip + 4 -
407                                                                 tcp_socket_tab[pos].previous_content) + 1);
408
409                                                tcp_socket_tab[pos].previous_content_len =
410                                                        tcp_socket_tab[pos].previous_content_len - (end_sip +
411                                                                                                                                                4 -
412                                                                                                                                                tcp_socket_tab
413                                                                                                                                                [pos].
414                                                                                                                                                previous_content);
415
416                                                tcp_socket_tab[pos].previous_content = (char *)
417                                                        osip_realloc(tcp_socket_tab[pos].previous_content,
418                                                                                 tcp_socket_tab[pos].previous_content_len +
419                                                                                 1);
420                                                if (tcp_socket_tab[pos].previous_content == NULL) {
421                                                        OSIP_TRACE(osip_trace
422                                                                           (__FILE__, __LINE__, OSIP_ERROR, NULL,
423                                                                                "Reallocation error: (len=%i)",
424                                                                                tcp_socket_tab[pos].previous_content_len +
425                                                                                1));
426                                                        tcp_socket_tab[pos].previous_content_len = 0;
427                                                        break;
428                                                }
429                                                end_sip =
430                                                        strstr(tcp_socket_tab[pos].previous_content,
431                                                                   "\r\n\r\n");
432                                                continue;       /* and restart from new CRLFCRLF */
433                                        }
434
435                                        /* header content-length was found before CRLFCRLF -> all headers are available */
436                                        cl_header++;    /* after ':' char */
437                                        cl_size = osip_atoi(cl_header);
438
439                                        if (cl_size == 0
440                                                || (cl_size > 0 && end_sip + 4 + cl_size <=
441                                                tcp_socket_tab[pos].previous_content +
442                                                tcp_socket_tab[pos].previous_content_len)) {
443                                                /* we have beg_sip & end_sip */
444                                                _eXosip_handle_incoming_message(tcp_socket_tab
445                                                                                                                [pos].previous_content,
446                                                                                                                end_sip + 4 + cl_size -
447                                                                                                                tcp_socket_tab
448                                                                                                                [pos].previous_content,
449                                                                                                                tcp_socket_tab[pos].socket,
450                                                                                                                tcp_socket_tab
451                                                                                                                [pos].remote_ip,
452                                                                                                                tcp_socket_tab
453                                                                                                                [pos].remote_port);
454                                                if (tcp_socket_tab[pos].previous_content_len -
455                                                        (end_sip + 4 + cl_size -
456                                                         tcp_socket_tab[pos].previous_content) == 0) {
457                                                        end_sip = NULL;
458                                                        OSIP_TRACE(osip_trace
459                                                                           (__FILE__, __LINE__, OSIP_INFO2, NULL,
460                                                                                "All TCP data consumed\n"));
461                                                        tcp_socket_tab[pos].previous_content_len = 0;
462                                                        osip_free(tcp_socket_tab[pos].previous_content);
463                                                        tcp_socket_tab[pos].previous_content = NULL;
464                                                        continue;
465                                                }
466
467                                                /* any more content? */
468                                                memmove(tcp_socket_tab[pos].previous_content,
469                                                                end_sip + 4 + cl_size,
470                                                                tcp_socket_tab[pos].previous_content_len -
471                                                                (end_sip + 4 + cl_size -
472                                                                 tcp_socket_tab[pos].previous_content) + 1);
473
474                                                tcp_socket_tab[pos].previous_content_len =
475                                                        tcp_socket_tab[pos].previous_content_len - (end_sip +
476                                                                                                                                                4 +
477                                                                                                                                                cl_size -
478                                                                                                                                                tcp_socket_tab
479                                                                                                                                                [pos].
480                                                                                                                                                previous_content);
481
482                                                tcp_socket_tab[pos].previous_content = (char *)
483                                                        osip_realloc(tcp_socket_tab[pos].previous_content,
484                                                                                 tcp_socket_tab[pos].previous_content_len +
485                                                                                 1);
486                                                if (tcp_socket_tab[pos].previous_content == NULL) {
487                                                        OSIP_TRACE(osip_trace
488                                                                           (__FILE__, __LINE__, OSIP_ERROR, NULL,
489                                                                                "Reallocation error: (len=%i)",
490                                                                                tcp_socket_tab[pos].previous_content_len +
491                                                                                1));
492                                                        tcp_socket_tab[pos].previous_content_len = 0;
493                                                        break;
494                                                }
495                                                end_sip =
496                                                        strstr(tcp_socket_tab[pos].previous_content,
497                                                                   "\r\n\r\n");
498                                                continue;       /* and restart from new CRLFCRLF */
499                                        }
500
501                                        /* uncomplete SIP message */
502                                        end_sip = NULL;
503                                        OSIP_TRACE(osip_trace
504                                                           (__FILE__, __LINE__, OSIP_INFO2, NULL,
505                                                                "Uncomplete TCP data (%s)\n", buf));
506                                        continue;
507                                }
508
509                                if (tcp_socket_tab[pos].previous_content_len == 0) {
510                                        /* all data consumed are reallocation error ? */
511                                        continue;
512                                }
513#else
514                        if (i > 5) {
515                                osip_strncpy(buf + i, "\0", 1);
516                                OSIP_TRACE(osip_trace
517                                                   (__FILE__, __LINE__, OSIP_INFO2, NULL,
518                                                        "Received TCP message: \n%s\n", buf));
519                                _eXosip_handle_incoming_message(buf, i,
520                                                                                                tcp_socket_tab[pos].socket,
521                                                                                                tcp_socket_tab[pos].remote_ip,
522                                                                                                tcp_socket_tab[pos].remote_port);
523#endif
524                        } else if (i < 0) {
525                                int status = ex_errno;
526                                if (status != EAGAIN) {
527                                        OSIP_TRACE(osip_trace
528                                                           (__FILE__, __LINE__, OSIP_ERROR, NULL,
529                                                                "Could not read socket (%s)- close it\n",
530                                                                strerror(status)));
531                                        close(tcp_socket_tab[pos].socket);
532                                        memset(&(tcp_socket_tab[pos]), 0, sizeof(tcp_socket_tab[pos]));
533                                }
534                        } else if (i == 0) {
535                                OSIP_TRACE(osip_trace
536                                                   (__FILE__, __LINE__, OSIP_INFO1, NULL,
537                                                        "End of stream (read 0 byte from %s:%i)\n",
538                                                        tcp_socket_tab[pos].remote_ip,
539                                                        tcp_socket_tab[pos].remote_port));
540                                close(tcp_socket_tab[pos].socket);
541                                memset(&(tcp_socket_tab[pos]), 0, sizeof(tcp_socket_tab[pos]));
542                        }
543#ifndef MINISIZE
544                        else {
545                                /* we expect at least one byte, otherwise there's no doubt that it is not a sip message ! */
546                                OSIP_TRACE(osip_trace
547                                                   (__FILE__, __LINE__, OSIP_INFO1, NULL,
548                                                        "Dummy SIP message received (size=%i)\n", i));
549                        }
550#endif
551                }
552        }
553
554        if (buf != NULL)
555                osip_free(buf);
556
557        return OSIP_SUCCESS;
558}
559
560static int _tcp_tl_find_socket(char *host, int port)
561{
562        int pos;
563
564        for (pos = 0; pos < EXOSIP_MAX_SOCKETS; pos++) {
565                if (tcp_socket_tab[pos].socket != 0) {
566                        if (0 == osip_strcasecmp(tcp_socket_tab[pos].remote_ip, host)
567                                && port == tcp_socket_tab[pos].remote_port)
568                                return tcp_socket_tab[pos].socket;
569                }
570        }
571        return -1;
572}
573
574static int _tcp_tl_is_connected(int sock)
575{
576        int res;
577        struct timeval tv;
578        fd_set wrset;
579        int valopt;
580        socklen_t sock_len;
581        tv.tv_sec = SOCKET_TIMEOUT / 1000;
582        tv.tv_usec = (SOCKET_TIMEOUT % 1000) * 1000;
583
584        FD_ZERO(&wrset);
585        FD_SET(sock, &wrset);
586
587        res = select(sock + 1, NULL, &wrset, NULL, &tv);
588        if (res > 0) {
589                sock_len = sizeof(int);
590                if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (void *) (&valopt), &sock_len)
591                        == 0) {
592                        if (valopt) {
593                                OSIP_TRACE(osip_trace
594                                                   (__FILE__, __LINE__, OSIP_INFO2, NULL,
595                                                        "Cannot connect socket node / %s[%d]\n",
596                                                        strerror(ex_errno), ex_errno));
597                                return -1;
598                        } else {
599                                return 0;
600                        }
601                } else {
602                        OSIP_TRACE(osip_trace
603                                           (__FILE__, __LINE__, OSIP_INFO2, NULL,
604                                                "Cannot connect socket node / error in getsockopt %s[%d]\n",
605                                                strerror(ex_errno), ex_errno));
606                        return -1;
607                }
608        } else if (res < 0) {
609                OSIP_TRACE(osip_trace
610                                   (__FILE__, __LINE__, OSIP_INFO2, NULL,
611                                        "Cannot connect socket node / error in select %s[%d]\n",
612                                        strerror(ex_errno), ex_errno));
613                return -1;
614        } else {
615                OSIP_TRACE(osip_trace
616                                   (__FILE__, __LINE__, OSIP_INFO2, NULL,
617                                        "Cannot connect socket node / select timeout (%d ms)\n",
618                                        SOCKET_TIMEOUT));
619                return 1;
620        }
621}
622
623static int _tcp_tl_connect_socket(char *host, int port)
624{
625        int pos;
626        int res;
627        struct addrinfo *addrinfo = NULL;
628        struct addrinfo *curinfo;
629        int sock = -1;
630
631        char src6host[NI_MAXHOST];
632        memset(src6host, 0, sizeof(src6host));
633
634        for (pos = 0; pos < EXOSIP_MAX_SOCKETS; pos++) {
635                if (tcp_socket_tab[pos].socket == 0) {
636                        break;
637                }
638        }
639
640        if (pos == EXOSIP_MAX_SOCKETS)
641                return -1;
642
643        res = eXosip_get_addrinfo(&addrinfo, host, port, IPPROTO_TCP);
644        if (res)
645                return -1;
646
647
648        for (curinfo = addrinfo; curinfo; curinfo = curinfo->ai_next) {
649                if (curinfo->ai_protocol && curinfo->ai_protocol != IPPROTO_TCP) {
650                        OSIP_TRACE(osip_trace
651                                           (__FILE__, __LINE__, OSIP_INFO2, NULL,
652                                                "Skipping protocol %d\n", curinfo->ai_protocol));
653                        continue;
654                }
655
656                res =
657                        getnameinfo((struct sockaddr *) curinfo->ai_addr, curinfo->ai_addrlen,
658                                                src6host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
659
660                if (res == 0) {
661                        int i = _tcp_tl_find_socket(src6host, port);
662                        if (i >= 0) {
663                                eXosip_freeaddrinfo(addrinfo);
664                                return i;
665                        }
666                        OSIP_TRACE(osip_trace
667                                           (__FILE__, __LINE__, OSIP_INFO2, NULL,
668                                                "New binding with %s\n", src6host));
669                }
670
671                sock = (int) socket(curinfo->ai_family, curinfo->ai_socktype,
672                                                        curinfo->ai_protocol);
673                if (sock < 0) {
674                        OSIP_TRACE(osip_trace
675                                           (__FILE__, __LINE__, OSIP_INFO2, NULL,
676                                                "Cannot create socket %s!\n", strerror(ex_errno)));
677                        continue;
678                }
679
680                if (curinfo->ai_family == AF_INET6) {
681#ifdef IPV6_V6ONLY
682                        if (setsockopt_ipv6only(sock)) {
683                                close(sock);
684                                sock = -1;
685                                OSIP_TRACE(osip_trace
686                                                   (__FILE__, __LINE__, OSIP_INFO2, NULL,
687                                                        "Cannot set socket option %s!\n", strerror(ex_errno)));
688                                continue;
689                        }
690#endif                                                  /* IPV6_V6ONLY */
691                }
692                /* set NON-BLOCKING MODE */
693#if defined(_WIN32_WCE) || defined(WIN32)
694                {
695                        unsigned long nonBlock = 1;
696                        int val;
697
698                        ioctlsocket(sock, FIONBIO, &nonBlock);
699
700                        val = 1;
701                        if (setsockopt
702                                (sock, SOL_SOCKET, SO_KEEPALIVE, (char *) &val,
703                                 sizeof(val)) == -1) {
704                                close(sock);
705                                sock = -1;
706                                OSIP_TRACE(osip_trace
707                                                   (__FILE__, __LINE__, OSIP_INFO2, NULL,
708                                                        "Cannot get socket flag!\n"));
709                                continue;
710                        }
711                }
712#if !defined(_WIN32_WCE)
713                {
714                        DWORD err = 0L;
715                        DWORD dwBytes = 0L;
716                        struct tcp_keepalive kalive = { 0 };
717                        struct tcp_keepalive kaliveOut = { 0 };
718                        kalive.onoff = 1;
719                        kalive.keepalivetime = 30000;   /* Keep Alive in 5.5 sec. */
720                        kalive.keepaliveinterval = 3000;        /* Resend if No-Reply */
721                        err = WSAIoctl(sock, SIO_KEEPALIVE_VALS, &kalive,
722                                                   sizeof(kalive), &kaliveOut, sizeof(kaliveOut), &dwBytes,
723                                                   NULL, NULL);
724                        if (err != 0) {
725                                OSIP_TRACE(osip_trace
726                                                   (__FILE__, __LINE__, OSIP_WARNING, NULL,
727                                                        "Cannot set keepalive interval!\n"));
728                        }
729                }
730#endif
731#else
732                {
733                        int val;
734
735                        val = fcntl(sock, F_GETFL);
736                        if (val < 0) {
737                                close(sock);
738                                sock = -1;
739                                OSIP_TRACE(osip_trace
740                                                   (__FILE__, __LINE__, OSIP_INFO2, NULL,
741                                                        "Cannot get socket flag!\n"));
742                                continue;
743                        }
744                        val |= O_NONBLOCK;
745                        if (fcntl(sock, F_SETFL, val) < 0) {
746                                close(sock);
747                                sock = -1;
748                                OSIP_TRACE(osip_trace
749                                                   (__FILE__, __LINE__, OSIP_INFO2, NULL,
750                                                        "Cannot set socket flag!\n"));
751                                continue;
752                        }
753#if 0
754                        val = 1;
755                        if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)) ==
756                                -1)
757                                val = 30;               /* 30 sec before starting probes */
758                        setsockopt(sock, SOL_TCP, TCP_KEEPIDLE, &val, sizeof(val));
759                        val = 2;                        /* 2 probes max */
760                        setsockopt(sock, SOL_TCP, TCP_KEEPCNT, &val, sizeof(val));
761                        val = 10;                       /* 10 seconds between each probe */
762                        setsockopt(sock, SOL_TCP, TCP_KEEPINTVL, &val, sizeof(val));
763#endif
764                }
765#endif
766
767                OSIP_TRACE(osip_trace
768                                   (__FILE__, __LINE__, OSIP_INFO2, NULL,
769                                        "socket node:%s , socket %d, family:%d set to non blocking mode\n",
770                                        host, sock, curinfo->ai_family));
771                res = connect(sock, curinfo->ai_addr, curinfo->ai_addrlen);
772                if (res < 0) {
773#if defined(_WIN32_WCE) || defined(WIN32)
774                        if (ex_errno != WSAEWOULDBLOCK) {
775#else
776                        if (ex_errno != EINPROGRESS) {
777#endif
778                                OSIP_TRACE(osip_trace
779                                                   (__FILE__, __LINE__, OSIP_INFO2, NULL,
780                                                        "Cannot connect socket node:%s family:%d %s[%d]\n",
781                                                        host, curinfo->ai_family, strerror(ex_errno),
782                                                        ex_errno));
783                                close(sock);
784                                sock = -1;
785                                continue;
786                        } else {
787                                res = _tcp_tl_is_connected(sock);
788                                if (res > 0) {
789                                        OSIP_TRACE(osip_trace
790                                                           (__FILE__, __LINE__, OSIP_INFO2, NULL,
791                                                                "socket node:%s, socket %d [pos=%d], family:%d, in progress\n",
792                                                                host, sock, pos, curinfo->ai_family));
793                                        break;
794                                } else if (res == 0) {
795                                        OSIP_TRACE(osip_trace
796                                                           (__FILE__, __LINE__, OSIP_INFO2, NULL,
797                                                                "socket node:%s , socket %d [pos=%d], family:%d, connected\n",
798                                                                host, sock, pos, curinfo->ai_family));
799                                        break;
800                                } else {
801                                        close(sock);
802                                        sock = -1;
803                                        continue;
804                                }
805                        }
806                }
807
808                break;
809        }
810
811        eXosip_freeaddrinfo(addrinfo);
812
813        if (sock > 0) {
814                tcp_socket_tab[pos].socket = sock;
815
816                if (src6host[0] == '\0')
817                        osip_strncpy(tcp_socket_tab[pos].remote_ip, host,
818                                                 sizeof(tcp_socket_tab[pos].remote_ip) - 1);
819                else
820                        osip_strncpy(tcp_socket_tab[pos].remote_ip, src6host,
821                                                 sizeof(tcp_socket_tab[pos].remote_ip) - 1);
822
823                tcp_socket_tab[pos].remote_port = port;
824                return sock;
825        }
826
827        return -1;
828}
829
830static int
831tcp_tl_send_message(osip_transaction_t * tr, osip_message_t * sip, char *host,
832                                        int port, int out_socket)
833{
834        size_t length = 0;
835        char *message;
836        int i;
837
838        if (host == NULL) {
839                host = sip->req_uri->host;
840                if (sip->req_uri->port != NULL)
841                        port = osip_atoi(sip->req_uri->port);
842                else
843                        port = 5060;
844        }
845
846        /* remove preloaded route if there is no tag in the To header
847         */
848        {
849                osip_route_t *route = NULL;
850                osip_generic_param_t *tag = NULL;
851                osip_message_get_route(sip, 0, &route);
852
853                osip_to_get_tag(sip->to, &tag);
854                if (tag == NULL && route != NULL && route->url != NULL) {
855                        osip_list_remove(&sip->routes, 0);
856                }
857                i = osip_message_to_str(sip, &message, &length);
858                if (tag == NULL && route != NULL && route->url != NULL) {
859                        osip_list_add(&sip->routes, route, 0);
860                }
861        }
862
863        if (i != 0 || length <= 0) {
864                return -1;
865        }
866
867        /* Step 1: find existing socket to send message */
868        if (out_socket <= 0) {
869                out_socket = _tcp_tl_find_socket(host, port);
870
871                /* Step 2: create new socket with host:port */
872                if (out_socket <= 0) {
873                        out_socket = _tcp_tl_connect_socket(host, port);
874                }
875        } else {
876                OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_INFO1, NULL,
877                                                          "reusing REQUEST connection (to dest=%s:%i)\n",
878                                                          host, port));
879        }
880
881        if (out_socket <= 0) {
882                osip_free(message);
883                return -1;
884        }
885
886        i = _tcp_tl_is_connected(out_socket);
887        if (i > 0) {
888                time_t now;
889                now = time(NULL);
890                OSIP_TRACE(osip_trace
891                                   (__FILE__, __LINE__, OSIP_INFO2, NULL,
892                                        "socket node:%s, socket %d [pos=%d], in progress\n",
893                                        host, out_socket, -1));
894                osip_free(message);
895                if (tr != NULL && now - tr->birth_time > 10)
896                        return -1;
897                return 1;
898        } else if (i == 0) {
899                OSIP_TRACE(osip_trace
900                                   (__FILE__, __LINE__, OSIP_INFO2, NULL,
901                                        "socket node:%s , socket %d [pos=%d], connected\n",
902                                        host, out_socket, -1));
903        } else {
904                OSIP_TRACE(osip_trace
905                                   (__FILE__, __LINE__, OSIP_ERROR, NULL,
906                                        "socket node:%s, socket %d [pos=%d], socket error\n",
907                                        host, out_socket, -1));
908                osip_free(message);
909                return -1;
910        }
911
912        OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_INFO1, NULL,
913                                                  "Message sent: (to dest=%s:%i) \n%s\n",
914                                                  host, port, message));
915
916        while (1) {
917                i = send(out_socket, (const void *) message, length, 0);
918                if (i < 0) {
919                        int status = ex_errno;
920                        if (EAGAIN == status || EWOULDBLOCK == status) {
921                                struct timeval tv;
922                                fd_set wrset;
923                                tv.tv_sec = SOCKET_TIMEOUT / 1000;
924                                tv.tv_usec = (SOCKET_TIMEOUT % 1000) * 1000;
925
926                                FD_ZERO(&wrset);
927                                FD_SET(out_socket, &wrset);
928
929                                i = select(out_socket + 1, NULL, &wrset, NULL, &tv);
930                                if (i > 0) {
931                                        continue;
932                                } else if (i < 0) {
933                                        OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_ERROR, NULL,
934                                                                                  "TCP select error: %s\n",
935                                                                                  strerror(ex_errno)));
936                                        osip_free(message);
937                                        return -1;
938                                } else {
939                                        OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_ERROR, NULL,
940                                                                                  "TCP timeout: %d ms\n", SOCKET_TIMEOUT));
941                                        osip_free(message);
942                                        return -1;
943                                }
944                        } else {
945                                /* SIP_NETWORK_ERROR; */
946                                OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_ERROR, NULL,
947                                                                          "TCP error: %s\n", strerror(status)));
948                                osip_free(message);
949                                return -1;
950                        }
951                }
952                break;
953        }
954
955        osip_free(message);
956        return OSIP_SUCCESS;
957}
958
959static int tcp_tl_keepalive(void)
960{
961        char buf[4] = "\r\n\r\n";
962        int pos;
963        int i;
964        int ret = 0;
965        int success = 0;
966
967        if (tcp_socket <= 0)
968                return 0;
969
970        for (pos = 0; pos < EXOSIP_MAX_SOCKETS; pos++) {
971                if (tcp_socket_tab[pos].socket > 0) {
972                        i = _tcp_tl_is_connected(tcp_socket_tab[pos].socket);
973                        if (i > 0) {
974                                OSIP_TRACE(osip_trace
975                                                   (__FILE__, __LINE__, OSIP_INFO2, NULL,
976                                                        "tcp_tl_keepalive socket node:%s, socket %d [pos=%d], in progress\n",
977                                                        tcp_socket_tab[pos].remote_ip,
978                                                        tcp_socket_tab[pos].socket, pos));
979                                continue;
980                        } else if (i == 0) {
981                                OSIP_TRACE(osip_trace
982                                                   (__FILE__, __LINE__, OSIP_INFO2, NULL,
983                                                        "tcp_tl_keepalive socket node:%s , socket %d [pos=%d], connected\n",
984                                                        tcp_socket_tab[pos].remote_ip,
985                                                        tcp_socket_tab[pos].socket, pos));
986                        } else {
987                                OSIP_TRACE(osip_trace
988                                                   (__FILE__, __LINE__, OSIP_ERROR, NULL,
989                                                        "tcp_tl_keepalive socket node:%s, socket %d [pos=%d], socket error\n",
990                                                        tcp_socket_tab[pos].remote_ip,
991                                                        tcp_socket_tab[pos].socket, pos));
992                                close(tcp_socket_tab[pos].socket);
993                                tcp_socket_tab[pos].socket = -1;
994                                continue;
995                        }
996                        i = send(tcp_socket_tab[pos].socket, (const void *) buf, 4, 0);
997                        if (i <= 0)
998                                ret -= 1;
999                        else
1000                                success = 1;
1001                }
1002        }
1003        return success == 0 ? ret : success;
1004}
1005
1006static int tcp_tl_set_socket(int socket)
1007{
1008        tcp_socket = socket;
1009
1010        return OSIP_SUCCESS;
1011}
1012
1013static int tcp_tl_masquerade_contact(const char *public_address, int port)
1014{
1015        if (public_address == NULL || public_address[0] == '\0') {
1016                memset(tcp_firewall_ip, '\0', sizeof(tcp_firewall_ip));
1017                memset(tcp_firewall_port, '\0', sizeof(tcp_firewall_port));
1018                if (eXtl_tcp.proto_port > 0)
1019                        snprintf(tcp_firewall_port, sizeof(tcp_firewall_port), "%i",
1020                                         eXtl_tcp.proto_port);
1021                return OSIP_SUCCESS;
1022        }
1023        snprintf(tcp_firewall_ip, sizeof(tcp_firewall_ip), "%s", public_address);
1024        if (port > 0) {
1025                snprintf(tcp_firewall_port, sizeof(tcp_firewall_port), "%i", port);
1026        }
1027        return OSIP_SUCCESS;
1028}
1029
1030static int
1031tcp_tl_get_masquerade_contact(char *ip, int ip_size, char *port, int port_size)
1032{
1033        memset(ip, 0, ip_size);
1034        memset(port, 0, port_size);
1035
1036        if (tcp_firewall_ip[0] != '\0')
1037                snprintf(ip, ip_size, "%s", tcp_firewall_ip);
1038
1039        if (tcp_firewall_port[0] != '\0')
1040                snprintf(port, port_size, "%s", tcp_firewall_port);
1041        return OSIP_SUCCESS;
1042}
1043
1044struct eXtl_protocol eXtl_tcp = {
1045        1,
1046        5060,
1047        "TCP",
1048        "0.0.0.0",
1049        IPPROTO_TCP,
1050        AF_INET,
1051        0,
1052        0,
1053
1054        &tcp_tl_init,
1055        &tcp_tl_free,
1056        &tcp_tl_open,
1057        &tcp_tl_set_fdset,
1058        &tcp_tl_read_message,
1059        &tcp_tl_send_message,
1060        &tcp_tl_keepalive,
1061        &tcp_tl_set_socket,
1062        &tcp_tl_masquerade_contact,
1063        &tcp_tl_get_masquerade_contact
1064};
Note: See TracBrowser for help on using the repository browser.