blob: 899bbd0fff0dc732cee8ffba6fd5e9d4fc48e17f [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 */
Benny Prijono9f0ef092009-08-12 10:56:06 +0000461PJ_DEF(pj_status_t) pj_sockaddr_parse2(int af, unsigned options,
Benny Prijono0f4b9db2009-06-04 15:11:25 +0000462 const pj_str_t *str,
Benny Prijono9f0ef092009-08-12 10:56:06 +0000463 pj_str_t *p_hostpart,
464 pj_uint16_t *p_port,
465 int *raf)
Benny Prijono0f4b9db2009-06-04 15:11:25 +0000466{
467 const char *end = str->ptr + str->slen;
468 const char *last_colon_pos = NULL;
Benny Prijono9f0ef092009-08-12 10:56:06 +0000469 unsigned colon_cnt = 0;
470 const char *p;
Benny Prijono0f4b9db2009-06-04 15:11:25 +0000471
Benny Prijono9f0ef092009-08-12 10:56:06 +0000472 PJ_ASSERT_RETURN((af==PJ_AF_INET || af==PJ_AF_INET6 || af==PJ_AF_UNSPEC) &&
473 options==0 &&
474 str!=NULL, PJ_EINVAL);
475
476 /* Special handling for empty input */
477 if (str->slen==0 || str->ptr==NULL) {
478 if (p_hostpart)
479 p_hostpart->slen = 0;
480 if (p_port)
481 *p_port = 0;
482 if (*raf)
483 *raf = PJ_AF_INET;
484 return PJ_SUCCESS;
485 }
486
487 /* Count the colon and get the last colon */
488 for (p=str->ptr; p!=end; ++p) {
489 if (*p == ':') {
490 ++colon_cnt;
491 last_colon_pos = p;
492 }
493 }
Benny Prijono0f4b9db2009-06-04 15:11:25 +0000494
495 /* Deduce address family if it's not given */
496 if (af == PJ_AF_UNSPEC) {
Benny Prijono0f4b9db2009-06-04 15:11:25 +0000497 if (colon_cnt > 1)
498 af = PJ_AF_INET6;
499 else
500 af = PJ_AF_INET;
Benny Prijono9f0ef092009-08-12 10:56:06 +0000501 } else if (af == PJ_AF_INET && colon_cnt > 1)
502 return PJ_EINVAL;
503
504 if (raf)
505 *raf = af;
Benny Prijono0f4b9db2009-06-04 15:11:25 +0000506
507 if (af == PJ_AF_INET) {
508 /* Parse as IPv4. Supported formats:
509 * - "10.0.0.1:80"
510 * - "10.0.0.1"
511 * - "10.0.0.1:"
512 * - ":80"
513 * - ":"
514 */
Benny Prijono9f0ef092009-08-12 10:56:06 +0000515 pj_str_t hostpart;
Benny Prijono0f4b9db2009-06-04 15:11:25 +0000516 unsigned long port;
517
Benny Prijono9f0ef092009-08-12 10:56:06 +0000518 hostpart.ptr = (char*)str->ptr;
Benny Prijono0f4b9db2009-06-04 15:11:25 +0000519
520 if (last_colon_pos) {
521 pj_str_t port_part;
522 int i;
523
Benny Prijono9f0ef092009-08-12 10:56:06 +0000524 hostpart.slen = last_colon_pos - str->ptr;
Benny Prijono0f4b9db2009-06-04 15:11:25 +0000525
526 port_part.ptr = (char*)last_colon_pos + 1;
527 port_part.slen = end - port_part.ptr;
528
529 /* Make sure port number is valid */
530 for (i=0; i<port_part.slen; ++i) {
531 if (!pj_isdigit(port_part.ptr[i]))
532 return PJ_EINVAL;
533 }
534 port = pj_strtoul(&port_part);
535 if (port > 65535)
536 return PJ_EINVAL;
537 } else {
Benny Prijono9f0ef092009-08-12 10:56:06 +0000538 hostpart.slen = str->slen;
Benny Prijono0f4b9db2009-06-04 15:11:25 +0000539 port = 0;
540 }
541
Benny Prijono9f0ef092009-08-12 10:56:06 +0000542 if (p_hostpart)
543 *p_hostpart = hostpart;
544 if (p_port)
545 *p_port = (pj_uint16_t)port;
546
547 return PJ_SUCCESS;
548
549 } else if (af == PJ_AF_INET6) {
550
551 /* Parse as IPv6. Supported formats:
Benny Prijono0f4b9db2009-06-04 15:11:25 +0000552 * - "fe::01:80" ==> note: port number is zero in this case, not 80!
553 * - "[fe::01]:80"
554 * - "fe::01"
555 * - "fe::01:"
556 * - "[fe::01]"
557 * - "[fe::01]:"
558 * - "[::]:80"
559 * - ":::80"
560 * - "[::]"
561 * - "[::]:"
562 * - ":::"
563 * - "::"
564 */
Benny Prijono9f0ef092009-08-12 10:56:06 +0000565 pj_str_t hostpart, port_part;
Benny Prijono0f4b9db2009-06-04 15:11:25 +0000566
567 if (*str->ptr == '[') {
Benny Prijono9f0ef092009-08-12 10:56:06 +0000568 char *end_bracket;
Benny Prijono0f4b9db2009-06-04 15:11:25 +0000569 int i;
570 unsigned long port;
571
Benny Prijono9f0ef092009-08-12 10:56:06 +0000572 if (last_colon_pos == NULL)
573 return PJ_EINVAL;
574
575 end_bracket = pj_strchr(str, ']');
Benny Prijono0f4b9db2009-06-04 15:11:25 +0000576 if (end_bracket == NULL)
577 return PJ_EINVAL;
578
Benny Prijono9f0ef092009-08-12 10:56:06 +0000579 hostpart.ptr = (char*)str->ptr + 1;
580 hostpart.slen = end_bracket - hostpart.ptr;
Benny Prijono0f4b9db2009-06-04 15:11:25 +0000581
582 if (last_colon_pos < end_bracket) {
583 port_part.ptr = NULL;
584 port_part.slen = 0;
585 } else {
586 port_part.ptr = (char*)last_colon_pos + 1;
587 port_part.slen = end - port_part.ptr;
588 }
589
590 /* Make sure port number is valid */
591 for (i=0; i<port_part.slen; ++i) {
592 if (!pj_isdigit(port_part.ptr[i]))
593 return PJ_EINVAL;
594 }
595 port = pj_strtoul(&port_part);
596 if (port > 65535)
597 return PJ_EINVAL;
598
Benny Prijono9f0ef092009-08-12 10:56:06 +0000599 if (p_hostpart)
600 *p_hostpart = hostpart;
601 if (p_port)
602 *p_port = (pj_uint16_t)port;
603
604 return PJ_SUCCESS;
605
Benny Prijono0f4b9db2009-06-04 15:11:25 +0000606 } else {
Benny Prijono9f0ef092009-08-12 10:56:06 +0000607 /* Treat everything as part of the IPv6 IP address */
608 if (p_hostpart)
609 *p_hostpart = *str;
610 if (p_port)
611 *p_port = 0;
Benny Prijono0f4b9db2009-06-04 15:11:25 +0000612
Benny Prijono9f0ef092009-08-12 10:56:06 +0000613 return PJ_SUCCESS;
Benny Prijono0f4b9db2009-06-04 15:11:25 +0000614 }
Benny Prijono9f0ef092009-08-12 10:56:06 +0000615
616 } else {
617 return PJ_EAFNOTSUP;
618 }
619
620}
621
622/*
623 * Parse address
624 */
625PJ_DEF(pj_status_t) pj_sockaddr_parse( int af, unsigned options,
626 const pj_str_t *str,
627 pj_sockaddr *addr)
628{
629 pj_str_t hostpart;
630 pj_uint16_t port;
631 pj_status_t status;
632
633 PJ_ASSERT_RETURN(addr, PJ_EINVAL);
634 PJ_ASSERT_RETURN(af==PJ_AF_UNSPEC ||
635 af==PJ_AF_INET ||
636 af==PJ_AF_INET6, PJ_EINVAL);
637 PJ_ASSERT_RETURN(options == 0, PJ_EINVAL);
638
639 status = pj_sockaddr_parse2(af, options, str, &hostpart, &port, &af);
640 if (status != PJ_SUCCESS)
641 return status;
642
643 status = pj_sockaddr_init(af, addr, &hostpart, port);
644#if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6
645 if (status != PJ_SUCCESS && af == PJ_AF_INET6) {
646 /* Parsing does not yield valid address. Try to treat the last
647 * portion after the colon as port number.
648 */
649 const char *last_colon_pos=NULL, *p;
650 const char *end = str->ptr + str->slen;
651 unsigned long long_port;
652 pj_str_t port_part;
653 int i;
654
655 /* Parse as IPv6:port */
656 for (p=str->ptr; p!=end; ++p) {
657 if (*p == ':')
658 last_colon_pos = p;
659 }
660
661 if (last_colon_pos == NULL)
662 return status;
663
664 hostpart.ptr = (char*)str->ptr;
665 hostpart.slen = last_colon_pos - str->ptr;
666
667 port_part.ptr = (char*)last_colon_pos + 1;
668 port_part.slen = end - port_part.ptr;
669
670 /* Make sure port number is valid */
671 for (i=0; i<port_part.slen; ++i) {
672 if (!pj_isdigit(port_part.ptr[i]))
673 return status;
674 }
675 long_port = pj_strtoul(&port_part);
676 if (long_port > 65535)
677 return status;
678
679 port = (pj_uint16_t)long_port;
680
681 status = pj_sockaddr_init(PJ_AF_INET6, addr, &hostpart, port);
Benny Prijono0f4b9db2009-06-04 15:11:25 +0000682 }
683#endif
Benny Prijono9f0ef092009-08-12 10:56:06 +0000684
685 return status;
Benny Prijono0f4b9db2009-06-04 15:11:25 +0000686}
687
Benny Prijono27fc1432009-04-28 13:47:45 +0000688static pj_bool_t is_usable_ip(const pj_sockaddr *addr)
689{
690 if (addr->addr.sa_family==PJ_AF_INET) {
691 /* Only consider if the address is not 127.0.0.0/8 or 0.0.0.0/8.
692 * The 0.0.0.0/8 is a special IP class that doesn't seem to be
693 * practically useful for our purpose.
694 */
695 if ((pj_ntohl(addr->ipv4.sin_addr.s_addr)>>24)==127)
696 return PJ_FALSE;
697 if ((pj_ntohl(addr->ipv4.sin_addr.s_addr)>>24)==0)
698 return PJ_FALSE;
699
700 return PJ_TRUE;
701
702 } else if (addr->addr.sa_family==PJ_AF_INET6) {
703 pj_sockaddr ipv6_loop;
704 const pj_str_t loop = { "::1", 3};
705 pj_status_t status;
706
707 status = pj_sockaddr_set_str_addr(PJ_AF_INET6, &ipv6_loop, &loop);
708 if (status != PJ_SUCCESS)
709 return PJ_TRUE;
710
711 if (pj_memcmp(&addr->ipv6.sin6_addr, &ipv6_loop.ipv6.sin6_addr, 16)==0)
712 return PJ_FALSE;
713
714 return PJ_TRUE;
715 } else {
716 return PJ_TRUE;
717 }
718}
719
Benny Prijono62b86eb2007-12-01 08:52:57 +0000720/* Resolve the IP address of local machine */
721PJ_DEF(pj_status_t) pj_gethostip(int af, pj_sockaddr *addr)
722{
Benny Prijono27fc1432009-04-28 13:47:45 +0000723 unsigned i, count, cand_cnt;
724 enum {
725 CAND_CNT = 8,
726 WEIGHT_HOSTNAME = 1, /* hostname IP is not always valid! */
727 WEIGHT_DEF_ROUTE = 2,
728 WEIGHT_INTERFACE = 1
729 };
730 /* candidates: */
731 pj_sockaddr cand_addr[CAND_CNT];
732 unsigned cand_weight[CAND_CNT];
733 int selected_cand;
734 char strip[PJ_INET6_ADDRSTRLEN+10];
Benny Prijono62b86eb2007-12-01 08:52:57 +0000735 pj_addrinfo ai;
736 pj_status_t status;
737
Benny Prijono27fc1432009-04-28 13:47:45 +0000738 /* May not be used if TRACE_ is disabled */
739 PJ_UNUSED_ARG(strip);
Benny Prijono62b86eb2007-12-01 08:52:57 +0000740
741#ifdef _MSC_VER
742 /* Get rid of "uninitialized he variable" with MS compilers */
743 pj_bzero(&ai, sizeof(ai));
744#endif
745
Benny Prijono27fc1432009-04-28 13:47:45 +0000746 cand_cnt = 0;
747 pj_bzero(cand_addr, sizeof(cand_addr));
748 pj_bzero(cand_weight, sizeof(cand_weight));
749 for (i=0; i<PJ_ARRAY_SIZE(cand_addr); ++i) {
750 cand_addr[i].addr.sa_family = (pj_uint16_t)af;
751 PJ_SOCKADDR_RESET_LEN(&cand_addr[i]);
752 }
753
Benny Prijono62b86eb2007-12-01 08:52:57 +0000754 addr->addr.sa_family = (pj_uint16_t)af;
755 PJ_SOCKADDR_RESET_LEN(addr);
756
Benny Prijono27fc1432009-04-28 13:47:45 +0000757 /* Get hostname's IP address */
Benny Prijono62b86eb2007-12-01 08:52:57 +0000758 count = 1;
759 status = pj_getaddrinfo(af, pj_gethostname(), &count, &ai);
760 if (status == PJ_SUCCESS) {
Benny Prijono9db4bd62007-12-31 11:26:21 +0000761 pj_assert(ai.ai_addr.addr.sa_family == (pj_uint16_t)af);
Benny Prijono27fc1432009-04-28 13:47:45 +0000762 pj_sockaddr_copy_addr(&cand_addr[cand_cnt], &ai.ai_addr);
763 pj_sockaddr_set_port(&cand_addr[cand_cnt], 0);
764 cand_weight[cand_cnt] += WEIGHT_HOSTNAME;
765 ++cand_cnt;
766
767 TRACE_((THIS_FILE, "hostname IP is %s",
768 pj_sockaddr_print(&ai.ai_addr, strip, sizeof(strip), 0)));
Benny Prijono62b86eb2007-12-01 08:52:57 +0000769 }
770
771
Benny Prijono27fc1432009-04-28 13:47:45 +0000772 /* Get default interface (interface for default route) */
773 if (cand_cnt < PJ_ARRAY_SIZE(cand_addr)) {
774 status = pj_getdefaultipinterface(af, addr);
775 if (status == PJ_SUCCESS) {
776 TRACE_((THIS_FILE, "default IP is %s",
777 pj_sockaddr_print(addr, strip, sizeof(strip), 0)));
778
779 pj_sockaddr_set_port(addr, 0);
780 for (i=0; i<cand_cnt; ++i) {
781 if (pj_sockaddr_cmp(&cand_addr[i], addr)==0)
782 break;
783 }
784
785 cand_weight[i] += WEIGHT_DEF_ROUTE;
786 if (i >= cand_cnt) {
787 pj_sockaddr_copy_addr(&cand_addr[i], addr);
788 ++cand_cnt;
789 }
790 }
Benny Prijono62b86eb2007-12-01 08:52:57 +0000791 }
792
Benny Prijono27fc1432009-04-28 13:47:45 +0000793
794 /* Enumerate IP interfaces */
795 if (cand_cnt < PJ_ARRAY_SIZE(cand_addr)) {
796 unsigned start_if = cand_cnt;
797 unsigned count = PJ_ARRAY_SIZE(cand_addr) - start_if;
798
799 status = pj_enum_ip_interface(af, &count, &cand_addr[start_if]);
800 if (status == PJ_SUCCESS && count) {
801 /* Clear the port number */
802 for (i=0; i<count; ++i)
803 pj_sockaddr_set_port(&cand_addr[start_if+i], 0);
804
805 /* For each candidate that we found so far (that is the hostname
806 * address and default interface address, check if they're found
807 * in the interface list. If found, add the weight, and if not,
808 * decrease the weight.
809 */
810 for (i=0; i<cand_cnt; ++i) {
811 unsigned j;
812 for (j=0; j<count; ++j) {
813 if (pj_sockaddr_cmp(&cand_addr[i],
814 &cand_addr[start_if+j])==0)
815 break;
Benny Prijono9db4bd62007-12-31 11:26:21 +0000816 }
Benny Prijono27fc1432009-04-28 13:47:45 +0000817
818 if (j == count) {
819 /* Not found */
820 cand_weight[i] -= WEIGHT_INTERFACE;
821 } else {
822 cand_weight[i] += WEIGHT_INTERFACE;
823 }
824 }
825
826 /* Add remaining interface to candidate list. */
827 for (i=0; i<count; ++i) {
828 unsigned j;
829 for (j=0; j<cand_cnt; ++j) {
830 if (pj_sockaddr_cmp(&cand_addr[start_if+i],
831 &cand_addr[j])==0)
832 break;
833 }
834
835 if (j == cand_cnt) {
836 pj_sockaddr_copy_addr(&cand_addr[cand_cnt],
837 &cand_addr[start_if+i]);
838 cand_weight[cand_cnt] += WEIGHT_INTERFACE;
839 ++cand_cnt;
840 }
841 }
842 }
843 }
844
845 /* Enumerate candidates to get the best IP address to choose */
846 selected_cand = -1;
847 for (i=0; i<cand_cnt; ++i) {
848 TRACE_((THIS_FILE, "Checking candidate IP %s, weight=%d",
849 pj_sockaddr_print(&cand_addr[i], strip, sizeof(strip), 0),
850 cand_weight[i]));
851
852 if (!is_usable_ip(&cand_addr[i])) {
853 continue;
854 }
855
856 if (selected_cand == -1)
857 selected_cand = i;
858 else if (cand_weight[i] > cand_weight[selected_cand])
859 selected_cand = i;
Benny Prijono62b86eb2007-12-01 08:52:57 +0000860 }
861
862 /* If else fails, returns loopback interface as the last resort */
Benny Prijono27fc1432009-04-28 13:47:45 +0000863 if (selected_cand == -1) {
864 if (af==PJ_AF_INET) {
865 addr->ipv4.sin_addr.s_addr = pj_htonl (0x7f000001);
866 } else {
867 pj_in6_addr *s6_addr;
868
869 s6_addr = (pj_in6_addr*) pj_sockaddr_get_addr(addr);
870 pj_bzero(s6_addr, sizeof(pj_in6_addr));
871 s6_addr->s6_addr[15] = 1;
872 }
873 TRACE_((THIS_FILE, "Loopback IP %s returned",
874 pj_sockaddr_print(addr, strip, sizeof(strip), 0)));
875 } else {
876 pj_sockaddr_copy_addr(addr, &cand_addr[selected_cand]);
877 TRACE_((THIS_FILE, "Candidate %s selected",
878 pj_sockaddr_print(addr, strip, sizeof(strip), 0)));
Benny Prijono62b86eb2007-12-01 08:52:57 +0000879 }
880
Benny Prijono27fc1432009-04-28 13:47:45 +0000881 return PJ_SUCCESS;
Benny Prijono62b86eb2007-12-01 08:52:57 +0000882}
883
884/* Get the default IP interface */
885PJ_DEF(pj_status_t) pj_getdefaultipinterface(int af, pj_sockaddr *addr)
886{
887 pj_sock_t fd;
888 pj_str_t cp;
889 pj_sockaddr a;
890 int len;
891 pj_uint8_t zero[64];
892 pj_status_t status;
893
894 addr->addr.sa_family = (pj_uint16_t)af;
895
896 status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &fd);
897 if (status != PJ_SUCCESS) {
898 return status;
899 }
900
901 if (af == PJ_AF_INET) {
902 cp = pj_str("1.1.1.1");
903 } else {
904 cp = pj_str("1::1");
905 }
906 status = pj_sockaddr_init(af, &a, &cp, 53);
907 if (status != PJ_SUCCESS) {
908 pj_sock_close(fd);
909 return status;
910 }
911
912 status = pj_sock_connect(fd, &a, sizeof(a));
913 if (status != PJ_SUCCESS) {
914 pj_sock_close(fd);
915 return status;
916 }
917
918 len = sizeof(a);
919 status = pj_sock_getsockname(fd, &a, &len);
920 if (status != PJ_SUCCESS) {
921 pj_sock_close(fd);
922 return status;
923 }
924
925 pj_sock_close(fd);
926
927 /* Check that the address returned is not zero */
928 pj_bzero(zero, sizeof(zero));
929 if (pj_memcmp(pj_sockaddr_get_addr(&a), zero,
930 pj_sockaddr_get_addr_len(&a))==0)
931 {
932 return PJ_ENOTFOUND;
933 }
934
Benny Prijono9db4bd62007-12-31 11:26:21 +0000935 pj_sockaddr_copy_addr(addr, &a);
Benny Prijono62b86eb2007-12-01 08:52:57 +0000936
937 /* Success */
938 return PJ_SUCCESS;
939}
940
941
942/* Only need to implement these in DLL build */
943#if defined(PJ_DLL)
Benny Prijono8ab968f2007-07-20 08:08:30 +0000944
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000945PJ_DEF(pj_uint16_t) pj_AF_UNSPEC(void)
946{
947 return PJ_AF_UNSPEC;
948}
949
Benny Prijono8ab968f2007-07-20 08:08:30 +0000950PJ_DEF(pj_uint16_t) pj_AF_UNIX(void)
951{
952 return PJ_AF_UNIX;
953}
954
955PJ_DEF(pj_uint16_t) pj_AF_INET(void)
956{
957 return PJ_AF_INET;
958}
959
960PJ_DEF(pj_uint16_t) pj_AF_INET6(void)
961{
962 return PJ_AF_INET6;
963}
964
965PJ_DEF(pj_uint16_t) pj_AF_PACKET(void)
966{
967 return PJ_AF_PACKET;
968}
969
970PJ_DEF(pj_uint16_t) pj_AF_IRDA(void)
971{
972 return PJ_AF_IRDA;
973}
974
975PJ_DEF(int) pj_SOCK_STREAM(void)
976{
977 return PJ_SOCK_STREAM;
978}
979
980PJ_DEF(int) pj_SOCK_DGRAM(void)
981{
982 return PJ_SOCK_DGRAM;
983}
984
985PJ_DEF(int) pj_SOCK_RAW(void)
986{
987 return PJ_SOCK_RAW;
988}
989
990PJ_DEF(int) pj_SOCK_RDM(void)
991{
992 return PJ_SOCK_RDM;
993}
994
995PJ_DEF(pj_uint16_t) pj_SOL_SOCKET(void)
996{
997 return PJ_SOL_SOCKET;
998}
999
1000PJ_DEF(pj_uint16_t) pj_SOL_IP(void)
1001{
1002 return PJ_SOL_IP;
1003}
1004
1005PJ_DEF(pj_uint16_t) pj_SOL_TCP(void)
1006{
1007 return PJ_SOL_TCP;
1008}
1009
1010PJ_DEF(pj_uint16_t) pj_SOL_UDP(void)
1011{
1012 return PJ_SOL_UDP;
1013}
1014
1015PJ_DEF(pj_uint16_t) pj_SOL_IPV6(void)
1016{
1017 return PJ_SOL_IPV6;
1018}
1019
1020PJ_DEF(int) pj_IP_TOS(void)
1021{
1022 return PJ_IP_TOS;
1023}
1024
1025PJ_DEF(int) pj_IPTOS_LOWDELAY(void)
1026{
1027 return PJ_IPTOS_LOWDELAY;
1028}
1029
1030PJ_DEF(int) pj_IPTOS_THROUGHPUT(void)
1031{
1032 return PJ_IPTOS_THROUGHPUT;
1033}
1034
1035PJ_DEF(int) pj_IPTOS_RELIABILITY(void)
1036{
1037 return PJ_IPTOS_RELIABILITY;
1038}
1039
1040PJ_DEF(int) pj_IPTOS_MINCOST(void)
1041{
1042 return PJ_IPTOS_MINCOST;
1043}
1044
1045PJ_DEF(pj_uint16_t) pj_SO_TYPE(void)
1046{
1047 return PJ_SO_TYPE;
1048}
1049
1050PJ_DEF(pj_uint16_t) pj_SO_RCVBUF(void)
1051{
1052 return PJ_SO_RCVBUF;
1053}
1054
1055PJ_DEF(pj_uint16_t) pj_SO_SNDBUF(void)
1056{
1057 return PJ_SO_SNDBUF;
1058}
1059
Nanang Izzuddinb76154e2008-09-16 16:11:44 +00001060PJ_DEF(pj_uint16_t) pj_IP_MULTICAST_IF(void)
1061{
1062 return PJ_IP_MULTICAST_IF;
1063}
1064
1065PJ_DEF(pj_uint16_t) pj_IP_MULTICAST_TTL(void)
1066{
1067 return PJ_IP_MULTICAST_TTL;
1068}
1069
1070PJ_DEF(pj_uint16_t) pj_IP_MULTICAST_LOOP(void)
1071{
1072 return PJ_IP_MULTICAST_LOOP;
1073}
1074
1075PJ_DEF(pj_uint16_t) pj_IP_ADD_MEMBERSHIP(void)
1076{
1077 return PJ_IP_ADD_MEMBERSHIP;
1078}
1079
1080PJ_DEF(pj_uint16_t) pj_IP_DROP_MEMBERSHIP(void)
1081{
1082 return PJ_IP_DROP_MEMBERSHIP;
1083}
1084
Benny Prijono8ab968f2007-07-20 08:08:30 +00001085PJ_DEF(int) pj_MSG_OOB(void)
1086{
1087 return PJ_MSG_OOB;
1088}
1089
1090PJ_DEF(int) pj_MSG_PEEK(void)
1091{
1092 return PJ_MSG_PEEK;
1093}
1094
1095PJ_DEF(int) pj_MSG_DONTROUTE(void)
1096{
1097 return PJ_MSG_DONTROUTE;
1098}
1099
Benny Prijono62b86eb2007-12-01 08:52:57 +00001100#endif /* PJ_DLL */
1101