1 /*!
2 * \file sccp_netsock.c
3 * \brief SCCP NetSock Class
4 * \author Diederik de Groot < ddegroot@users.sourceforge.net >
5 * \note This program is free software and may be modified and distributed under the terms of the GNU Public License.
6 * See the LICENSE file at the top of the source tree.
7 * \since 2016-02-02
8 */
9 #include "config.h"
10 #include "common.h"
11 #include "sccp_netsock.h"
12
13 SCCP_FILE_VERSION(__FILE__, "");
14
15 #include "sccp_session.h"
16 #include <netinet/in.h>
17 #include <asterisk/netsock2.h>
18 #include <asterisk/acl.h>
19
20 /* arbitrary values */
21 #define NETSOCK_TIMEOUT_SEC 10 /* timeout after seven seconds when trying to read/write from/to a socket */
22 #define NETSOCK_TIMEOUT_MILLISEC 0 /* " " 0 milli seconds " " */
23 #define NETSOCK_KEEPALIVE_CNT 3 /* The maximum number of keepalive probes TCP should send before dropping the connection. */
24 #define NETSOCK_LINGER_WAIT 0 /* but wait 0 milliseconds before closing socket and discard all outboung messages */
25 #define NETSOCK_RCVBUF SCCP_MAX_PACKET /* SO_RCVBUF */
26 #define NETSOCK_SNDBUF (SCCP_MAX_PACKET * 5) /* SO_SNDBUG */
27
28 union sockaddr_union {
29 struct sockaddr sa;
30 struct sockaddr_storage ss;
31 struct sockaddr_in sin;
32 struct sockaddr_in6 sin6;
33 };
34
ast_sockaddr2storage(struct ast_sockaddr * src)35 gcc_inline struct sockaddr_storage * ast_sockaddr2storage(struct ast_sockaddr * src)
36 {
37 return &src->ss;
38 }
39
storage2ast_sockaddr(struct sockaddr_storage * src,struct ast_sockaddr * dst)40 gcc_inline struct ast_sockaddr * storage2ast_sockaddr(struct sockaddr_storage * src, struct ast_sockaddr * dst)
41 {
42 memcpy(&dst->ss, src, sizeof(struct sockaddr_storage));
43 dst->ss.ss_family = src->ss_family;
44 if(src->ss_family == AF_INET6) {
45 dst->len = sizeof(struct sockaddr_in6);
46 } else {
47 dst->len = sizeof(struct sockaddr_in);
48 }
49 return dst;
50 }
51
52 //#include "sccp_utils.h" // sccp_copy_string
sccp_netsock_ouraddrfor(const struct sockaddr_storage * them,struct sockaddr_storage * us)53 boolean_t sccp_netsock_ouraddrfor(const struct sockaddr_storage * them, struct sockaddr_storage * us)
54 {
55 const char * sock_err;
56 int sockfd;
57 int port = sccp_netsock_getPort(us);
58 socklen_t slen = (socklen_t)(sizeof(struct sockaddr_in));
59 int family = AF_INET;
60 union sockaddr_union themaddr = { .ss = *them };
61 union sockaddr_union usaddr = { .ss = *us };
62
63 if(sccp_netsock_is_IPv6(them)) {
64 family = AF_INET6;
65 slen = (socklen_t)(sizeof(struct sockaddr_in6));
66 }
67
68 sockfd = socket(family, SOCK_DGRAM, 0);
69 if(sockfd < 0) {
70 sock_err = ast_strdupa(strerror(errno));
71 pbx_log(LOG_ERROR, "Cannot create socket to %s: %s\n", sccp_netsock_stringify_addr(them), sock_err);
72 return FALSE;
73 }
74
75 if(connect(sockfd, &themaddr.sa, slen)) {
76 sock_err = ast_strdupa(strerror(errno));
77 pbx_log(LOG_WARNING, "Cannot connect to %s: %s\n", sccp_netsock_stringify_addr(them), sock_err);
78 close(sockfd);
79 return FALSE;
80 }
81
82 if(getsockname(sockfd, &usaddr.sa, &slen)) {
83 sock_err = ast_strdupa(strerror(errno));
84 pbx_log(LOG_WARNING, "Cannot get socket name for connection to %s: %s\n", sccp_netsock_stringify_addr(them), sock_err);
85 close(sockfd);
86 return FALSE;
87 }
88
89 memcpy(us, &usaddr.ss, sizeof(struct sockaddr_storage));
90 close(sockfd);
91 sccp_netsock_setPort(us, port);
92 // sccp_log(DEBUGCAT_SOCKET)(VERBOSE_PREFIX_3 "SCCP: Connected via '%s'\n", sccp_netsock_stringify_addr(us));
93 return TRUE;
94 }
95
sccp_netsock_is_IPv4(const struct sockaddr_storage * sockAddrStorage)96 gcc_inline boolean_t sccp_netsock_is_IPv4(const struct sockaddr_storage *sockAddrStorage)
97 {
98 return (sockAddrStorage->ss_family == AF_INET) ? TRUE : FALSE;
99 }
100
sccp_netsock_is_IPv6(const struct sockaddr_storage * sockAddrStorage)101 gcc_inline boolean_t sccp_netsock_is_IPv6(const struct sockaddr_storage *sockAddrStorage)
102 {
103 return (sockAddrStorage->ss_family == AF_INET6) ? TRUE : FALSE;
104 }
105
sccp_netsock_getPort(const struct sockaddr_storage * sockAddrStorage)106 uint16_t __PURE__ sccp_netsock_getPort(const struct sockaddr_storage * sockAddrStorage)
107 {
108 if (sccp_netsock_is_IPv4(sockAddrStorage)) {
109 return ntohs(((struct sockaddr_in *) sockAddrStorage)->sin_port);
110 }
111 if (sccp_netsock_is_IPv6(sockAddrStorage)) {
112 return ntohs(((struct sockaddr_in6 *) sockAddrStorage)->sin6_port);
113 }
114 return 0;
115 }
116
sccp_netsock_setPort(const struct sockaddr_storage * sockAddrStorage,uint16_t port)117 void sccp_netsock_setPort(const struct sockaddr_storage *sockAddrStorage, uint16_t port)
118 {
119 if (sccp_netsock_is_IPv4(sockAddrStorage)) {
120 ((struct sockaddr_in *) sockAddrStorage)->sin_port = htons(port);
121 } else if (sccp_netsock_is_IPv6(sockAddrStorage)) {
122 ((struct sockaddr_in6 *) sockAddrStorage)->sin6_port = htons(port);
123 }
124 }
125
sccp_netsock_is_any_addr(const struct sockaddr_storage * sockAddrStorage)126 int __PURE__ sccp_netsock_is_any_addr(const struct sockaddr_storage *sockAddrStorage)
127 {
128 union sockaddr_union tmp_addr = {
129 .ss = *sockAddrStorage,
130 };
131
132 return (sccp_netsock_is_IPv4(sockAddrStorage) && (tmp_addr.sin.sin_addr.s_addr == INADDR_ANY)) || (sccp_netsock_is_IPv6(sockAddrStorage) && IN6_IS_ADDR_UNSPECIFIED(&tmp_addr.sin6.sin6_addr));
133 }
134
__netsock_resolve_first_af(struct sockaddr_storage * addr,const char * name,int family)135 static boolean_t __netsock_resolve_first_af(struct sockaddr_storage *addr, const char *name, int family)
136 {
137 struct addrinfo * res = NULL;
138 int e = 0;
139 boolean_t result = FALSE;
140 if (!name) {
141 return FALSE;
142 }
143
144 struct addrinfo hints = {
145 .ai_family = family,
146 .ai_socktype = SOCK_STREAM,
147 };
148 #if defined(AI_ADDRCONFIG)
149 hints.ai_flags |= AI_ADDRCONFIG;
150 #endif
151 #if defined(AI_V4MAPPED)
152 hints.ai_flags |= AI_V4MAPPED;
153 #endif
154
155 e = getaddrinfo(name, NULL, &hints, &res);
156 if(e == 0) {
157 memcpy(addr, res->ai_addr, res->ai_addrlen);
158 result = TRUE;
159 } else {
160 if (e == EAI_NONAME) {
161 pbx_log(LOG_ERROR, "SCCP: name:%s could not be resolved\n", name);
162 } else {
163 pbx_log(LOG_ERROR, "getaddrinfo(\"%s\") failed: %s\n", name, gai_strerror(e));
164 }
165 }
166 freeaddrinfo(res);
167 return result;
168 }
169
170 static struct {
171 time_t expire;
172 struct sockaddr_storage ip;
173 } externhost[] = {
174 [AF_INET] = {0, {.ss_family = AF_INET}},
175 [AF_INET6] = {0, {.ss_family = AF_INET6}},
176 };
177
sccp_netsock_getExternalAddr(struct sockaddr_storage * sockAddrStorage,int family)178 boolean_t sccp_netsock_getExternalAddr(struct sockaddr_storage *sockAddrStorage, int family)
179 {
180 boolean_t result = FALSE;
181 if (sccp_netsock_is_any_addr(&GLOB(externip))) {
182 if (GLOB(externhost) && strlen(GLOB(externhost)) != 0 && GLOB(externrefresh) > 0) {
183 if (time(NULL) >= externhost[family].expire) {
184 if (!__netsock_resolve_first_af(&externhost[family].ip, GLOB(externhost), family)) {
185 pbx_log(LOG_NOTICE, "Warning: Resolving '%s' failed!\n", GLOB(externhost));
186 return FALSE;
187 }
188 externhost[family].expire = time(NULL) + GLOB(externrefresh);
189 }
190 memcpy(sockAddrStorage, &externhost[family].ip, sizeof(struct sockaddr_storage));
191 sccp_log(DEBUGCAT_SOCKET) (VERBOSE_PREFIX_3 "SCCP: %s resolved to %s\n", GLOB(externhost), sccp_netsock_stringify_addr(sockAddrStorage));
192 result = TRUE;
193 } else {
194 sccp_log(DEBUGCAT_CORE) (VERBOSE_PREFIX_3 "SCCP: No externip/externhost set in sccp.conf.\nWhen you are running your PBX on a seperate host behind a NAT-TING Firewall you need to set externip/externhost.\n");
195 }
196 } else {
197 memcpy(sockAddrStorage, &GLOB(externip), sizeof(struct sockaddr_storage));
198 result = TRUE;
199 }
200 return result;
201 }
202
sccp_netsock_flush_externhost(void)203 void sccp_netsock_flush_externhost(void)
204 {
205 externhost[AF_INET].expire = 0;
206 externhost[AF_INET6].expire = 0;
207 }
208
sccp_netsock_sizeof(const struct sockaddr_storage * sockAddrStorage)209 size_t __PURE__ sccp_netsock_sizeof(const struct sockaddr_storage * sockAddrStorage)
210 {
211 if (sccp_netsock_is_IPv4(sockAddrStorage)) {
212 return sizeof(struct sockaddr_in);
213 }
214 if (sccp_netsock_is_IPv6(sockAddrStorage)) {
215 return sizeof(struct sockaddr_in6);
216 }
217 return 0;
218 }
219
sccp_netsock_is_ipv6_link_local(const struct sockaddr_storage * sockAddrStorage)220 static int sccp_netsock_is_ipv6_link_local(const struct sockaddr_storage *sockAddrStorage)
221 {
222 union sockaddr_union tmp_addr = {
223 .ss = *sockAddrStorage,
224 };
225 return sccp_netsock_is_IPv6(sockAddrStorage) && IN6_IS_ADDR_LINKLOCAL(&tmp_addr.sin6.sin6_addr);
226 }
227
sccp_netsock_is_mapped_IPv4(const struct sockaddr_storage * sockAddrStorage)228 boolean_t __PURE__ sccp_netsock_is_mapped_IPv4(const struct sockaddr_storage *sockAddrStorage)
229 {
230 if (sccp_netsock_is_IPv6(sockAddrStorage)) {
231 const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sockAddrStorage;
232 return IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr);
233 }
234 return FALSE;
235 }
236
sccp_netsock_ipv4_mapped(const struct sockaddr_storage * sockAddrStorage,struct sockaddr_storage * sockAddrStorage_mapped)237 boolean_t sccp_netsock_ipv4_mapped(const struct sockaddr_storage *sockAddrStorage, struct sockaddr_storage *sockAddrStorage_mapped)
238 {
239 const struct sockaddr_in6 * sin6 = NULL;
240 struct sockaddr_in sin4;
241
242 if (!sccp_netsock_is_IPv6(sockAddrStorage)) {
243 return FALSE;
244 }
245
246 if (!sccp_netsock_is_mapped_IPv4(sockAddrStorage)) {
247 return FALSE;
248 }
249
250 sin6 = (const struct sockaddr_in6 *) sockAddrStorage;
251
252 memset(&sin4, 0, sizeof(sin4));
253 sin4.sin_family = AF_INET;
254 sin4.sin_port = sin6->sin6_port;
255 sin4.sin_addr.s_addr = ((uint32_t *) & sin6->sin6_addr)[3];
256
257 memcpy(sockAddrStorage_mapped, &sin4, sizeof(sin4));
258 return TRUE;
259 }
260
261 /*!
262 * \brief
263 * Compares the addresses of two sockaddr structures.
264 *
265 * \retval -1 \a a is lexicographically smaller than \a b
266 * \retval 0 \a a is equal to \a b
267 * \retval 1 \a b is lexicographically smaller than \a a
268 */
sccp_netsock_cmp_addr(const struct sockaddr_storage * a,const struct sockaddr_storage * b)269 int sccp_netsock_cmp_addr(const struct sockaddr_storage *a, const struct sockaddr_storage *b)
270 {
271 //char *stra = pbx_strdupa(sccp_netsock_stringpify_addr(a));
272 //char *strb = pbx_strdupa(sccp_netsock_stringify_addr(b));
273
274 const struct sockaddr_storage * a_tmp = NULL;
275
276 const struct sockaddr_storage * b_tmp = NULL;
277 struct sockaddr_storage ipv4_mapped;
278 size_t len_a = sccp_netsock_sizeof(a);
279 size_t len_b = sccp_netsock_sizeof(b);
280 int ret = -1;
281
282 a_tmp = a;
283 b_tmp = b;
284
285 if (len_a != len_b) {
286 if (sccp_netsock_ipv4_mapped(a, &ipv4_mapped)) {
287 a_tmp = &ipv4_mapped;
288 } else if (sccp_netsock_ipv4_mapped(b, &ipv4_mapped)) {
289 b_tmp = &ipv4_mapped;
290 }
291 }
292 if (len_a < len_b) {
293 ret = -1;
294 goto EXIT;
295 } else if (len_a > len_b) {
296 ret = 1;
297 goto EXIT;
298 }
299
300 if (a_tmp->ss_family == b_tmp->ss_family) {
301 if (a_tmp->ss_family == AF_INET) {
302 ret = memcmp(&(((struct sockaddr_in *) a_tmp)->sin_addr), &(((struct sockaddr_in *) b_tmp)->sin_addr), sizeof(struct in_addr));
303 } else { // AF_INET6
304 ret = memcmp(&(((struct sockaddr_in6 *) a_tmp)->sin6_addr), &(((struct sockaddr_in6 *) b_tmp)->sin6_addr), sizeof(struct in6_addr));
305 }
306 }
307 EXIT:
308 //sccp_log(DEBUGCAT_HIGH)(VERBOSE_PREFIX_2 "SCCP: sccp_netsock_cmp_addr(%s, %s) returning %d\n", stra, strb, ret);
309 return ret;
310 }
311
312 /*!
313 * \brief
314 * Compares the port of two sockaddr structures.
315 *
316 * \retval -1 \a a is smaller than \a b
317 * \retval 0 \a a is equal to \a b
318 * \retval 1 \a b is smaller than \a a
319 */
sccp_netsock_cmp_port(const struct sockaddr_storage * a,const struct sockaddr_storage * b)320 int sccp_netsock_cmp_port(const struct sockaddr_storage *a, const struct sockaddr_storage *b)
321 {
322 uint16_t a_port = sccp_netsock_getPort(a);
323 uint16_t b_port = sccp_netsock_getPort(b);
324
325 sccp_log(DEBUGCAT_HIGH)(VERBOSE_PREFIX_2 "SCCP: sccp_netsock_cmp_port(%d, %d) returning %d\n", a_port, b_port, (a_port < b_port) ? -1 : (a_port == b_port) ? 0 : 1);
326
327 return (a_port < b_port) ? -1 : (a_port == b_port) ? 0 : 1;
328 }
329
330 /*!
331 * \brief
332 * Splits a string into its host and port components
333 *
334 * \param str [in] The string to parse. May be modified by writing a NUL at the end of
335 * the host part.
336 * \param host [out] Pointer to the host component within \a str.
337 * \param port [out] Pointer to the port component within \a str.
338 * \param flags If set to zero, a port MAY be present. If set to PARSE_PORT_IGNORE, a
339 * port MAY be present but will be ignored. If set to PARSE_PORT_REQUIRE,
340 * a port MUST be present. If set to PARSE_PORT_FORBID, a port MUST NOT
341 * be present.
342 *
343 * \retval 1 Success
344 * \retval 0 Failure
345 */
sccp_netsock_split_hostport(char * str,char ** host,char ** port,int flags)346 int sccp_netsock_split_hostport(char *str, char **host, char **port, int flags)
347 {
348 char *s = str;
349 char *orig_str = str; /* Original string in case the port presence is incorrect. */
350 char *host_end = NULL; /* Delay terminating the host in case the port presence is incorrect. */
351
352 sccp_log(DEBUGCAT_HIGH) (VERBOSE_PREFIX_4 "Splitting '%s' into...\n", str);
353 *host = NULL;
354 *port = NULL;
355 if (*s == '[') {
356 *host = ++s;
357 for (; *s && *s != ']'; ++s) {
358 }
359 if (*s == ']') {
360 host_end = s;
361 ++s;
362 }
363 if (*s == ':') {
364 *port = s + 1;
365 }
366 } else {
367 *host = s;
368 for (; *s; ++s) {
369 if (*s == ':') {
370 if (*port) {
371 *port = NULL;
372 break;
373 } else {
374 *port = s;
375 }
376 }
377 }
378 if (*port) {
379 host_end = *port;
380 ++*port;
381 }
382 }
383
384 switch (flags & PARSE_PORT_MASK) {
385 case PARSE_PORT_IGNORE:
386 *port = NULL;
387 break;
388 case PARSE_PORT_REQUIRE:
389 if (*port == NULL) {
390 pbx_log(LOG_WARNING, "Port missing in %s\n", orig_str);
391 return 0;
392 }
393 break;
394 case PARSE_PORT_FORBID:
395 if (*port != NULL) {
396 pbx_log(LOG_WARNING, "Port disallowed in %s\n", orig_str);
397 return 0;
398 }
399 break;
400 }
401 /* Can terminate the host string now if needed. */
402 if (host_end) {
403 *host_end = '\0';
404 }
405 sccp_log(DEBUGCAT_HIGH) (VERBOSE_PREFIX_4 "...host '%s' and port '%s'.\n", *host, *port ? *port : "");
406 return 1;
407 }
408
409 AST_THREADSTORAGE(sccp_netsock_stringify_buf);
__netsock_stringify_fmt(const struct sockaddr_storage * sockAddrStorage,int format)410 char *__netsock_stringify_fmt(const struct sockaddr_storage *sockAddrStorage, int format)
411 {
412 struct sockaddr_storage sa_ipv4;
413 const struct sockaddr_storage * sockAddrStorage_tmp = NULL;
414 char host[NI_MAXHOST] = "";
415 char port[NI_MAXSERV] = "";
416 struct ast_str * str = NULL;
417 int e = 0;
418 static const size_t size = sizeof(host) - 1 + sizeof(port) - 1 + 4;
419
420 if (!sockAddrStorage) {
421 return "(null)";
422 }
423
424 if (!(str = ast_str_thread_get(&sccp_netsock_stringify_buf, size))) {
425 return "";
426 }
427
428 if(sccp_netsock_is_mapped_IPv4(sockAddrStorage)) {
429 sccp_netsock_ipv4_mapped(sockAddrStorage, &sa_ipv4);
430 sockAddrStorage_tmp = &sa_ipv4;
431 } else {
432 sockAddrStorage_tmp = sockAddrStorage;
433 }
434
435 if ((e = getnameinfo((struct sockaddr *) sockAddrStorage_tmp, sccp_netsock_sizeof(sockAddrStorage_tmp), format & SCCP_SOCKADDR_STR_ADDR ? host : NULL, format & SCCP_SOCKADDR_STR_ADDR ? sizeof(host) : 0, format & SCCP_SOCKADDR_STR_PORT ? port : 0, format & SCCP_SOCKADDR_STR_PORT ? sizeof(port) : 0, NI_NUMERICHOST | NI_NUMERICSERV))) {
436 sccp_log(DEBUGCAT_SOCKET) (VERBOSE_PREFIX_3 "SCCP: getnameinfo(): %s \n", gai_strerror(e));
437 return "";
438 }
439
440 if ((format & SCCP_SOCKADDR_STR_REMOTE) == SCCP_SOCKADDR_STR_REMOTE) {
441 char * p = NULL;
442
443 if (sccp_netsock_is_ipv6_link_local(sockAddrStorage_tmp) && (p = strchr(host, '%'))) {
444 *p = '\0';
445 }
446 }
447 switch ((format & SCCP_SOCKADDR_STR_FORMAT_MASK)) {
448 case SCCP_SOCKADDR_STR_DEFAULT:
449 ast_str_set(&str, 0, sockAddrStorage_tmp->ss_family == AF_INET6 ? "[%s]:%s" : "%s:%s", host, port);
450 break;
451 case SCCP_SOCKADDR_STR_ADDR:
452 ast_str_set(&str, 0, "%s", host);
453 break;
454 case SCCP_SOCKADDR_STR_HOST:
455 ast_str_set(&str, 0, sockAddrStorage_tmp->ss_family == AF_INET6 ? "[%s]" : "%s", host);
456 break;
457 case SCCP_SOCKADDR_STR_PORT:
458 ast_str_set(&str, 0, "%s", port);
459 break;
460 default:
461 pbx_log(LOG_ERROR, "Invalid format\n");
462 return "";
463 }
464
465 return ast_str_buffer(str);
466 }
467
468 #define SCCP_NETSOCK_SETOPTION(_SOCKET, _LEVEL,_OPTIONNAME, _OPTIONVAL, _OPTIONLEN) \
469 if (setsockopt(_SOCKET, _LEVEL, _OPTIONNAME, (void*)(_OPTIONVAL), _OPTIONLEN) == -1) { \
470 if (errno != ENOTSUP) { \
471 pbx_log(LOG_WARNING, "Failed to set SCCP socket: " #_LEVEL ":" #_OPTIONNAME " error: '%s'\n", strerror(errno)); \
472 } \
473 }
474
sccp_netsock_setoptions(int new_socket,int reuse,int linger,int keepalive,int sndtimeout,int rcvtimeout)475 void sccp_netsock_setoptions(int new_socket, int reuse, int linger, int keepalive, int sndtimeout, int rcvtimeout)
476 {
477 int on = 1;
478
479 /* reuse */
480 if (reuse > -1) {
481 SCCP_NETSOCK_SETOPTION(new_socket, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
482 #if defined(SO_REUSEPORT)
483 SCCP_NETSOCK_SETOPTION(new_socket, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(reuse));
484 #endif
485 }
486
487 /* nodelay */
488 SCCP_NETSOCK_SETOPTION(new_socket, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
489
490 /* tos/cos */
491 int value = (int) GLOB(sccp_tos);
492 SCCP_NETSOCK_SETOPTION(new_socket, IPPROTO_IP, IP_TOS, &value, sizeof(value));
493 #if defined(linux)
494 value = (int) GLOB(sccp_cos);
495 SCCP_NETSOCK_SETOPTION(new_socket, SOL_SOCKET, SO_PRIORITY, &value, sizeof(value));
496
497 /* rcvbuf / sndbug */
498 int so_rcvbuf = NETSOCK_RCVBUF;
499 int so_sndbuf = NETSOCK_SNDBUF;
500 SCCP_NETSOCK_SETOPTION(new_socket, SOL_SOCKET, SO_RCVBUF, &so_rcvbuf, sizeof(int));
501 SCCP_NETSOCK_SETOPTION(new_socket, SOL_SOCKET, SO_SNDBUF, &so_sndbuf, sizeof(int));
502
503 /* linger */
504 if (linger > -1) {
505 struct linger so_linger = {linger, NETSOCK_LINGER_WAIT}; /* linger=on but wait NETSOCK_LINGER_WAIT milliseconds before closing socket and discard all outboung messages */
506 SCCP_NETSOCK_SETOPTION(new_socket, SOL_SOCKET, SO_LINGER, &so_linger, sizeof(so_linger));
507 }
508
509 /* timeeo */
510 if (sndtimeout) { /* Setting the send timeout is a must, case because currently we are doing blocking send.
511 * Without this timeout, it could stay in send for a long time, which means the session would
512 * not read the alert pipe, and it could take a lot of time before asking the session
513 * to stop and the session thread exiting, which would then create some partial deadlock
514 * when trying closing all sessions.
515 */
516 struct timeval mytv = { NETSOCK_TIMEOUT_SEC, NETSOCK_TIMEOUT_MILLISEC }; /* timeout after xxxx seconds when trying to write to a socket */
517 SCCP_NETSOCK_SETOPTION(new_socket, SOL_SOCKET, SO_SNDTIMEO, &mytv, sizeof(mytv));
518 }
519
520 if (rcvtimeout) {
521 struct timeval mytv = { NETSOCK_TIMEOUT_SEC, NETSOCK_TIMEOUT_MILLISEC }; /* timeout after xxxx seconds when trying to read from a socket */
522 SCCP_NETSOCK_SETOPTION(new_socket, SOL_SOCKET, SO_RCVTIMEO, &mytv, sizeof(mytv));
523 }
524
525 /* keepalive */
526 if (keepalive > -1) {
527 int ip_keepidle = keepalive; /* The time (in seconds) the connection needs to remain idle before TCP starts sending keepalive probes */
528 int ip_keepintvl = keepalive; /* The time (in seconds) between individual keepalive probes, once we have started to probe. */
529 int ip_keepcnt = NETSOCK_KEEPALIVE_CNT; /* The maximum number of keepalive probes TCP should send before dropping the connection. */
530 SCCP_NETSOCK_SETOPTION(new_socket, SOL_TCP, TCP_KEEPIDLE, &ip_keepidle, sizeof(int));
531 SCCP_NETSOCK_SETOPTION(new_socket, SOL_TCP, TCP_KEEPINTVL, &ip_keepintvl, sizeof(int));
532 SCCP_NETSOCK_SETOPTION(new_socket, SOL_TCP, TCP_KEEPCNT, &ip_keepcnt, sizeof(int));
533 SCCP_NETSOCK_SETOPTION(new_socket, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on));
534 }
535 /* thin-tcp */
536 //#ifdef TCP_THIN_LINEAR_TIMEOUTS
537 // SCCP_NETSOCK_SETOPTION(new_socket, IPPROTO_TCP, TCP_THIN_LINEAR_TIMEOUTS, &on, sizeof(on));
538 // SCCP_NETSOCK_SETOPTION(new_socket, IPPROTO_TCP, TCP_THIN_DUPACK, &on, sizeof(on));
539 //#endif
540 #endif
541 }
542
543 #undef SCCP_NETSOCK_SETOPTION
544
545 // kate: indent-width 8; replace-tabs off; indent-mode cstyle; auto-insert-doxygen on; line-numbers on; tab-indents on; keep-extra-spaces off; auto-brackets off;
546