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