blob: 0317fc66c6c1b4b9ce00be0785ac22c6c0947eed [file] [log] [blame]
Benny Prijono8ab968f2007-07-20 08:08:30 +00001/* $Id$ */
2/*
Benny Prijono844653c2008-12-23 17:27:53 +00003 * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
Benny Prijono8ab968f2007-07-20 08:08:30 +00005 *
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>
Benny Prijono62b86eb2007-12-01 08:52:57 +000021#include <pj/assert.h>
Benny Prijono0f4b9db2009-06-04 15:11:25 +000022#include <pj/ctype.h>
Benny Prijono62b86eb2007-12-01 08:52:57 +000023#include <pj/errno.h>
24#include <pj/ip_helper.h>
25#include <pj/os.h>
26#include <pj/addr_resolv.h>
27#include <pj/string.h>
28#include <pj/compat/socket.h>
29
Benny Prijono27fc1432009-04-28 13:47:45 +000030#if 0
31 /* Enable some tracing */
32 #include <pj/log.h>
33 #define THIS_FILE "sock_common.c"
34 #define TRACE_(arg) PJ_LOG(4,arg)
35#else
36 #define TRACE_(arg)
37#endif
38
Benny Prijono62b86eb2007-12-01 08:52:57 +000039
40/*
41 * Convert address string with numbers and dots to binary IP address.
42 */
43PJ_DEF(pj_in_addr) pj_inet_addr(const pj_str_t *cp)
44{
45 pj_in_addr addr;
46
47 pj_inet_aton(cp, &addr);
48 return addr;
49}
50
51/*
52 * Convert address string with numbers and dots to binary IP address.
53 */
54PJ_DEF(pj_in_addr) pj_inet_addr2(const char *cp)
55{
56 pj_str_t str = pj_str((char*)cp);
57 return pj_inet_addr(&str);
58}
59
60/*
Benny Prijono80025db2007-12-02 15:36:46 +000061 * Get text representation.
62 */
63PJ_DEF(char*) pj_inet_ntop2( int af, const void *src,
64 char *dst, int size)
65{
66 pj_status_t status;
67
68 status = pj_inet_ntop(af, src, dst, size);
69 return (status==PJ_SUCCESS)? dst : NULL;
70}
71
72/*
Benny Prijono40c26332007-12-03 14:33:39 +000073 * Print socket address.
74 */
75PJ_DEF(char*) pj_sockaddr_print( const pj_sockaddr_t *addr,
76 char *buf, int size,
77 unsigned flags)
78{
79 enum {
80 WITH_PORT = 1,
81 WITH_BRACKETS = 2
82 };
83
84 char txt[PJ_INET6_ADDRSTRLEN];
85 char port[32];
86 const pj_addr_hdr *h = (const pj_addr_hdr*)addr;
87 char *bquote, *equote;
88 pj_status_t status;
89
90 status = pj_inet_ntop(h->sa_family, pj_sockaddr_get_addr(addr),
91 txt, sizeof(txt));
92 if (status != PJ_SUCCESS)
93 return "";
94
95 if (h->sa_family != PJ_AF_INET6 || (flags & WITH_BRACKETS)==0) {
96 bquote = ""; equote = "";
97 } else {
98 bquote = "["; equote = "]";
99 }
100
101 if (flags & WITH_PORT) {
102 pj_ansi_snprintf(port, sizeof(port), ":%d",
103 pj_sockaddr_get_port(addr));
104 } else {
105 port[0] = '\0';
106 }
107
108 pj_ansi_snprintf(buf, size, "%s%s%s%s",
109 bquote, txt, equote, port);
110
111 return buf;
112}
113
114/*
Benny Prijono62b86eb2007-12-01 08:52:57 +0000115 * Set the IP address of an IP socket address from string address,
116 * with resolving the host if necessary. The string address may be in a
117 * standard numbers and dots notation or may be a hostname. If hostname
118 * is specified, then the function will resolve the host into the IP
119 * address.
120 */
121PJ_DEF(pj_status_t) pj_sockaddr_in_set_str_addr( pj_sockaddr_in *addr,
122 const pj_str_t *str_addr)
123{
124 PJ_CHECK_STACK();
125
126 PJ_ASSERT_RETURN(!str_addr || str_addr->slen < PJ_MAX_HOSTNAME,
127 (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL));
128
129 PJ_SOCKADDR_RESET_LEN(addr);
130 addr->sin_family = AF_INET;
131 pj_bzero(addr->sin_zero, sizeof(addr->sin_zero));
132
133 if (str_addr && str_addr->slen) {
134 addr->sin_addr = pj_inet_addr(str_addr);
135 if (addr->sin_addr.s_addr == PJ_INADDR_NONE) {
136 pj_hostent he;
137 pj_status_t rc;
138
139 rc = pj_gethostbyname(str_addr, &he);
140 if (rc == 0) {
141 addr->sin_addr.s_addr = *(pj_uint32_t*)he.h_addr;
142 } else {
143 addr->sin_addr.s_addr = PJ_INADDR_NONE;
144 return rc;
145 }
146 }
147
148 } else {
149 addr->sin_addr.s_addr = 0;
150 }
151
152 return PJ_SUCCESS;
153}
154
155/* Set address from a name */
156PJ_DEF(pj_status_t) pj_sockaddr_set_str_addr(int af,
157 pj_sockaddr *addr,
158 const pj_str_t *str_addr)
159{
160 pj_status_t status;
161
162 if (af == PJ_AF_INET) {
163 return pj_sockaddr_in_set_str_addr(&addr->ipv4, str_addr);
164 }
165
166 PJ_ASSERT_RETURN(af==PJ_AF_INET6, PJ_EAFNOTSUP);
167
168 /* IPv6 specific */
169
170 addr->ipv6.sin6_family = PJ_AF_INET6;
171 PJ_SOCKADDR_RESET_LEN(addr);
172
173 if (str_addr && str_addr->slen) {
174 status = pj_inet_pton(PJ_AF_INET6, str_addr, &addr->ipv6.sin6_addr);
175 if (status != PJ_SUCCESS) {
176 pj_addrinfo ai;
177 unsigned count = 1;
178
179 status = pj_getaddrinfo(PJ_AF_INET6, str_addr, &count, &ai);
180 if (status==PJ_SUCCESS) {
181 pj_memcpy(&addr->ipv6.sin6_addr, &ai.ai_addr.ipv6.sin6_addr,
182 sizeof(pj_sockaddr_in6));
183 }
184 }
185 } else {
186 status = PJ_SUCCESS;
187 }
188
189 return status;
190}
191
192/*
193 * Set the IP address and port of an IP socket address.
194 * The string address may be in a standard numbers and dots notation or
195 * may be a hostname. If hostname is specified, then the function will
196 * resolve the host into the IP address.
197 */
198PJ_DEF(pj_status_t) pj_sockaddr_in_init( pj_sockaddr_in *addr,
199 const pj_str_t *str_addr,
200 pj_uint16_t port)
201{
202 PJ_ASSERT_RETURN(addr, (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL));
203
204 PJ_SOCKADDR_RESET_LEN(addr);
205 addr->sin_family = PJ_AF_INET;
206 pj_bzero(addr->sin_zero, sizeof(addr->sin_zero));
207 pj_sockaddr_in_set_port(addr, port);
208 return pj_sockaddr_in_set_str_addr(addr, str_addr);
209}
210
211/*
212 * Initialize IP socket address based on the address and port info.
213 */
214PJ_DEF(pj_status_t) pj_sockaddr_init(int af,
215 pj_sockaddr *addr,
216 const pj_str_t *cp,
217 pj_uint16_t port)
218{
219 pj_status_t status;
220
221 if (af == PJ_AF_INET) {
222 return pj_sockaddr_in_init(&addr->ipv4, cp, port);
223 }
224
225 /* IPv6 specific */
226 PJ_ASSERT_RETURN(af==PJ_AF_INET6, PJ_EAFNOTSUP);
227
228 pj_bzero(addr, sizeof(pj_sockaddr_in6));
229 addr->addr.sa_family = PJ_AF_INET6;
230
231 status = pj_sockaddr_set_str_addr(af, addr, cp);
232 if (status != PJ_SUCCESS)
233 return status;
234
235 addr->ipv6.sin6_port = pj_htons(port);
236 return PJ_SUCCESS;
237}
238
239/*
Benny Prijono40c26332007-12-03 14:33:39 +0000240 * Compare two socket addresses.
241 */
242PJ_DEF(int) pj_sockaddr_cmp( const pj_sockaddr_t *addr1,
243 const pj_sockaddr_t *addr2)
244{
245 const pj_sockaddr *a1 = (const pj_sockaddr*) addr1;
246 const pj_sockaddr *a2 = (const pj_sockaddr*) addr2;
247 int port1, port2;
248 int result;
249
250 /* Compare address family */
251 if (a1->addr.sa_family < a2->addr.sa_family)
252 return -1;
253 else if (a1->addr.sa_family > a2->addr.sa_family)
254 return 1;
255
256 /* Compare addresses */
257 result = pj_memcmp(pj_sockaddr_get_addr(a1),
258 pj_sockaddr_get_addr(a2),
259 pj_sockaddr_get_addr_len(a1));
260 if (result != 0)
261 return result;
262
263 /* Compare port number */
264 port1 = pj_sockaddr_get_port(a1);
265 port2 = pj_sockaddr_get_port(a2);
266
267 if (port1 < port2)
268 return -1;
269 else if (port1 > port2)
270 return 1;
271
272 /* TODO:
273 * Do we need to compare flow label and scope id in IPv6?
274 */
275
276 /* Looks equal */
277 return 0;
278}
279
280/*
Benny Prijono62b86eb2007-12-01 08:52:57 +0000281 * Get first IP address associated with the hostname.
282 */
283PJ_DEF(pj_in_addr) pj_gethostaddr(void)
284{
285 pj_sockaddr_in addr;
286 const pj_str_t *hostname = pj_gethostname();
287
288 pj_sockaddr_in_set_str_addr(&addr, hostname);
289 return addr.sin_addr;
290}
291
292/*
293 * Get port number of a pj_sockaddr_in
294 */
295PJ_DEF(pj_uint16_t) pj_sockaddr_in_get_port(const pj_sockaddr_in *addr)
296{
297 return pj_ntohs(addr->sin_port);
298}
299
300/*
301 * Get the address part
302 */
303PJ_DEF(void*) pj_sockaddr_get_addr(const pj_sockaddr_t *addr)
304{
305 const pj_sockaddr *a = (const pj_sockaddr*)addr;
306
307 PJ_ASSERT_RETURN(a->addr.sa_family == PJ_AF_INET ||
308 a->addr.sa_family == PJ_AF_INET6, NULL);
309
310 if (a->addr.sa_family == PJ_AF_INET6)
311 return (void*) &a->ipv6.sin6_addr;
312 else
313 return (void*) &a->ipv4.sin_addr;
314}
315
316/*
317 * Check if sockaddr contains a non-zero address
318 */
319PJ_DEF(pj_bool_t) pj_sockaddr_has_addr(const pj_sockaddr_t *addr)
320{
321 const pj_sockaddr *a = (const pj_sockaddr*)addr;
322
Benny Prijonobb7b98e2007-12-12 17:13:34 +0000323 /* It's probably not wise to raise assertion here if
324 * the address doesn't contain a valid address family, and
325 * just return PJ_FALSE instead.
326 *
327 * The reason is because application may need to distinguish
328 * these three conditions with sockaddr:
329 * a) sockaddr is not initialized. This is by convention
330 * indicated by sa_family==0.
331 * b) sockaddr is initialized with zero address. This is
332 * indicated with the address field having zero address.
333 * c) sockaddr is initialized with valid address/port.
334 *
335 * If we enable this assertion, then application will loose
336 * the capability to specify condition a), since it will be
337 * forced to always initialize sockaddr (even with zero address).
338 * This may break some parts of upper layer libraries.
339 */
340 //PJ_ASSERT_RETURN(a->addr.sa_family == PJ_AF_INET ||
341 // a->addr.sa_family == PJ_AF_INET6, PJ_EAFNOTSUP);
Benny Prijono62b86eb2007-12-01 08:52:57 +0000342
Benny Prijonobb7b98e2007-12-12 17:13:34 +0000343 if (a->addr.sa_family!=PJ_AF_INET && a->addr.sa_family!=PJ_AF_INET6) {
344 return PJ_FALSE;
345 } else if (a->addr.sa_family == PJ_AF_INET6) {
Benny Prijono62b86eb2007-12-01 08:52:57 +0000346 pj_uint8_t zero[24];
347 pj_bzero(zero, sizeof(zero));
348 return pj_memcmp(a->ipv6.sin6_addr.s6_addr, zero,
349 sizeof(pj_in6_addr)) != 0;
350 } else
351 return a->ipv4.sin_addr.s_addr != PJ_INADDR_ANY;
352}
353
354/*
355 * Get port number
356 */
357PJ_DEF(pj_uint16_t) pj_sockaddr_get_port(const pj_sockaddr_t *addr)
358{
359 const pj_sockaddr *a = (const pj_sockaddr*) addr;
360
361 PJ_ASSERT_RETURN(a->addr.sa_family == PJ_AF_INET ||
362 a->addr.sa_family == PJ_AF_INET6, (pj_uint16_t)0xFFFF);
363
364 return pj_ntohs((pj_uint16_t)(a->addr.sa_family == PJ_AF_INET6 ?
365 a->ipv6.sin6_port : a->ipv4.sin_port));
366}
367
368/*
369 * Get the length of the address part.
370 */
371PJ_DEF(unsigned) pj_sockaddr_get_addr_len(const pj_sockaddr_t *addr)
372{
373 const pj_sockaddr *a = (const pj_sockaddr*) addr;
374 PJ_ASSERT_RETURN(a->addr.sa_family == PJ_AF_INET ||
375 a->addr.sa_family == PJ_AF_INET6, PJ_EAFNOTSUP);
376 return a->addr.sa_family == PJ_AF_INET6 ?
377 sizeof(pj_in6_addr) : sizeof(pj_in_addr);
378}
379
380/*
Benny Prijono80025db2007-12-02 15:36:46 +0000381 * Get socket address length.
382 */
383PJ_DEF(unsigned) pj_sockaddr_get_len(const pj_sockaddr_t *addr)
384{
385 const pj_sockaddr *a = (const pj_sockaddr*) addr;
386 PJ_ASSERT_RETURN(a->addr.sa_family == PJ_AF_INET ||
387 a->addr.sa_family == PJ_AF_INET6, PJ_EAFNOTSUP);
388 return a->addr.sa_family == PJ_AF_INET6 ?
389 sizeof(pj_sockaddr_in6) : sizeof(pj_sockaddr_in);
390}
391
392/*
Benny Prijono40c26332007-12-03 14:33:39 +0000393 * Copy only the address part (sin_addr/sin6_addr) of a socket address.
394 */
395PJ_DEF(void) pj_sockaddr_copy_addr( pj_sockaddr *dst,
396 const pj_sockaddr *src)
397{
Benny Prijono1243ffb2008-08-13 08:41:42 +0000398 /* Destination sockaddr might not be initialized */
399 const char *srcbuf = (char*)pj_sockaddr_get_addr(src);
400 char *dstbuf = ((char*)dst) + (srcbuf - (char*)src);
401 pj_memcpy(dstbuf, srcbuf, pj_sockaddr_get_addr_len(src));
Benny Prijono40c26332007-12-03 14:33:39 +0000402}
403
404/*
Benny Prijono842754c2008-05-11 18:11:32 +0000405 * Copy socket address.
406 */
407PJ_DEF(void) pj_sockaddr_cp(pj_sockaddr_t *dst, const pj_sockaddr_t *src)
408{
409 pj_memcpy(dst, src, pj_sockaddr_get_len(src));
410}
411
412/*
Benny Prijono62b86eb2007-12-01 08:52:57 +0000413 * Set port number of pj_sockaddr_in
414 */
415PJ_DEF(void) pj_sockaddr_in_set_port(pj_sockaddr_in *addr,
416 pj_uint16_t hostport)
417{
418 addr->sin_port = pj_htons(hostport);
419}
420
421/*
422 * Set port number of pj_sockaddr
423 */
424PJ_DEF(pj_status_t) pj_sockaddr_set_port(pj_sockaddr *addr,
425 pj_uint16_t hostport)
426{
427 int af = addr->addr.sa_family;
428
Benny Prijono80025db2007-12-02 15:36:46 +0000429 PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6, PJ_EINVAL);
Benny Prijono62b86eb2007-12-01 08:52:57 +0000430
431 if (af == PJ_AF_INET6)
432 addr->ipv6.sin6_port = pj_htons(hostport);
433 else
434 addr->ipv4.sin_port = pj_htons(hostport);
435
436 return PJ_SUCCESS;
437}
438
439/*
440 * Get IPv4 address
441 */
442PJ_DEF(pj_in_addr) pj_sockaddr_in_get_addr(const pj_sockaddr_in *addr)
443{
444 pj_in_addr in_addr;
445 in_addr.s_addr = pj_ntohl(addr->sin_addr.s_addr);
446 return in_addr;
447}
448
449/*
450 * Set IPv4 address
451 */
452PJ_DEF(void) pj_sockaddr_in_set_addr(pj_sockaddr_in *addr,
453 pj_uint32_t hostaddr)
454{
455 addr->sin_addr.s_addr = pj_htonl(hostaddr);
456}
457
Benny Prijono0f4b9db2009-06-04 15:11:25 +0000458/*
459 * Parse address
460 */
461PJ_DEF(pj_status_t) pj_sockaddr_parse( int af, unsigned options,
462 const pj_str_t *str,
463 pj_sockaddr *addr)
464{
465 const char *end = str->ptr + str->slen;
466 const char *last_colon_pos = NULL;
467
468 PJ_ASSERT_RETURN(addr, PJ_EINVAL);
469 PJ_ASSERT_RETURN(af==PJ_AF_UNSPEC ||
470 af==PJ_AF_INET ||
471 af==PJ_AF_INET6, PJ_EINVAL);
472 PJ_ASSERT_RETURN(options == 0, PJ_EINVAL);
473
474 /* Deduce address family if it's not given */
475 if (af == PJ_AF_UNSPEC) {
476 unsigned colon_cnt = 0;
477 const char *p;
478
479 /* Can't accept NULL or empty input if address family is unknown */
480 PJ_ASSERT_RETURN(str && str->slen, PJ_EINVAL);
481
482 for (p=str->ptr; p!=end; ++p) {
483 if (*p == ':') {
484 ++colon_cnt;
485 last_colon_pos = p;
486 }
487 }
488
489 if (colon_cnt > 1)
490 af = PJ_AF_INET6;
491 else
492 af = PJ_AF_INET;
493 } else {
494 /* Input may be NULL or empty as long as address family is given */
495 if (str == NULL || str->slen == 0)
496 return pj_sockaddr_init(af, addr, NULL, 0);
497 }
498
499 if (af == PJ_AF_INET) {
500 /* Parse as IPv4. Supported formats:
501 * - "10.0.0.1:80"
502 * - "10.0.0.1"
503 * - "10.0.0.1:"
504 * - ":80"
505 * - ":"
506 */
507 pj_str_t ip_part;
508 unsigned long port;
509
510 if (last_colon_pos == NULL)
511 last_colon_pos = pj_strchr(str, ':');
512
513 ip_part.ptr = (char*)str->ptr;
514
515 if (last_colon_pos) {
516 pj_str_t port_part;
517 int i;
518
519 ip_part.slen = last_colon_pos - str->ptr;
520
521 port_part.ptr = (char*)last_colon_pos + 1;
522 port_part.slen = end - port_part.ptr;
523
524 /* Make sure port number is valid */
525 for (i=0; i<port_part.slen; ++i) {
526 if (!pj_isdigit(port_part.ptr[i]))
527 return PJ_EINVAL;
528 }
529 port = pj_strtoul(&port_part);
530 if (port > 65535)
531 return PJ_EINVAL;
532 } else {
533 ip_part.slen = str->slen;
534 port = 0;
535 }
536
537 return pj_sockaddr_in_init(&addr->ipv4, &ip_part, (pj_uint16_t)port);
538 }
539#if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6
540 else if (af == PJ_AF_INET6) {
541 /* Parse as IPv4. Supported formats:
542 * - "fe::01:80" ==> note: port number is zero in this case, not 80!
543 * - "[fe::01]:80"
544 * - "fe::01"
545 * - "fe::01:"
546 * - "[fe::01]"
547 * - "[fe::01]:"
548 * - "[::]:80"
549 * - ":::80"
550 * - "[::]"
551 * - "[::]:"
552 * - ":::"
553 * - "::"
554 */
555 pj_str_t ip_part, port_part;
556
557 if (*str->ptr == '[') {
558 char *end_bracket = pj_strchr(str, ']');
559 int i;
560 unsigned long port;
561
562 if (end_bracket == NULL)
563 return PJ_EINVAL;
564
565 ip_part.ptr = (char*)str->ptr + 1;
566 ip_part.slen = end_bracket - ip_part.ptr;
567
568 if (last_colon_pos == NULL) {
569 const char *p;
570 for (p=str->ptr; p!=end; ++p) {
571 if (*p == ':')
572 last_colon_pos = p;
573 }
574 }
575
576 if (last_colon_pos == NULL)
577 return PJ_EINVAL;
578
579 if (last_colon_pos < end_bracket) {
580 port_part.ptr = NULL;
581 port_part.slen = 0;
582 } else {
583 port_part.ptr = (char*)last_colon_pos + 1;
584 port_part.slen = end - port_part.ptr;
585 }
586
587 /* Make sure port number is valid */
588 for (i=0; i<port_part.slen; ++i) {
589 if (!pj_isdigit(port_part.ptr[i]))
590 return PJ_EINVAL;
591 }
592 port = pj_strtoul(&port_part);
593 if (port > 65535)
594 return PJ_EINVAL;
595
596 return pj_sockaddr_init(PJ_AF_INET6, addr, &ip_part,
597 (pj_uint16_t)port);
598 } else {
599 int i;
600 unsigned long port;
601
602 /* First lets try to parse everything as IPv6 address */
603 if (pj_sockaddr_init(PJ_AF_INET6, addr, str, 0)==PJ_SUCCESS)
604 return PJ_SUCCESS;
605
606 /* Parse as IPv6:port */
607 if (last_colon_pos == NULL) {
608 const char *p;
609 for (p=str->ptr; p!=end; ++p) {
610 if (*p == ':')
611 last_colon_pos = p;
612 }
613 }
614
615 if (last_colon_pos == NULL)
616 return PJ_EINVAL;
617
618 ip_part.ptr = (char*)str->ptr;
619 ip_part.slen = last_colon_pos - str->ptr;
620
621 port_part.ptr = (char*)last_colon_pos + 1;
622 port_part.slen = end - port_part.ptr;
623
624 /* Make sure port number is valid */
625 for (i=0; i<port_part.slen; ++i) {
626 if (!pj_isdigit(port_part.ptr[i]))
627 return PJ_EINVAL;
628 }
629 port = pj_strtoul(&port_part);
630 if (port > 65535)
631 return PJ_EINVAL;
632
633 return pj_sockaddr_init(PJ_AF_INET6, addr, &ip_part,
634 (pj_uint16_t)port);
635 }
636 }
637#endif
638 else {
639 return PJ_EIPV6NOTSUP;
640 }
641}
642
Benny Prijono27fc1432009-04-28 13:47:45 +0000643static pj_bool_t is_usable_ip(const pj_sockaddr *addr)
644{
645 if (addr->addr.sa_family==PJ_AF_INET) {
646 /* Only consider if the address is not 127.0.0.0/8 or 0.0.0.0/8.
647 * The 0.0.0.0/8 is a special IP class that doesn't seem to be
648 * practically useful for our purpose.
649 */
650 if ((pj_ntohl(addr->ipv4.sin_addr.s_addr)>>24)==127)
651 return PJ_FALSE;
652 if ((pj_ntohl(addr->ipv4.sin_addr.s_addr)>>24)==0)
653 return PJ_FALSE;
654
655 return PJ_TRUE;
656
657 } else if (addr->addr.sa_family==PJ_AF_INET6) {
658 pj_sockaddr ipv6_loop;
659 const pj_str_t loop = { "::1", 3};
660 pj_status_t status;
661
662 status = pj_sockaddr_set_str_addr(PJ_AF_INET6, &ipv6_loop, &loop);
663 if (status != PJ_SUCCESS)
664 return PJ_TRUE;
665
666 if (pj_memcmp(&addr->ipv6.sin6_addr, &ipv6_loop.ipv6.sin6_addr, 16)==0)
667 return PJ_FALSE;
668
669 return PJ_TRUE;
670 } else {
671 return PJ_TRUE;
672 }
673}
674
Benny Prijono62b86eb2007-12-01 08:52:57 +0000675/* Resolve the IP address of local machine */
676PJ_DEF(pj_status_t) pj_gethostip(int af, pj_sockaddr *addr)
677{
Benny Prijono27fc1432009-04-28 13:47:45 +0000678 unsigned i, count, cand_cnt;
679 enum {
680 CAND_CNT = 8,
681 WEIGHT_HOSTNAME = 1, /* hostname IP is not always valid! */
682 WEIGHT_DEF_ROUTE = 2,
683 WEIGHT_INTERFACE = 1
684 };
685 /* candidates: */
686 pj_sockaddr cand_addr[CAND_CNT];
687 unsigned cand_weight[CAND_CNT];
688 int selected_cand;
689 char strip[PJ_INET6_ADDRSTRLEN+10];
Benny Prijono62b86eb2007-12-01 08:52:57 +0000690 pj_addrinfo ai;
691 pj_status_t status;
692
Benny Prijono27fc1432009-04-28 13:47:45 +0000693 /* May not be used if TRACE_ is disabled */
694 PJ_UNUSED_ARG(strip);
Benny Prijono62b86eb2007-12-01 08:52:57 +0000695
696#ifdef _MSC_VER
697 /* Get rid of "uninitialized he variable" with MS compilers */
698 pj_bzero(&ai, sizeof(ai));
699#endif
700
Benny Prijono27fc1432009-04-28 13:47:45 +0000701 cand_cnt = 0;
702 pj_bzero(cand_addr, sizeof(cand_addr));
703 pj_bzero(cand_weight, sizeof(cand_weight));
704 for (i=0; i<PJ_ARRAY_SIZE(cand_addr); ++i) {
705 cand_addr[i].addr.sa_family = (pj_uint16_t)af;
706 PJ_SOCKADDR_RESET_LEN(&cand_addr[i]);
707 }
708
Benny Prijono62b86eb2007-12-01 08:52:57 +0000709 addr->addr.sa_family = (pj_uint16_t)af;
710 PJ_SOCKADDR_RESET_LEN(addr);
711
Benny Prijono27fc1432009-04-28 13:47:45 +0000712 /* Get hostname's IP address */
Benny Prijono62b86eb2007-12-01 08:52:57 +0000713 count = 1;
714 status = pj_getaddrinfo(af, pj_gethostname(), &count, &ai);
715 if (status == PJ_SUCCESS) {
Benny Prijono9db4bd62007-12-31 11:26:21 +0000716 pj_assert(ai.ai_addr.addr.sa_family == (pj_uint16_t)af);
Benny Prijono27fc1432009-04-28 13:47:45 +0000717 pj_sockaddr_copy_addr(&cand_addr[cand_cnt], &ai.ai_addr);
718 pj_sockaddr_set_port(&cand_addr[cand_cnt], 0);
719 cand_weight[cand_cnt] += WEIGHT_HOSTNAME;
720 ++cand_cnt;
721
722 TRACE_((THIS_FILE, "hostname IP is %s",
723 pj_sockaddr_print(&ai.ai_addr, strip, sizeof(strip), 0)));
Benny Prijono62b86eb2007-12-01 08:52:57 +0000724 }
725
726
Benny Prijono27fc1432009-04-28 13:47:45 +0000727 /* Get default interface (interface for default route) */
728 if (cand_cnt < PJ_ARRAY_SIZE(cand_addr)) {
729 status = pj_getdefaultipinterface(af, addr);
730 if (status == PJ_SUCCESS) {
731 TRACE_((THIS_FILE, "default IP is %s",
732 pj_sockaddr_print(addr, strip, sizeof(strip), 0)));
733
734 pj_sockaddr_set_port(addr, 0);
735 for (i=0; i<cand_cnt; ++i) {
736 if (pj_sockaddr_cmp(&cand_addr[i], addr)==0)
737 break;
738 }
739
740 cand_weight[i] += WEIGHT_DEF_ROUTE;
741 if (i >= cand_cnt) {
742 pj_sockaddr_copy_addr(&cand_addr[i], addr);
743 ++cand_cnt;
744 }
745 }
Benny Prijono62b86eb2007-12-01 08:52:57 +0000746 }
747
Benny Prijono27fc1432009-04-28 13:47:45 +0000748
749 /* Enumerate IP interfaces */
750 if (cand_cnt < PJ_ARRAY_SIZE(cand_addr)) {
751 unsigned start_if = cand_cnt;
752 unsigned count = PJ_ARRAY_SIZE(cand_addr) - start_if;
753
754 status = pj_enum_ip_interface(af, &count, &cand_addr[start_if]);
755 if (status == PJ_SUCCESS && count) {
756 /* Clear the port number */
757 for (i=0; i<count; ++i)
758 pj_sockaddr_set_port(&cand_addr[start_if+i], 0);
759
760 /* For each candidate that we found so far (that is the hostname
761 * address and default interface address, check if they're found
762 * in the interface list. If found, add the weight, and if not,
763 * decrease the weight.
764 */
765 for (i=0; i<cand_cnt; ++i) {
766 unsigned j;
767 for (j=0; j<count; ++j) {
768 if (pj_sockaddr_cmp(&cand_addr[i],
769 &cand_addr[start_if+j])==0)
770 break;
Benny Prijono9db4bd62007-12-31 11:26:21 +0000771 }
Benny Prijono27fc1432009-04-28 13:47:45 +0000772
773 if (j == count) {
774 /* Not found */
775 cand_weight[i] -= WEIGHT_INTERFACE;
776 } else {
777 cand_weight[i] += WEIGHT_INTERFACE;
778 }
779 }
780
781 /* Add remaining interface to candidate list. */
782 for (i=0; i<count; ++i) {
783 unsigned j;
784 for (j=0; j<cand_cnt; ++j) {
785 if (pj_sockaddr_cmp(&cand_addr[start_if+i],
786 &cand_addr[j])==0)
787 break;
788 }
789
790 if (j == cand_cnt) {
791 pj_sockaddr_copy_addr(&cand_addr[cand_cnt],
792 &cand_addr[start_if+i]);
793 cand_weight[cand_cnt] += WEIGHT_INTERFACE;
794 ++cand_cnt;
795 }
796 }
797 }
798 }
799
800 /* Enumerate candidates to get the best IP address to choose */
801 selected_cand = -1;
802 for (i=0; i<cand_cnt; ++i) {
803 TRACE_((THIS_FILE, "Checking candidate IP %s, weight=%d",
804 pj_sockaddr_print(&cand_addr[i], strip, sizeof(strip), 0),
805 cand_weight[i]));
806
807 if (!is_usable_ip(&cand_addr[i])) {
808 continue;
809 }
810
811 if (selected_cand == -1)
812 selected_cand = i;
813 else if (cand_weight[i] > cand_weight[selected_cand])
814 selected_cand = i;
Benny Prijono62b86eb2007-12-01 08:52:57 +0000815 }
816
817 /* If else fails, returns loopback interface as the last resort */
Benny Prijono27fc1432009-04-28 13:47:45 +0000818 if (selected_cand == -1) {
819 if (af==PJ_AF_INET) {
820 addr->ipv4.sin_addr.s_addr = pj_htonl (0x7f000001);
821 } else {
822 pj_in6_addr *s6_addr;
823
824 s6_addr = (pj_in6_addr*) pj_sockaddr_get_addr(addr);
825 pj_bzero(s6_addr, sizeof(pj_in6_addr));
826 s6_addr->s6_addr[15] = 1;
827 }
828 TRACE_((THIS_FILE, "Loopback IP %s returned",
829 pj_sockaddr_print(addr, strip, sizeof(strip), 0)));
830 } else {
831 pj_sockaddr_copy_addr(addr, &cand_addr[selected_cand]);
832 TRACE_((THIS_FILE, "Candidate %s selected",
833 pj_sockaddr_print(addr, strip, sizeof(strip), 0)));
Benny Prijono62b86eb2007-12-01 08:52:57 +0000834 }
835
Benny Prijono27fc1432009-04-28 13:47:45 +0000836 return PJ_SUCCESS;
Benny Prijono62b86eb2007-12-01 08:52:57 +0000837}
838
839/* Get the default IP interface */
840PJ_DEF(pj_status_t) pj_getdefaultipinterface(int af, pj_sockaddr *addr)
841{
842 pj_sock_t fd;
843 pj_str_t cp;
844 pj_sockaddr a;
845 int len;
846 pj_uint8_t zero[64];
847 pj_status_t status;
848
849 addr->addr.sa_family = (pj_uint16_t)af;
850
851 status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &fd);
852 if (status != PJ_SUCCESS) {
853 return status;
854 }
855
856 if (af == PJ_AF_INET) {
857 cp = pj_str("1.1.1.1");
858 } else {
859 cp = pj_str("1::1");
860 }
861 status = pj_sockaddr_init(af, &a, &cp, 53);
862 if (status != PJ_SUCCESS) {
863 pj_sock_close(fd);
864 return status;
865 }
866
867 status = pj_sock_connect(fd, &a, sizeof(a));
868 if (status != PJ_SUCCESS) {
869 pj_sock_close(fd);
870 return status;
871 }
872
873 len = sizeof(a);
874 status = pj_sock_getsockname(fd, &a, &len);
875 if (status != PJ_SUCCESS) {
876 pj_sock_close(fd);
877 return status;
878 }
879
880 pj_sock_close(fd);
881
882 /* Check that the address returned is not zero */
883 pj_bzero(zero, sizeof(zero));
884 if (pj_memcmp(pj_sockaddr_get_addr(&a), zero,
885 pj_sockaddr_get_addr_len(&a))==0)
886 {
887 return PJ_ENOTFOUND;
888 }
889
Benny Prijono9db4bd62007-12-31 11:26:21 +0000890 pj_sockaddr_copy_addr(addr, &a);
Benny Prijono62b86eb2007-12-01 08:52:57 +0000891
892 /* Success */
893 return PJ_SUCCESS;
894}
895
896
897/* Only need to implement these in DLL build */
898#if defined(PJ_DLL)
Benny Prijono8ab968f2007-07-20 08:08:30 +0000899
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000900PJ_DEF(pj_uint16_t) pj_AF_UNSPEC(void)
901{
902 return PJ_AF_UNSPEC;
903}
904
Benny Prijono8ab968f2007-07-20 08:08:30 +0000905PJ_DEF(pj_uint16_t) pj_AF_UNIX(void)
906{
907 return PJ_AF_UNIX;
908}
909
910PJ_DEF(pj_uint16_t) pj_AF_INET(void)
911{
912 return PJ_AF_INET;
913}
914
915PJ_DEF(pj_uint16_t) pj_AF_INET6(void)
916{
917 return PJ_AF_INET6;
918}
919
920PJ_DEF(pj_uint16_t) pj_AF_PACKET(void)
921{
922 return PJ_AF_PACKET;
923}
924
925PJ_DEF(pj_uint16_t) pj_AF_IRDA(void)
926{
927 return PJ_AF_IRDA;
928}
929
930PJ_DEF(int) pj_SOCK_STREAM(void)
931{
932 return PJ_SOCK_STREAM;
933}
934
935PJ_DEF(int) pj_SOCK_DGRAM(void)
936{
937 return PJ_SOCK_DGRAM;
938}
939
940PJ_DEF(int) pj_SOCK_RAW(void)
941{
942 return PJ_SOCK_RAW;
943}
944
945PJ_DEF(int) pj_SOCK_RDM(void)
946{
947 return PJ_SOCK_RDM;
948}
949
950PJ_DEF(pj_uint16_t) pj_SOL_SOCKET(void)
951{
952 return PJ_SOL_SOCKET;
953}
954
955PJ_DEF(pj_uint16_t) pj_SOL_IP(void)
956{
957 return PJ_SOL_IP;
958}
959
960PJ_DEF(pj_uint16_t) pj_SOL_TCP(void)
961{
962 return PJ_SOL_TCP;
963}
964
965PJ_DEF(pj_uint16_t) pj_SOL_UDP(void)
966{
967 return PJ_SOL_UDP;
968}
969
970PJ_DEF(pj_uint16_t) pj_SOL_IPV6(void)
971{
972 return PJ_SOL_IPV6;
973}
974
975PJ_DEF(int) pj_IP_TOS(void)
976{
977 return PJ_IP_TOS;
978}
979
980PJ_DEF(int) pj_IPTOS_LOWDELAY(void)
981{
982 return PJ_IPTOS_LOWDELAY;
983}
984
985PJ_DEF(int) pj_IPTOS_THROUGHPUT(void)
986{
987 return PJ_IPTOS_THROUGHPUT;
988}
989
990PJ_DEF(int) pj_IPTOS_RELIABILITY(void)
991{
992 return PJ_IPTOS_RELIABILITY;
993}
994
995PJ_DEF(int) pj_IPTOS_MINCOST(void)
996{
997 return PJ_IPTOS_MINCOST;
998}
999
1000PJ_DEF(pj_uint16_t) pj_SO_TYPE(void)
1001{
1002 return PJ_SO_TYPE;
1003}
1004
1005PJ_DEF(pj_uint16_t) pj_SO_RCVBUF(void)
1006{
1007 return PJ_SO_RCVBUF;
1008}
1009
1010PJ_DEF(pj_uint16_t) pj_SO_SNDBUF(void)
1011{
1012 return PJ_SO_SNDBUF;
1013}
1014
Nanang Izzuddinb76154e2008-09-16 16:11:44 +00001015PJ_DEF(pj_uint16_t) pj_IP_MULTICAST_IF(void)
1016{
1017 return PJ_IP_MULTICAST_IF;
1018}
1019
1020PJ_DEF(pj_uint16_t) pj_IP_MULTICAST_TTL(void)
1021{
1022 return PJ_IP_MULTICAST_TTL;
1023}
1024
1025PJ_DEF(pj_uint16_t) pj_IP_MULTICAST_LOOP(void)
1026{
1027 return PJ_IP_MULTICAST_LOOP;
1028}
1029
1030PJ_DEF(pj_uint16_t) pj_IP_ADD_MEMBERSHIP(void)
1031{
1032 return PJ_IP_ADD_MEMBERSHIP;
1033}
1034
1035PJ_DEF(pj_uint16_t) pj_IP_DROP_MEMBERSHIP(void)
1036{
1037 return PJ_IP_DROP_MEMBERSHIP;
1038}
1039
Benny Prijono8ab968f2007-07-20 08:08:30 +00001040PJ_DEF(int) pj_MSG_OOB(void)
1041{
1042 return PJ_MSG_OOB;
1043}
1044
1045PJ_DEF(int) pj_MSG_PEEK(void)
1046{
1047 return PJ_MSG_PEEK;
1048}
1049
1050PJ_DEF(int) pj_MSG_DONTROUTE(void)
1051{
1052 return PJ_MSG_DONTROUTE;
1053}
1054
Benny Prijono62b86eb2007-12-01 08:52:57 +00001055#endif /* PJ_DLL */
1056