1 /* $Id$ */
2 /*
3 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20 #include <pj/sock.h>
21 #include <pj/assert.h>
22 #include <pj/ctype.h>
23 #include <pj/errno.h>
24 #include <pj/ip_helper.h>
25 #include <pj/os.h>
26 #include <pj/addr_resolv.h>
27 #include <pj/rand.h>
28 #include <pj/string.h>
29 #include <pj/compat/socket.h>
30
31 #if 0
32 /* Enable some tracing */
33 #include <pj/log.h>
34 #define THIS_FILE "sock_common.c"
35 #define TRACE_(arg) PJ_LOG(4,arg)
36 #else
37 #define TRACE_(arg)
38 #endif
39
40
41 /*
42 * Convert address string with numbers and dots to binary IP address.
43 */
pj_inet_addr(const pj_str_t * cp)44 PJ_DEF(pj_in_addr) pj_inet_addr(const pj_str_t *cp)
45 {
46 pj_in_addr addr;
47
48 pj_inet_aton(cp, &addr);
49 return addr;
50 }
51
52 /*
53 * Convert address string with numbers and dots to binary IP address.
54 */
pj_inet_addr2(const char * cp)55 PJ_DEF(pj_in_addr) pj_inet_addr2(const char *cp)
56 {
57 pj_str_t str = pj_str((char*)cp);
58 return pj_inet_addr(&str);
59 }
60
61 /*
62 * Get text representation.
63 */
pj_inet_ntop2(int af,const void * src,char * dst,int size)64 PJ_DEF(char*) pj_inet_ntop2( int af, const void *src,
65 char *dst, int size)
66 {
67 pj_status_t status;
68
69 status = pj_inet_ntop(af, src, dst, size);
70 return (status==PJ_SUCCESS)? dst : NULL;
71 }
72
73 /*
74 * Print socket address.
75 */
pj_sockaddr_print(const pj_sockaddr_t * addr,char * buf,int size,unsigned flags)76 PJ_DEF(char*) pj_sockaddr_print( const pj_sockaddr_t *addr,
77 char *buf, int size,
78 unsigned flags)
79 {
80 enum {
81 WITH_PORT = 1,
82 WITH_BRACKETS = 2
83 };
84
85 char txt[PJ_INET6_ADDRSTRLEN];
86 char port[32];
87 const pj_addr_hdr *h = (const pj_addr_hdr*)addr;
88 char *bquote, *equote;
89 pj_status_t status;
90
91 status = pj_inet_ntop(h->sa_family, pj_sockaddr_get_addr(addr),
92 txt, sizeof(txt));
93 if (status != PJ_SUCCESS)
94 return "";
95
96 if (h->sa_family != PJ_AF_INET6 || (flags & WITH_BRACKETS)==0) {
97 bquote = ""; equote = "";
98 } else {
99 bquote = "["; equote = "]";
100 }
101
102 if (flags & WITH_PORT) {
103 pj_ansi_snprintf(port, sizeof(port), ":%d",
104 pj_sockaddr_get_port(addr));
105 } else {
106 port[0] = '\0';
107 }
108
109 pj_ansi_snprintf(buf, size, "%s%s%s%s",
110 bquote, txt, equote, port);
111
112 return buf;
113 }
114
115 /*
116 * Set the IP address of an IP socket address from string address,
117 * with resolving the host if necessary. The string address may be in a
118 * standard numbers and dots notation or may be a hostname. If hostname
119 * is specified, then the function will resolve the host into the IP
120 * address.
121 */
pj_sockaddr_in_set_str_addr(pj_sockaddr_in * addr,const pj_str_t * str_addr)122 PJ_DEF(pj_status_t) pj_sockaddr_in_set_str_addr( pj_sockaddr_in *addr,
123 const pj_str_t *str_addr)
124 {
125 PJ_CHECK_STACK();
126
127 PJ_ASSERT_RETURN(!str_addr || str_addr->slen < PJ_MAX_HOSTNAME,
128 (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL));
129
130 PJ_SOCKADDR_RESET_LEN(addr);
131 addr->sin_family = PJ_AF_INET;
132 pj_bzero(addr->sin_zero_pad, sizeof(addr->sin_zero_pad));
133
134 if (str_addr && str_addr->slen) {
135 addr->sin_addr = pj_inet_addr(str_addr);
136 if (addr->sin_addr.s_addr == PJ_INADDR_NONE) {
137 pj_addrinfo ai;
138 unsigned count = 1;
139 pj_status_t status;
140
141 status = pj_getaddrinfo(pj_AF_INET(), str_addr, &count, &ai);
142 if (status==PJ_SUCCESS) {
143 pj_memcpy(&addr->sin_addr, &ai.ai_addr.ipv4.sin_addr,
144 sizeof(addr->sin_addr));
145 } else {
146 return status;
147 }
148 }
149
150 } else {
151 addr->sin_addr.s_addr = 0;
152 }
153
154 return PJ_SUCCESS;
155 }
156
157 /* Set address from a name */
pj_sockaddr_set_str_addr(int af,pj_sockaddr * addr,const pj_str_t * str_addr)158 PJ_DEF(pj_status_t) pj_sockaddr_set_str_addr(int af,
159 pj_sockaddr *addr,
160 const pj_str_t *str_addr)
161 {
162 pj_status_t status;
163
164 if (af == PJ_AF_INET) {
165 return pj_sockaddr_in_set_str_addr(&addr->ipv4, str_addr);
166 }
167
168 PJ_ASSERT_RETURN(af==PJ_AF_INET6, PJ_EAFNOTSUP);
169
170 /* IPv6 specific */
171
172 addr->ipv6.sin6_family = PJ_AF_INET6;
173 PJ_SOCKADDR_RESET_LEN(addr);
174
175 if (str_addr && str_addr->slen) {
176 #if defined(PJ_SOCKADDR_USE_GETADDRINFO) && PJ_SOCKADDR_USE_GETADDRINFO!=0
177 if (1) {
178 #else
179 status = pj_inet_pton(PJ_AF_INET6, str_addr, &addr->ipv6.sin6_addr);
180 if (status != PJ_SUCCESS) {
181 #endif
182 pj_addrinfo ai;
183 unsigned count = 1;
184
185 status = pj_getaddrinfo(PJ_AF_INET6, str_addr, &count, &ai);
186 if (status==PJ_SUCCESS) {
187 pj_memcpy(&addr->ipv6.sin6_addr, &ai.ai_addr.ipv6.sin6_addr,
188 sizeof(addr->ipv6.sin6_addr));
189 addr->ipv6.sin6_scope_id = ai.ai_addr.ipv6.sin6_scope_id;
190 }
191 }
192 } else {
193 status = PJ_SUCCESS;
194 }
195
196 return status;
197 }
198
199 /*
200 * Set the IP address and port of an IP socket address.
201 * The string address may be in a standard numbers and dots notation or
202 * may be a hostname. If hostname is specified, then the function will
203 * resolve the host into the IP address.
204 */
205 PJ_DEF(pj_status_t) pj_sockaddr_in_init( pj_sockaddr_in *addr,
206 const pj_str_t *str_addr,
207 pj_uint16_t port)
208 {
209 PJ_ASSERT_RETURN(addr, (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL));
210
211 PJ_SOCKADDR_RESET_LEN(addr);
212 addr->sin_family = PJ_AF_INET;
213 pj_bzero(addr->sin_zero_pad, sizeof(addr->sin_zero_pad));
214 pj_sockaddr_in_set_port(addr, port);
215 return pj_sockaddr_in_set_str_addr(addr, str_addr);
216 }
217
218 /*
219 * Initialize IP socket address based on the address and port info.
220 */
221 PJ_DEF(pj_status_t) pj_sockaddr_init(int af,
222 pj_sockaddr *addr,
223 const pj_str_t *cp,
224 pj_uint16_t port)
225 {
226 pj_status_t status;
227
228 if (af == PJ_AF_INET) {
229 return pj_sockaddr_in_init(&addr->ipv4, cp, port);
230 }
231
232 /* IPv6 specific */
233 PJ_ASSERT_RETURN(af==PJ_AF_INET6, PJ_EAFNOTSUP);
234
235 pj_bzero(addr, sizeof(pj_sockaddr_in6));
236 addr->addr.sa_family = PJ_AF_INET6;
237
238 status = pj_sockaddr_set_str_addr(af, addr, cp);
239 if (status != PJ_SUCCESS)
240 return status;
241
242 addr->ipv6.sin6_port = pj_htons(port);
243 return PJ_SUCCESS;
244 }
245
246 /*
247 * Compare two socket addresses.
248 */
249 PJ_DEF(int) pj_sockaddr_cmp( const pj_sockaddr_t *addr1,
250 const pj_sockaddr_t *addr2)
251 {
252 const pj_sockaddr *a1 = (const pj_sockaddr*) addr1;
253 const pj_sockaddr *a2 = (const pj_sockaddr*) addr2;
254 int port1, port2;
255 int result;
256
257 /* Compare address family */
258 if (a1->addr.sa_family < a2->addr.sa_family)
259 return -1;
260 else if (a1->addr.sa_family > a2->addr.sa_family)
261 return 1;
262
263 /* Compare addresses */
264 result = pj_memcmp(pj_sockaddr_get_addr(a1),
265 pj_sockaddr_get_addr(a2),
266 pj_sockaddr_get_addr_len(a1));
267 if (result != 0)
268 return result;
269
270 /* Compare port number */
271 port1 = pj_sockaddr_get_port(a1);
272 port2 = pj_sockaddr_get_port(a2);
273
274 if (port1 < port2)
275 return -1;
276 else if (port1 > port2)
277 return 1;
278
279 /* TODO:
280 * Do we need to compare flow label and scope id in IPv6?
281 */
282
283 /* Looks equal */
284 return 0;
285 }
286
287 /*
288 * Get first IP address associated with the hostname.
289 */
290 PJ_DEF(pj_in_addr) pj_gethostaddr(void)
291 {
292 pj_sockaddr_in addr;
293 const pj_str_t *hostname = pj_gethostname();
294
295 pj_sockaddr_in_set_str_addr(&addr, hostname);
296 return addr.sin_addr;
297 }
298
299 /*
300 * Get port number of a pj_sockaddr_in
301 */
302 PJ_DEF(pj_uint16_t) pj_sockaddr_in_get_port(const pj_sockaddr_in *addr)
303 {
304 return pj_ntohs(addr->sin_port);
305 }
306
307 /*
308 * Get the address part
309 */
310 PJ_DEF(void*) pj_sockaddr_get_addr(const pj_sockaddr_t *addr)
311 {
312 const pj_sockaddr *a = (const pj_sockaddr*)addr;
313
314 PJ_ASSERT_RETURN(a->addr.sa_family == PJ_AF_INET ||
315 a->addr.sa_family == PJ_AF_INET6, NULL);
316
317 if (a->addr.sa_family == PJ_AF_INET6)
318 return (void*) &a->ipv6.sin6_addr;
319 else
320 return (void*) &a->ipv4.sin_addr;
321 }
322
323 /*
324 * Check if sockaddr contains a non-zero address
325 */
326 PJ_DEF(pj_bool_t) pj_sockaddr_has_addr(const pj_sockaddr_t *addr)
327 {
328 const pj_sockaddr *a = (const pj_sockaddr*)addr;
329
330 /* It's probably not wise to raise assertion here if
331 * the address doesn't contain a valid address family, and
332 * just return PJ_FALSE instead.
333 *
334 * The reason is because application may need to distinguish
335 * these three conditions with sockaddr:
336 * a) sockaddr is not initialized. This is by convention
337 * indicated by sa_family==0.
338 * b) sockaddr is initialized with zero address. This is
339 * indicated with the address field having zero address.
340 * c) sockaddr is initialized with valid address/port.
341 *
342 * If we enable this assertion, then application will loose
343 * the capability to specify condition a), since it will be
344 * forced to always initialize sockaddr (even with zero address).
345 * This may break some parts of upper layer libraries.
346 */
347 //PJ_ASSERT_RETURN(a->addr.sa_family == PJ_AF_INET ||
348 // a->addr.sa_family == PJ_AF_INET6, PJ_FALSE);
349
350 if (a->addr.sa_family!=PJ_AF_INET && a->addr.sa_family!=PJ_AF_INET6) {
351 return PJ_FALSE;
352 } else if (a->addr.sa_family == PJ_AF_INET6) {
353 pj_uint8_t zero[24];
354 pj_bzero(zero, sizeof(zero));
355 return pj_memcmp(a->ipv6.sin6_addr.s6_addr, zero,
356 sizeof(pj_in6_addr)) != 0;
357 } else
358 return a->ipv4.sin_addr.s_addr != PJ_INADDR_ANY;
359 }
360
361 /*
362 * Get port number
363 */
364 PJ_DEF(pj_uint16_t) pj_sockaddr_get_port(const pj_sockaddr_t *addr)
365 {
366 const pj_sockaddr *a = (const pj_sockaddr*) addr;
367
368 PJ_ASSERT_RETURN(a->addr.sa_family == PJ_AF_INET ||
369 a->addr.sa_family == PJ_AF_INET6, (pj_uint16_t)0xFFFF);
370
371 return pj_ntohs((pj_uint16_t)(a->addr.sa_family == PJ_AF_INET6 ?
372 a->ipv6.sin6_port : a->ipv4.sin_port));
373 }
374
375 /*
376 * Get the length of the address part.
377 */
378 PJ_DEF(unsigned) pj_sockaddr_get_addr_len(const pj_sockaddr_t *addr)
379 {
380 const pj_sockaddr *a = (const pj_sockaddr*) addr;
381 PJ_ASSERT_RETURN(a->addr.sa_family == PJ_AF_INET ||
382 a->addr.sa_family == PJ_AF_INET6, 0);
383 return a->addr.sa_family == PJ_AF_INET6 ?
384 sizeof(pj_in6_addr) : sizeof(pj_in_addr);
385 }
386
387 /*
388 * Get socket address length.
389 */
390 PJ_DEF(unsigned) pj_sockaddr_get_len(const pj_sockaddr_t *addr)
391 {
392 const pj_sockaddr *a = (const pj_sockaddr*) addr;
393 PJ_ASSERT_RETURN(a->addr.sa_family == PJ_AF_INET ||
394 a->addr.sa_family == PJ_AF_INET6, 0);
395 return a->addr.sa_family == PJ_AF_INET6 ?
396 sizeof(pj_sockaddr_in6) : sizeof(pj_sockaddr_in);
397 }
398
399 /*
400 * Copy only the address part (sin_addr/sin6_addr) of a socket address.
401 */
402 PJ_DEF(void) pj_sockaddr_copy_addr( pj_sockaddr *dst,
403 const pj_sockaddr *src)
404 {
405 /* Destination sockaddr might not be initialized */
406 const char *srcbuf = (char*)pj_sockaddr_get_addr(src);
407 char *dstbuf = ((char*)dst) + (srcbuf - (char*)src);
408 pj_memcpy(dstbuf, srcbuf, pj_sockaddr_get_addr_len(src));
409 }
410
411 /*
412 * Copy socket address.
413 */
414 PJ_DEF(void) pj_sockaddr_cp(pj_sockaddr_t *dst, const pj_sockaddr_t *src)
415 {
416 pj_memcpy(dst, src, pj_sockaddr_get_len(src));
417 }
418
419 /*
420 * Synthesize address.
421 */
422 PJ_DEF(pj_status_t) pj_sockaddr_synthesize(int dst_af,
423 pj_sockaddr_t *dst,
424 const pj_sockaddr_t *src)
425 {
426 char ip_addr_buf[PJ_INET6_ADDRSTRLEN];
427 unsigned int count = 1;
428 pj_addrinfo ai[1];
429 pj_str_t ip_addr;
430 pj_status_t status;
431
432 /* Validate arguments */
433 PJ_ASSERT_RETURN(src && dst, PJ_EINVAL);
434
435 if (dst_af == ((const pj_sockaddr *)src)->addr.sa_family) {
436 pj_sockaddr_cp(dst, src);
437 return PJ_SUCCESS;
438 }
439
440 pj_sockaddr_print(src, ip_addr_buf, sizeof(ip_addr_buf), 0);
441 ip_addr = pj_str(ip_addr_buf);
442
443 /* Try to synthesize address using pj_getaddrinfo(). */
444 status = pj_getaddrinfo(dst_af, &ip_addr, &count, ai);
445 if (status == PJ_SUCCESS && count > 0) {
446 pj_sockaddr_cp(dst, &ai[0].ai_addr);
447 pj_sockaddr_set_port(dst, pj_sockaddr_get_port(src));
448 }
449
450 return status;
451 }
452
453 /*
454 * Set port number of pj_sockaddr_in
455 */
456 PJ_DEF(void) pj_sockaddr_in_set_port(pj_sockaddr_in *addr,
457 pj_uint16_t hostport)
458 {
459 addr->sin_port = pj_htons(hostport);
460 }
461
462 /*
463 * Set port number of pj_sockaddr
464 */
465 PJ_DEF(pj_status_t) pj_sockaddr_set_port(pj_sockaddr *addr,
466 pj_uint16_t hostport)
467 {
468 int af = addr->addr.sa_family;
469
470 PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6, PJ_EINVAL);
471
472 if (af == PJ_AF_INET6)
473 addr->ipv6.sin6_port = pj_htons(hostport);
474 else
475 addr->ipv4.sin_port = pj_htons(hostport);
476
477 return PJ_SUCCESS;
478 }
479
480 /*
481 * Get IPv4 address
482 */
483 PJ_DEF(pj_in_addr) pj_sockaddr_in_get_addr(const pj_sockaddr_in *addr)
484 {
485 pj_in_addr in_addr;
486 in_addr.s_addr = pj_ntohl(addr->sin_addr.s_addr);
487 return in_addr;
488 }
489
490 /*
491 * Set IPv4 address
492 */
493 PJ_DEF(void) pj_sockaddr_in_set_addr(pj_sockaddr_in *addr,
494 pj_uint32_t hostaddr)
495 {
496 addr->sin_addr.s_addr = pj_htonl(hostaddr);
497 }
498
499 /*
500 * Parse address
501 */
502 PJ_DEF(pj_status_t) pj_sockaddr_parse2(int af, unsigned options,
503 const pj_str_t *str,
504 pj_str_t *p_hostpart,
505 pj_uint16_t *p_port,
506 int *raf)
507 {
508 const char *end = str->ptr + str->slen;
509 const char *last_colon_pos = NULL;
510 unsigned colon_cnt = 0;
511 const char *p;
512
513 PJ_ASSERT_RETURN((af==PJ_AF_INET || af==PJ_AF_INET6 || af==PJ_AF_UNSPEC) &&
514 options==0 &&
515 str!=NULL, PJ_EINVAL);
516
517 /* Special handling for empty input */
518 if (str->slen==0 || str->ptr==NULL) {
519 if (p_hostpart)
520 p_hostpart->slen = 0;
521 if (p_port)
522 *p_port = 0;
523 if (raf)
524 *raf = PJ_AF_INET;
525 return PJ_SUCCESS;
526 }
527
528 /* Count the colon and get the last colon */
529 for (p=str->ptr; p!=end; ++p) {
530 if (*p == ':') {
531 ++colon_cnt;
532 last_colon_pos = p;
533 }
534 }
535
536 /* Deduce address family if it's not given */
537 if (af == PJ_AF_UNSPEC) {
538 if (colon_cnt > 1)
539 af = PJ_AF_INET6;
540 else
541 af = PJ_AF_INET;
542 } else if (af == PJ_AF_INET && colon_cnt > 1)
543 return PJ_EINVAL;
544
545 if (raf)
546 *raf = af;
547
548 if (af == PJ_AF_INET) {
549 /* Parse as IPv4. Supported formats:
550 * - "10.0.0.1:80"
551 * - "10.0.0.1"
552 * - "10.0.0.1:"
553 * - ":80"
554 * - ":"
555 */
556 pj_str_t hostpart;
557 unsigned long port;
558
559 hostpart.ptr = (char*)str->ptr;
560
561 if (last_colon_pos) {
562 pj_str_t port_part;
563 int i;
564
565 hostpart.slen = last_colon_pos - str->ptr;
566
567 port_part.ptr = (char*)last_colon_pos + 1;
568 port_part.slen = end - port_part.ptr;
569
570 /* Make sure port number is valid */
571 for (i=0; i<port_part.slen; ++i) {
572 if (!pj_isdigit(port_part.ptr[i]))
573 return PJ_EINVAL;
574 }
575 port = pj_strtoul(&port_part);
576 if (port > 65535)
577 return PJ_EINVAL;
578 } else {
579 hostpart.slen = str->slen;
580 port = 0;
581 }
582
583 if (p_hostpart)
584 *p_hostpart = hostpart;
585 if (p_port)
586 *p_port = (pj_uint16_t)port;
587
588 return PJ_SUCCESS;
589
590 } else if (af == PJ_AF_INET6) {
591
592 /* Parse as IPv6. Supported formats:
593 * - "fe::01:80" ==> note: port number is zero in this case, not 80!
594 * - "[fe::01]:80"
595 * - "fe::01"
596 * - "fe::01:"
597 * - "[fe::01]"
598 * - "[fe::01]:"
599 * - "[::]:80"
600 * - ":::80"
601 * - "[::]"
602 * - "[::]:"
603 * - ":::"
604 * - "::"
605 */
606 pj_str_t hostpart, port_part;
607
608 if (*str->ptr == '[') {
609 char *end_bracket;
610 int i;
611 unsigned long port;
612
613 if (last_colon_pos == NULL)
614 return PJ_EINVAL;
615
616 end_bracket = pj_strchr(str, ']');
617 if (end_bracket == NULL)
618 return PJ_EINVAL;
619
620 hostpart.ptr = (char*)str->ptr + 1;
621 hostpart.slen = end_bracket - hostpart.ptr;
622
623 if (last_colon_pos < end_bracket) {
624 port_part.ptr = NULL;
625 port_part.slen = 0;
626 } else {
627 port_part.ptr = (char*)last_colon_pos + 1;
628 port_part.slen = end - port_part.ptr;
629 }
630
631 /* Make sure port number is valid */
632 for (i=0; i<port_part.slen; ++i) {
633 if (!pj_isdigit(port_part.ptr[i]))
634 return PJ_EINVAL;
635 }
636 port = pj_strtoul(&port_part);
637 if (port > 65535)
638 return PJ_EINVAL;
639
640 if (p_hostpart)
641 *p_hostpart = hostpart;
642 if (p_port)
643 *p_port = (pj_uint16_t)port;
644
645 return PJ_SUCCESS;
646
647 } else {
648 /* Treat everything as part of the IPv6 IP address */
649 if (p_hostpart)
650 *p_hostpart = *str;
651 if (p_port)
652 *p_port = 0;
653
654 return PJ_SUCCESS;
655 }
656
657 } else {
658 return PJ_EAFNOTSUP;
659 }
660
661 }
662
663 /*
664 * Parse address
665 */
666 PJ_DEF(pj_status_t) pj_sockaddr_parse( int af, unsigned options,
667 const pj_str_t *str,
668 pj_sockaddr *addr)
669 {
670 pj_str_t hostpart;
671 pj_uint16_t port;
672 pj_status_t status;
673
674 PJ_ASSERT_RETURN(addr, PJ_EINVAL);
675 PJ_ASSERT_RETURN(af==PJ_AF_UNSPEC ||
676 af==PJ_AF_INET ||
677 af==PJ_AF_INET6, PJ_EINVAL);
678 PJ_ASSERT_RETURN(options == 0, PJ_EINVAL);
679
680 status = pj_sockaddr_parse2(af, options, str, &hostpart, &port, &af);
681 if (status != PJ_SUCCESS)
682 return status;
683
684 #if !defined(PJ_HAS_IPV6) || !PJ_HAS_IPV6
685 if (af==PJ_AF_INET6)
686 return PJ_EIPV6NOTSUP;
687 #endif
688
689 status = pj_sockaddr_init(af, addr, &hostpart, port);
690 #if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6
691 if (status != PJ_SUCCESS && af == PJ_AF_INET6) {
692 /* Parsing does not yield valid address. Try to treat the last
693 * portion after the colon as port number.
694 */
695 const char *last_colon_pos=NULL, *p;
696 const char *end = str->ptr + str->slen;
697 unsigned long long_port;
698 pj_str_t port_part;
699 int i;
700
701 /* Parse as IPv6:port */
702 for (p=str->ptr; p!=end; ++p) {
703 if (*p == ':')
704 last_colon_pos = p;
705 }
706
707 if (last_colon_pos == NULL)
708 return status;
709
710 hostpart.ptr = (char*)str->ptr;
711 hostpart.slen = last_colon_pos - str->ptr;
712
713 port_part.ptr = (char*)last_colon_pos + 1;
714 port_part.slen = end - port_part.ptr;
715
716 /* Make sure port number is valid */
717 for (i=0; i<port_part.slen; ++i) {
718 if (!pj_isdigit(port_part.ptr[i]))
719 return status;
720 }
721 long_port = pj_strtoul(&port_part);
722 if (long_port > 65535)
723 return status;
724
725 port = (pj_uint16_t)long_port;
726
727 status = pj_sockaddr_init(PJ_AF_INET6, addr, &hostpart, port);
728 }
729 #endif
730
731 return status;
732 }
733
734 /* Resolve the IP address of local machine */
735 PJ_DEF(pj_status_t) pj_gethostip(int af, pj_sockaddr *addr)
736 {
737 unsigned i, count, cand_cnt;
738 enum {
739 CAND_CNT = 8,
740
741 /* Weighting to be applied to found addresses */
742 WEIGHT_HOSTNAME = 1, /* hostname IP is not always valid! */
743 WEIGHT_DEF_ROUTE = 2,
744 WEIGHT_INTERFACE = 1,
745 WEIGHT_LOOPBACK = -5,
746 WEIGHT_LINK_LOCAL = -4,
747 WEIGHT_DISABLED = -50,
748
749 MIN_WEIGHT = WEIGHT_DISABLED+1 /* minimum weight to use */
750 };
751 /* candidates: */
752 pj_sockaddr cand_addr[CAND_CNT];
753 int cand_weight[CAND_CNT];
754 int selected_cand;
755 char strip[PJ_INET6_ADDRSTRLEN+10];
756 /* Special IPv4 addresses. */
757 struct spec_ipv4_t
758 {
759 pj_uint32_t addr;
760 pj_uint32_t mask;
761 int weight;
762 } spec_ipv4[] =
763 {
764 /* 127.0.0.0/8, loopback addr will be used if there is no other
765 * addresses.
766 */
767 { 0x7f000000, 0xFF000000, WEIGHT_LOOPBACK },
768
769 /* 0.0.0.0/8, special IP that doesn't seem to be practically useful */
770 { 0x00000000, 0xFF000000, WEIGHT_DISABLED },
771
772 /* 169.254.0.0/16, a zeroconf/link-local address, which has higher
773 * priority than loopback and will be used if there is no other
774 * valid addresses.
775 */
776 { 0xa9fe0000, 0xFFFF0000, WEIGHT_LINK_LOCAL }
777 };
778 /* Special IPv6 addresses */
779 struct spec_ipv6_t
780 {
781 pj_uint8_t addr[16];
782 pj_uint8_t mask[16];
783 int weight;
784 } spec_ipv6[] =
785 {
786 /* Loopback address, ::1/128 */
787 { {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
788 {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
789 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff},
790 WEIGHT_LOOPBACK
791 },
792
793 /* Link local, fe80::/10 */
794 { {0xfe,0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
795 {0xff,0xc0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
796 WEIGHT_LINK_LOCAL
797 },
798
799 /* Disabled, ::/128 */
800 { {0x0,0x0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
801 { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
802 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff},
803 WEIGHT_DISABLED
804 }
805 };
806 pj_addrinfo ai;
807 pj_status_t status;
808
809 /* May not be used if TRACE_ is disabled */
810 PJ_UNUSED_ARG(strip);
811
812 #ifdef _MSC_VER
813 /* Get rid of "uninitialized he variable" with MS compilers */
814 pj_bzero(&ai, sizeof(ai));
815 #endif
816
817 cand_cnt = 0;
818 pj_bzero(cand_addr, sizeof(cand_addr));
819 pj_bzero(cand_weight, sizeof(cand_weight));
820 for (i=0; i<PJ_ARRAY_SIZE(cand_addr); ++i) {
821 cand_addr[i].addr.sa_family = (pj_uint16_t)af;
822 PJ_SOCKADDR_RESET_LEN(&cand_addr[i]);
823 }
824
825 addr->addr.sa_family = (pj_uint16_t)af;
826 PJ_SOCKADDR_RESET_LEN(addr);
827
828 #if !defined(PJ_GETHOSTIP_DISABLE_LOCAL_RESOLUTION) || \
829 PJ_GETHOSTIP_DISABLE_LOCAL_RESOLUTION == 0
830 /* Get hostname's IP address */
831 {
832 const pj_str_t *hostname = pj_gethostname();
833 count = 1;
834
835 if (hostname->slen > 0)
836 status = pj_getaddrinfo(af, hostname, &count, &ai);
837 else
838 status = PJ_ERESOLVE;
839
840 if (status == PJ_SUCCESS) {
841 pj_assert(ai.ai_addr.addr.sa_family == (pj_uint16_t)af);
842 pj_sockaddr_copy_addr(&cand_addr[cand_cnt], &ai.ai_addr);
843 pj_sockaddr_set_port(&cand_addr[cand_cnt], 0);
844 cand_weight[cand_cnt] += WEIGHT_HOSTNAME;
845 ++cand_cnt;
846
847 TRACE_((THIS_FILE, "hostname IP is %s",
848 pj_sockaddr_print(&ai.ai_addr, strip, sizeof(strip), 3)));
849 }
850 }
851 #else
852 PJ_UNUSED_ARG(ai);
853 #endif
854
855 /* Get default interface (interface for default route) */
856 if (cand_cnt < PJ_ARRAY_SIZE(cand_addr)) {
857 status = pj_getdefaultipinterface(af, addr);
858 if (status == PJ_SUCCESS) {
859 TRACE_((THIS_FILE, "default IP is %s",
860 pj_sockaddr_print(addr, strip, sizeof(strip), 3)));
861
862 pj_sockaddr_set_port(addr, 0);
863 for (i=0; i<cand_cnt; ++i) {
864 if (pj_sockaddr_cmp(&cand_addr[i], addr)==0)
865 break;
866 }
867
868 cand_weight[i] += WEIGHT_DEF_ROUTE;
869 if (i >= cand_cnt) {
870 pj_sockaddr_copy_addr(&cand_addr[i], addr);
871 ++cand_cnt;
872 }
873 }
874 }
875
876
877 /* Enumerate IP interfaces */
878 if (cand_cnt < PJ_ARRAY_SIZE(cand_addr)) {
879 unsigned start_if = cand_cnt;
880 count = PJ_ARRAY_SIZE(cand_addr) - start_if;
881
882 status = pj_enum_ip_interface(af, &count, &cand_addr[start_if]);
883 if (status == PJ_SUCCESS && count) {
884 /* Clear the port number */
885 for (i=0; i<count; ++i)
886 pj_sockaddr_set_port(&cand_addr[start_if+i], 0);
887
888 /* For each candidate that we found so far (that is the hostname
889 * address and default interface address, check if they're found
890 * in the interface list. If found, add the weight, and if not,
891 * decrease the weight.
892 */
893 for (i=0; i<cand_cnt; ++i) {
894 unsigned j;
895 for (j=0; j<count; ++j) {
896 if (pj_sockaddr_cmp(&cand_addr[i],
897 &cand_addr[start_if+j])==0)
898 break;
899 }
900
901 if (j == count) {
902 /* Not found */
903 cand_weight[i] -= WEIGHT_INTERFACE;
904 } else {
905 cand_weight[i] += WEIGHT_INTERFACE;
906 }
907 }
908
909 /* Add remaining interface to candidate list. */
910 for (i=0; i<count; ++i) {
911 unsigned j;
912 for (j=0; j<cand_cnt; ++j) {
913 if (pj_sockaddr_cmp(&cand_addr[start_if+i],
914 &cand_addr[j])==0)
915 break;
916 }
917
918 if (j == cand_cnt) {
919 pj_sockaddr_copy_addr(&cand_addr[cand_cnt],
920 &cand_addr[start_if+i]);
921 cand_weight[cand_cnt] += WEIGHT_INTERFACE;
922 ++cand_cnt;
923 }
924 }
925 }
926 }
927
928 /* Apply weight adjustment for special IPv4/IPv6 addresses
929 * See http://trac.pjsip.org/repos/ticket/1046
930 */
931 if (af == PJ_AF_INET) {
932 for (i=0; i<cand_cnt; ++i) {
933 unsigned j;
934 for (j=0; j<PJ_ARRAY_SIZE(spec_ipv4); ++j) {
935 pj_uint32_t a = pj_ntohl(cand_addr[i].ipv4.sin_addr.s_addr);
936 pj_uint32_t pa = spec_ipv4[j].addr;
937 pj_uint32_t pm = spec_ipv4[j].mask;
938
939 if ((a & pm) == pa) {
940 cand_weight[i] += spec_ipv4[j].weight;
941 break;
942 }
943 }
944 }
945 } else if (af == PJ_AF_INET6) {
946 for (i=0; i<PJ_ARRAY_SIZE(spec_ipv6); ++i) {
947 unsigned j;
948 for (j=0; j<cand_cnt; ++j) {
949 pj_uint8_t *a = cand_addr[j].ipv6.sin6_addr.s6_addr;
950 pj_uint8_t am[16];
951 pj_uint8_t *pa = spec_ipv6[i].addr;
952 pj_uint8_t *pm = spec_ipv6[i].mask;
953 unsigned k;
954
955 for (k=0; k<16; ++k) {
956 am[k] = (pj_uint8_t)((a[k] & pm[k]) & 0xFF);
957 }
958
959 if (pj_memcmp(am, pa, 16)==0) {
960 cand_weight[j] += spec_ipv6[i].weight;
961 }
962 }
963 }
964 } else {
965 return PJ_EAFNOTSUP;
966 }
967
968 /* Enumerate candidates to get the best IP address to choose */
969 selected_cand = -1;
970 for (i=0; i<cand_cnt; ++i) {
971 TRACE_((THIS_FILE, "Checking candidate IP %s, weight=%d",
972 pj_sockaddr_print(&cand_addr[i], strip, sizeof(strip), 3),
973 cand_weight[i]));
974
975 if (cand_weight[i] < MIN_WEIGHT) {
976 continue;
977 }
978
979 if (selected_cand == -1)
980 selected_cand = i;
981 else if (cand_weight[i] > cand_weight[selected_cand])
982 selected_cand = i;
983 }
984
985 /* If else fails, returns loopback interface as the last resort */
986 if (selected_cand == -1) {
987 if (af==PJ_AF_INET) {
988 addr->ipv4.sin_addr.s_addr = pj_htonl (0x7f000001);
989 } else {
990 pj_in6_addr *s6_addr_;
991
992 s6_addr_ = (pj_in6_addr*) pj_sockaddr_get_addr(addr);
993 pj_bzero(s6_addr_, sizeof(pj_in6_addr));
994 s6_addr_->s6_addr[15] = 1;
995 }
996 TRACE_((THIS_FILE, "Loopback IP %s returned",
997 pj_sockaddr_print(addr, strip, sizeof(strip), 3)));
998 } else {
999 pj_sockaddr_copy_addr(addr, &cand_addr[selected_cand]);
1000 TRACE_((THIS_FILE, "Candidate %s selected",
1001 pj_sockaddr_print(addr, strip, sizeof(strip), 3)));
1002 }
1003
1004 return PJ_SUCCESS;
1005 }
1006
1007 /* Get IP interface for sending to the specified destination */
1008 PJ_DEF(pj_status_t) pj_getipinterface(int af,
1009 const pj_str_t *dst,
1010 pj_sockaddr *itf_addr,
1011 pj_bool_t allow_resolve,
1012 pj_sockaddr *p_dst_addr)
1013 {
1014 pj_sockaddr dst_addr;
1015 pj_sock_t fd;
1016 int len;
1017 pj_uint8_t zero[64];
1018 pj_status_t status;
1019
1020 pj_sockaddr_init(af, &dst_addr, NULL, 53);
1021 status = pj_inet_pton(af, dst, pj_sockaddr_get_addr(&dst_addr));
1022 if (status != PJ_SUCCESS) {
1023 /* "dst" is not an IP address. */
1024 if (allow_resolve) {
1025 status = pj_sockaddr_init(af, &dst_addr, dst, 53);
1026 } else {
1027 pj_str_t cp;
1028
1029 if (af == PJ_AF_INET) {
1030 cp = pj_str("1.1.1.1");
1031 } else {
1032 cp = pj_str("1::1");
1033 }
1034 status = pj_sockaddr_init(af, &dst_addr, &cp, 53);
1035 }
1036
1037 if (status != PJ_SUCCESS)
1038 return status;
1039 }
1040
1041 /* Create UDP socket and connect() to the destination IP */
1042 status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &fd);
1043 if (status != PJ_SUCCESS) {
1044 return status;
1045 }
1046
1047 status = pj_sock_connect(fd, &dst_addr, pj_sockaddr_get_len(&dst_addr));
1048 if (status != PJ_SUCCESS) {
1049 pj_sock_close(fd);
1050 return status;
1051 }
1052
1053 len = sizeof(*itf_addr);
1054 status = pj_sock_getsockname(fd, itf_addr, &len);
1055 if (status != PJ_SUCCESS) {
1056 pj_sock_close(fd);
1057 return status;
1058 }
1059
1060 pj_sock_close(fd);
1061
1062 /* Check that the address returned is not zero */
1063 pj_bzero(zero, sizeof(zero));
1064 if (pj_memcmp(pj_sockaddr_get_addr(itf_addr), zero,
1065 pj_sockaddr_get_addr_len(itf_addr))==0)
1066 {
1067 return PJ_ENOTFOUND;
1068 }
1069
1070 if (p_dst_addr)
1071 *p_dst_addr = dst_addr;
1072
1073 return PJ_SUCCESS;
1074 }
1075
1076 /* Get the default IP interface */
1077 PJ_DEF(pj_status_t) pj_getdefaultipinterface(int af, pj_sockaddr *addr)
1078 {
1079 pj_str_t cp;
1080
1081 if (af == PJ_AF_INET) {
1082 cp = pj_str("1.1.1.1");
1083 } else {
1084 cp = pj_str("1::1");
1085 }
1086
1087 return pj_getipinterface(af, &cp, addr, PJ_FALSE, NULL);
1088 }
1089
1090
1091 /*
1092 * Bind socket at random port.
1093 */
1094 PJ_DEF(pj_status_t) pj_sock_bind_random( pj_sock_t sockfd,
1095 const pj_sockaddr_t *addr,
1096 pj_uint16_t port_range,
1097 pj_uint16_t max_try)
1098 {
1099 pj_sockaddr bind_addr;
1100 int addr_len;
1101 pj_uint16_t base_port;
1102 pj_status_t status = PJ_SUCCESS;
1103
1104 PJ_CHECK_STACK();
1105
1106 PJ_ASSERT_RETURN(addr, PJ_EINVAL);
1107
1108 pj_sockaddr_cp(&bind_addr, addr);
1109 addr_len = pj_sockaddr_get_len(addr);
1110 base_port = pj_sockaddr_get_port(addr);
1111
1112 if (base_port == 0 || port_range == 0) {
1113 return pj_sock_bind(sockfd, &bind_addr, addr_len);
1114 }
1115
1116 for (; max_try; --max_try) {
1117 pj_uint16_t port;
1118 port = (pj_uint16_t)(base_port + pj_rand() % (port_range + 1));
1119 pj_sockaddr_set_port(&bind_addr, port);
1120 status = pj_sock_bind(sockfd, &bind_addr, addr_len);
1121 if (status == PJ_SUCCESS)
1122 break;
1123 }
1124
1125 return status;
1126 }
1127
1128
1129 /*
1130 * Adjust socket send/receive buffer size.
1131 */
1132 PJ_DEF(pj_status_t) pj_sock_setsockopt_sobuf( pj_sock_t sockfd,
1133 pj_uint16_t optname,
1134 pj_bool_t auto_retry,
1135 unsigned *buf_size)
1136 {
1137 pj_status_t status;
1138 int try_size, cur_size, i, step, size_len;
1139 enum { MAX_TRY = 20 };
1140
1141 PJ_CHECK_STACK();
1142
1143 PJ_ASSERT_RETURN(sockfd != PJ_INVALID_SOCKET &&
1144 buf_size &&
1145 *buf_size > 0 &&
1146 (optname == pj_SO_RCVBUF() ||
1147 optname == pj_SO_SNDBUF()),
1148 PJ_EINVAL);
1149
1150 size_len = sizeof(cur_size);
1151 status = pj_sock_getsockopt(sockfd, pj_SOL_SOCKET(), optname,
1152 &cur_size, &size_len);
1153 if (status != PJ_SUCCESS)
1154 return status;
1155
1156 try_size = *buf_size;
1157 step = (try_size - cur_size) / MAX_TRY;
1158 if (step < 4096)
1159 step = 4096;
1160
1161 for (i = 0; i < (MAX_TRY-1); ++i) {
1162 if (try_size <= cur_size) {
1163 /* Done, return current size */
1164 *buf_size = cur_size;
1165 break;
1166 }
1167
1168 status = pj_sock_setsockopt(sockfd, pj_SOL_SOCKET(), optname,
1169 &try_size, sizeof(try_size));
1170 if (status == PJ_SUCCESS) {
1171 status = pj_sock_getsockopt(sockfd, pj_SOL_SOCKET(), optname,
1172 &cur_size, &size_len);
1173 if (status != PJ_SUCCESS) {
1174 /* Ops! No info about current size, just return last try size
1175 * and quit.
1176 */
1177 *buf_size = try_size;
1178 break;
1179 }
1180 }
1181
1182 if (!auto_retry)
1183 break;
1184
1185 try_size -= step;
1186 }
1187
1188 return status;
1189 }
1190
1191
1192 PJ_DEF(char *) pj_addr_str_print( const pj_str_t *host_str, int port,
1193 char *buf, int size, unsigned flag)
1194 {
1195 enum {
1196 WITH_PORT = 1
1197 };
1198 char *bquote, *equote;
1199 int af = pj_AF_UNSPEC();
1200 pj_in6_addr dummy6;
1201
1202 /* Check if this is an IPv6 address */
1203 if (pj_inet_pton(pj_AF_INET6(), host_str, &dummy6) == PJ_SUCCESS)
1204 af = pj_AF_INET6();
1205
1206 if (af == pj_AF_INET6()) {
1207 bquote = "[";
1208 equote = "]";
1209 } else {
1210 bquote = "";
1211 equote = "";
1212 }
1213
1214 if (flag & WITH_PORT) {
1215 pj_ansi_snprintf(buf, size, "%s%.*s%s:%d",
1216 bquote, (int)host_str->slen, host_str->ptr, equote,
1217 port);
1218 } else {
1219 pj_ansi_snprintf(buf, size, "%s%.*s%s",
1220 bquote, (int)host_str->slen, host_str->ptr, equote);
1221 }
1222 return buf;
1223 }
1224
1225
1226 /* Only need to implement these in DLL build */
1227 #if defined(PJ_DLL)
1228
1229 PJ_DEF(pj_uint16_t) pj_AF_UNSPEC(void)
1230 {
1231 return PJ_AF_UNSPEC;
1232 }
1233
1234 PJ_DEF(pj_uint16_t) pj_AF_UNIX(void)
1235 {
1236 return PJ_AF_UNIX;
1237 }
1238
1239 PJ_DEF(pj_uint16_t) pj_AF_INET(void)
1240 {
1241 return PJ_AF_INET;
1242 }
1243
1244 PJ_DEF(pj_uint16_t) pj_AF_INET6(void)
1245 {
1246 return PJ_AF_INET6;
1247 }
1248
1249 PJ_DEF(pj_uint16_t) pj_AF_PACKET(void)
1250 {
1251 return PJ_AF_PACKET;
1252 }
1253
1254 PJ_DEF(pj_uint16_t) pj_AF_IRDA(void)
1255 {
1256 return PJ_AF_IRDA;
1257 }
1258
1259 PJ_DEF(int) pj_SOCK_STREAM(void)
1260 {
1261 return PJ_SOCK_STREAM;
1262 }
1263
1264 PJ_DEF(int) pj_SOCK_DGRAM(void)
1265 {
1266 return PJ_SOCK_DGRAM;
1267 }
1268
1269 PJ_DEF(int) pj_SOCK_RAW(void)
1270 {
1271 return PJ_SOCK_RAW;
1272 }
1273
1274 PJ_DEF(int) pj_SOCK_RDM(void)
1275 {
1276 return PJ_SOCK_RDM;
1277 }
1278
1279 PJ_DEF(pj_uint16_t) pj_SOL_SOCKET(void)
1280 {
1281 return PJ_SOL_SOCKET;
1282 }
1283
1284 PJ_DEF(pj_uint16_t) pj_SOL_IP(void)
1285 {
1286 return PJ_SOL_IP;
1287 }
1288
1289 PJ_DEF(pj_uint16_t) pj_SOL_TCP(void)
1290 {
1291 return PJ_SOL_TCP;
1292 }
1293
1294 PJ_DEF(pj_uint16_t) pj_SOL_UDP(void)
1295 {
1296 return PJ_SOL_UDP;
1297 }
1298
1299 PJ_DEF(pj_uint16_t) pj_SOL_IPV6(void)
1300 {
1301 return PJ_SOL_IPV6;
1302 }
1303
1304 PJ_DEF(int) pj_IP_TOS(void)
1305 {
1306 return PJ_IP_TOS;
1307 }
1308
1309 PJ_DEF(int) pj_IPTOS_LOWDELAY(void)
1310 {
1311 return PJ_IPTOS_LOWDELAY;
1312 }
1313
1314 PJ_DEF(int) pj_IPTOS_THROUGHPUT(void)
1315 {
1316 return PJ_IPTOS_THROUGHPUT;
1317 }
1318
1319 PJ_DEF(int) pj_IPTOS_RELIABILITY(void)
1320 {
1321 return PJ_IPTOS_RELIABILITY;
1322 }
1323
1324 PJ_DEF(int) pj_IPTOS_MINCOST(void)
1325 {
1326 return PJ_IPTOS_MINCOST;
1327 }
1328
1329 PJ_DEF(int) pj_IPV6_TCLASS(void)
1330 {
1331 return PJ_IPV6_TCLASS;
1332 }
1333
1334 PJ_DEF(pj_uint16_t) pj_SO_TYPE(void)
1335 {
1336 return PJ_SO_TYPE;
1337 }
1338
1339 PJ_DEF(pj_uint16_t) pj_SO_RCVBUF(void)
1340 {
1341 return PJ_SO_RCVBUF;
1342 }
1343
1344 PJ_DEF(pj_uint16_t) pj_SO_SNDBUF(void)
1345 {
1346 return PJ_SO_SNDBUF;
1347 }
1348
1349 PJ_DEF(pj_uint16_t) pj_TCP_NODELAY(void)
1350 {
1351 return PJ_TCP_NODELAY;
1352 }
1353
1354 PJ_DEF(pj_uint16_t) pj_SO_REUSEADDR(void)
1355 {
1356 return PJ_SO_REUSEADDR;
1357 }
1358
1359 PJ_DEF(pj_uint16_t) pj_SO_NOSIGPIPE(void)
1360 {
1361 return PJ_SO_NOSIGPIPE;
1362 }
1363
1364 PJ_DEF(pj_uint16_t) pj_SO_PRIORITY(void)
1365 {
1366 return PJ_SO_PRIORITY;
1367 }
1368
1369 PJ_DEF(pj_uint16_t) pj_IP_MULTICAST_IF(void)
1370 {
1371 return PJ_IP_MULTICAST_IF;
1372 }
1373
1374 PJ_DEF(pj_uint16_t) pj_IP_MULTICAST_TTL(void)
1375 {
1376 return PJ_IP_MULTICAST_TTL;
1377 }
1378
1379 PJ_DEF(pj_uint16_t) pj_IP_MULTICAST_LOOP(void)
1380 {
1381 return PJ_IP_MULTICAST_LOOP;
1382 }
1383
1384 PJ_DEF(pj_uint16_t) pj_IP_ADD_MEMBERSHIP(void)
1385 {
1386 return PJ_IP_ADD_MEMBERSHIP;
1387 }
1388
1389 PJ_DEF(pj_uint16_t) pj_IP_DROP_MEMBERSHIP(void)
1390 {
1391 return PJ_IP_DROP_MEMBERSHIP;
1392 }
1393
1394 PJ_DEF(int) pj_MSG_OOB(void)
1395 {
1396 return PJ_MSG_OOB;
1397 }
1398
1399 PJ_DEF(int) pj_MSG_PEEK(void)
1400 {
1401 return PJ_MSG_PEEK;
1402 }
1403
1404 PJ_DEF(int) pj_MSG_DONTROUTE(void)
1405 {
1406 return PJ_MSG_DONTROUTE;
1407 }
1408
1409 #endif /* PJ_DLL */
1410
1411