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