blob: 12f9bab5e1d0a24edc328c4817fe8daf28f5eb9d [file] [log] [blame]
Benny Prijono5dcb38d2005-11-21 01:55:47 +00001/* $Id$ */
2/*
Benny Prijono32177c02008-06-20 22:44:47 +00003 * Copyright (C)2003-2008 Benny Prijono <benny@prijono.org>
Benny Prijono5dcb38d2005-11-21 01:55:47 +00004 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19#include <pj/addr_resolv.h>
20#include <pj/assert.h>
21#include <pj/string.h>
Benny Prijono5dcb38d2005-11-21 01:55:47 +000022#include <pj/errno.h>
Benny Prijono4c8fb532007-11-26 05:36:18 +000023#include <pj/ip_helper.h>
Benny Prijono594e4c52006-09-14 18:51:01 +000024#include <pj/compat/socket.h>
Benny Prijono5dcb38d2005-11-21 01:55:47 +000025
26
27PJ_DEF(pj_status_t) pj_gethostbyname(const pj_str_t *hostname, pj_hostent *phe)
28{
29 struct hostent *he;
30 char copy[PJ_MAX_HOSTNAME];
31
32 pj_assert(hostname && hostname ->slen < PJ_MAX_HOSTNAME);
33
34 if (hostname->slen >= PJ_MAX_HOSTNAME)
35 return PJ_ENAMETOOLONG;
36
37 pj_memcpy(copy, hostname->ptr, hostname->slen);
38 copy[ hostname->slen ] = '\0';
39
40 he = gethostbyname(copy);
Benny Prijono64df0eb2007-01-26 17:09:14 +000041 if (!he) {
Benny Prijono129287a2007-03-01 16:52:45 +000042 return PJ_ERESOLVE;
43 /* DO NOT use pj_get_netos_error() since host resolution error
44 * is reported in h_errno instead of errno!
Benny Prijono64df0eb2007-01-26 17:09:14 +000045 return pj_get_netos_error();
Benny Prijono129287a2007-03-01 16:52:45 +000046 */
Benny Prijono64df0eb2007-01-26 17:09:14 +000047 }
Benny Prijono5dcb38d2005-11-21 01:55:47 +000048
49 phe->h_name = he->h_name;
50 phe->h_aliases = he->h_aliases;
51 phe->h_addrtype = he->h_addrtype;
52 phe->h_length = he->h_length;
53 phe->h_addr_list = he->h_addr_list;
54
55 return PJ_SUCCESS;
56}
57
Benny Prijonoc16c6e32007-11-18 14:53:47 +000058/* Resolve IPv4/IPv6 address */
Benny Prijono62b86eb2007-12-01 08:52:57 +000059PJ_DEF(pj_status_t) pj_getaddrinfo(int af, const pj_str_t *nodename,
Benny Prijonoc16c6e32007-11-18 14:53:47 +000060 unsigned *count, pj_addrinfo ai[])
61{
62#if defined(PJ_SOCK_HAS_GETADDRINFO) && PJ_SOCK_HAS_GETADDRINFO!=0
63 char nodecopy[PJ_MAX_HOSTNAME];
Benny Prijono80025db2007-12-02 15:36:46 +000064 struct addrinfo hint, *res, *orig_res;
Benny Prijonoc16c6e32007-11-18 14:53:47 +000065 unsigned i;
66 int rc;
67
68 PJ_ASSERT_RETURN(nodename && count && *count && ai, PJ_EINVAL);
69 PJ_ASSERT_RETURN(nodename->ptr && nodename->slen, PJ_EINVAL);
Benny Prijono62b86eb2007-12-01 08:52:57 +000070 PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6 ||
71 af==PJ_AF_UNSPEC, PJ_EINVAL);
Benny Prijonoc16c6e32007-11-18 14:53:47 +000072
Benny Prijono43d4b6c2008-01-24 19:59:41 +000073 /* Check if nodename is IP address */
74 pj_bzero(&ai[0], sizeof(ai[0]));
75 ai[0].ai_addr.addr.sa_family = (pj_uint16_t)af;
76 if (pj_inet_pton(af, nodename, pj_sockaddr_get_addr(&ai[0].ai_addr))
77 == PJ_SUCCESS)
78 {
79 pj_str_t tmp;
80
81 tmp.ptr = ai[0].ai_canonname;
82 pj_strncpy_with_null(&tmp, nodename, PJ_MAX_HOSTNAME);
83 ai[0].ai_addr.addr.sa_family = (pj_uint16_t)af;
84 *count = 1;
85
86 return PJ_SUCCESS;
87 }
88
Benny Prijonoc16c6e32007-11-18 14:53:47 +000089 /* Copy node name to null terminated string. */
90 if (nodename->slen >= PJ_MAX_HOSTNAME)
91 return PJ_ENAMETOOLONG;
92 pj_memcpy(nodecopy, nodename->ptr, nodename->slen);
93 nodecopy[nodename->slen] = '\0';
94
95 /* Call getaddrinfo() */
96 pj_bzero(&hint, sizeof(hint));
97 hint.ai_family = af;
98
99 rc = getaddrinfo(nodecopy, NULL, &hint, &res);
100 if (rc != 0)
101 return PJ_ERESOLVE;
102
Benny Prijono80025db2007-12-02 15:36:46 +0000103 orig_res = res;
104
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000105 /* Enumerate each item in the result */
106 for (i=0; i<*count && res; res=res->ai_next) {
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000107 /* Ignore unwanted address families */
108 if (af!=PJ_AF_UNSPEC && res->ai_family != af)
109 continue;
110
Benny Prijono62b86eb2007-12-01 08:52:57 +0000111 /* Store canonical name (possibly truncating the name) */
Benny Prijono80025db2007-12-02 15:36:46 +0000112 if (res->ai_canonname) {
113 pj_ansi_strncpy(ai[i].ai_canonname, res->ai_canonname,
114 sizeof(ai[i].ai_canonname));
115 ai[i].ai_canonname[sizeof(ai[i].ai_canonname)-1] = '\0';
116 } else {
117 pj_ansi_strcpy(ai[i].ai_canonname, nodecopy);
118 }
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000119
120 /* Store address */
121 PJ_ASSERT_ON_FAIL(res->ai_addrlen <= sizeof(pj_sockaddr), continue);
122 pj_memcpy(&ai[i].ai_addr, res->ai_addr, res->ai_addrlen);
123
124 /* Next slot */
125 ++i;
126 }
127
128 *count = i;
129
Benny Prijono80025db2007-12-02 15:36:46 +0000130 freeaddrinfo(orig_res);
131
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000132 /* Done */
133 return PJ_SUCCESS;
134
135#else /* PJ_SOCK_HAS_GETADDRINFO */
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000136
Benny Prijono43d4b6c2008-01-24 19:59:41 +0000137 PJ_ASSERT_RETURN(count && *count, PJ_EINVAL);
138
139 /* Check if nodename is IP address */
140 pj_bzero(&ai[0], sizeof(ai[0]));
141 ai[0].ai_addr.addr.sa_family = (pj_uint16_t)af;
142 if (pj_inet_pton(af, nodename, pj_sockaddr_get_addr(&ai[0].ai_addr))
143 == PJ_SUCCESS)
144 {
145 pj_str_t tmp;
146
147 tmp.ptr = ai[0].ai_canonname;
148 pj_strncpy_with_null(&tmp, nodename, PJ_MAX_HOSTNAME);
149 ai[0].ai_addr.addr.sa_family = (pj_uint16_t)af;
150 *count = 1;
151
152 return PJ_SUCCESS;
153 }
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000154
Benny Prijono62b86eb2007-12-01 08:52:57 +0000155 if (af == PJ_AF_INET || af == PJ_AF_UNSPEC) {
156 pj_hostent he;
157 unsigned i, max_count;
158 pj_status_t status;
159
Benny Prijono0cc83f02008-01-19 09:34:30 +0000160 /* VC6 complains that "he" is uninitialized */
161 #ifdef _MSC_VER
162 pj_bzero(&he, sizeof(he));
163 #endif
164
Benny Prijono62b86eb2007-12-01 08:52:57 +0000165 status = pj_gethostbyname(nodename, &he);
166 if (status != PJ_SUCCESS)
167 return status;
168
169 max_count = *count;
170 *count = 0;
171
172 pj_bzero(ai, max_count * sizeof(pj_addrinfo));
173
174 for (i=0; he.h_addr_list[i] && *count<max_count; ++i) {
175 pj_ansi_strncpy(ai[*count].ai_canonname, he.h_name,
176 sizeof(ai[*count].ai_canonname));
177 ai[*count].ai_canonname[sizeof(ai[*count].ai_canonname)-1] = '\0';
178
179 ai[*count].ai_addr.ipv4.sin_family = PJ_AF_INET;
180 pj_memcpy(&ai[*count].ai_addr.ipv4.sin_addr,
181 he.h_addr_list[i], he.h_length);
182
183 (*count)++;
184 }
185
186 return PJ_SUCCESS;
187
188 } else {
189 /* IPv6 is not supported */
190 *count = 0;
191
192 return PJ_EIPV6NOTSUP;
193 }
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000194#endif /* PJ_SOCK_HAS_GETADDRINFO */
195}
196