Fix version verification when "\|" doesn't work in sed.
[rsync.git] / lib / getaddrinfo.c
blob96d7a2ba3c0c1c8a6330e83b23b7d9af4f552c47
1 /*
2 PostgreSQL Database Management System
3 (formerly known as Postgres, then as Postgres95)
5 Portions Copyright (c) 1996-2005, The PostgreSQL Global Development Group
7 Portions Copyright (c) 1994, The Regents of the University of California
9 Permission to use, copy, modify, and distribute this software and its
10 documentation for any purpose, without fee, and without a written agreement
11 is hereby granted, provided that the above copyright notice and this paragraph
12 and the following two paragraphs appear in all copies.
14 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
15 DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
16 LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
17 EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
18 SUCH DAMAGE.
20 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
21 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
22 AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
23 ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS
24 TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
28 /*-------------------------------------------------------------------------
30 * getaddrinfo.c
31 * Support getaddrinfo() on platforms that don't have it.
33 * We also supply getnameinfo() here, assuming that the platform will have
34 * it if and only if it has getaddrinfo(). If this proves false on some
35 * platform, we'll need to split this file and provide a separate configure
36 * test for getnameinfo().
38 * Copyright (c) 2003-2007, PostgreSQL Global Development Group
40 * Copyright (C) 2007 Jeremy Allison.
41 * Modified to return multiple IPv4 addresses for Samba.
43 *-------------------------------------------------------------------------
46 #include "rsync.h"
48 #ifndef SMB_MALLOC
49 #define SMB_MALLOC(s) malloc(s)
50 #endif
52 #ifndef SMB_STRDUP
53 #define SMB_STRDUP(s) strdup(s)
54 #endif
56 #ifndef HOST_NAME_MAX
57 #define HOST_NAME_MAX 255
58 #endif
60 static int check_hostent_err(struct hostent *hp)
62 #ifndef INET6
63 extern int h_errno;
64 #endif
65 if (!hp) {
66 switch (h_errno) {
67 case HOST_NOT_FOUND:
68 case NO_DATA:
69 return EAI_NONAME;
70 case TRY_AGAIN:
71 return EAI_AGAIN;
72 case NO_RECOVERY:
73 default:
74 return EAI_FAIL;
77 if (!hp->h_name || hp->h_addrtype != AF_INET) {
78 return EAI_FAIL;
80 return 0;
83 static char *canon_name_from_hostent(struct hostent *hp,
84 int *perr)
86 char *ret = NULL;
88 *perr = check_hostent_err(hp);
89 if (*perr) {
90 return NULL;
92 ret = SMB_STRDUP(hp->h_name);
93 if (!ret) {
94 *perr = EAI_MEMORY;
96 return ret;
99 static char *get_my_canon_name(int *perr)
101 char name[HOST_NAME_MAX+1];
103 if (gethostname(name, HOST_NAME_MAX) == -1) {
104 *perr = EAI_FAIL;
105 return NULL;
107 /* Ensure null termination. */
108 name[HOST_NAME_MAX] = '\0';
109 return canon_name_from_hostent(gethostbyname(name), perr);
112 static char *get_canon_name_from_addr(struct in_addr ip,
113 int *perr)
115 return canon_name_from_hostent(
116 gethostbyaddr((void *)&ip, sizeof ip, AF_INET),
117 perr);
120 static struct addrinfo *alloc_entry(const struct addrinfo *hints,
121 struct in_addr ip,
122 unsigned short port)
124 struct sockaddr_in *psin = NULL;
125 struct addrinfo *ai = SMB_MALLOC(sizeof(*ai));
127 if (!ai) {
128 return NULL;
130 memset(ai, '\0', sizeof(*ai));
132 psin = SMB_MALLOC(sizeof(*psin));
133 if (!psin) {
134 free(ai);
135 return NULL;
138 memset(psin, '\0', sizeof(*psin));
140 psin->sin_family = AF_INET;
141 psin->sin_port = htons(port);
142 psin->sin_addr = ip;
144 ai->ai_flags = 0;
145 ai->ai_family = AF_INET;
146 ai->ai_socktype = hints->ai_socktype;
147 ai->ai_protocol = hints->ai_protocol;
148 ai->ai_addrlen = sizeof(*psin);
149 ai->ai_addr = (struct sockaddr *) psin;
150 ai->ai_canonname = NULL;
151 ai->ai_next = NULL;
153 return ai;
157 * get address info for a single ipv4 address.
159 * Bugs: - servname can only be a number, not text.
162 static int getaddr_info_single_addr(const char *service,
163 uint32 addr,
164 const struct addrinfo *hints,
165 struct addrinfo **res)
168 struct addrinfo *ai = NULL;
169 struct in_addr ip;
170 unsigned short port = 0;
172 if (service) {
173 port = (unsigned short)atoi(service);
175 ip.s_addr = htonl(addr);
177 ai = alloc_entry(hints, ip, port);
178 if (!ai) {
179 return EAI_MEMORY;
182 /* If we're asked for the canonical name,
183 * make sure it returns correctly. */
184 if (!(hints->ai_flags & AI_NUMERICSERV) &&
185 hints->ai_flags & AI_CANONNAME) {
186 int err;
187 if (addr == INADDR_LOOPBACK || addr == INADDR_ANY) {
188 ai->ai_canonname = get_my_canon_name(&err);
189 } else {
190 ai->ai_canonname =
191 get_canon_name_from_addr(ip,&err);
193 if (ai->ai_canonname == NULL) {
194 freeaddrinfo(ai);
195 return err;
199 *res = ai;
200 return 0;
204 * get address info for multiple ipv4 addresses.
206 * Bugs: - servname can only be a number, not text.
209 static int getaddr_info_name(const char *node,
210 const char *service,
211 const struct addrinfo *hints,
212 struct addrinfo **res)
214 struct addrinfo *listp = NULL, *prevp = NULL;
215 char **pptr = NULL;
216 int err;
217 struct hostent *hp = NULL;
218 unsigned short port = 0;
220 if (service) {
221 port = (unsigned short)atoi(service);
224 hp = gethostbyname(node);
225 err = check_hostent_err(hp);
226 if (err) {
227 return err;
230 for(pptr = hp->h_addr_list; *pptr; pptr++) {
231 struct in_addr ip = *(struct in_addr *)*pptr;
232 struct addrinfo *ai = alloc_entry(hints, ip, port);
234 if (!ai) {
235 freeaddrinfo(listp);
236 return EAI_MEMORY;
239 if (!listp) {
240 listp = ai;
241 prevp = ai;
242 ai->ai_canonname = SMB_STRDUP(hp->h_name);
243 if (!ai->ai_canonname) {
244 freeaddrinfo(listp);
245 return EAI_MEMORY;
247 } else {
248 prevp->ai_next = ai;
249 prevp = ai;
252 *res = listp;
253 return 0;
257 * get address info for ipv4 sockets.
259 * Bugs: - servname can only be a number, not text.
262 int getaddrinfo(const char *node,
263 const char *service,
264 const struct addrinfo * hintp,
265 struct addrinfo ** res)
267 struct addrinfo hints;
269 /* Setup the hints struct. */
270 if (hintp == NULL) {
271 memset(&hints, 0, sizeof(hints));
272 hints.ai_family = AF_INET;
273 hints.ai_socktype = SOCK_STREAM;
274 } else {
275 memcpy(&hints, hintp, sizeof(hints));
278 if (hints.ai_family != AF_INET && hints.ai_family != AF_UNSPEC) {
279 return EAI_FAMILY;
282 if (hints.ai_socktype == 0) {
283 hints.ai_socktype = SOCK_STREAM;
286 if (!node && !service) {
287 return EAI_NONAME;
290 if (node) {
291 if (node[0] == '\0') {
292 return getaddr_info_single_addr(service,
293 INADDR_ANY,
294 &hints,
295 res);
296 } else if (hints.ai_flags & AI_NUMERICHOST) {
297 struct in_addr ip;
298 if (inet_pton(AF_INET, node, &ip) <= 0)
299 return EAI_FAIL;
300 return getaddr_info_single_addr(service,
301 ntohl(ip.s_addr),
302 &hints,
303 res);
304 } else {
305 return getaddr_info_name(node,
306 service,
307 &hints,
308 res);
310 } else if (hints.ai_flags & AI_PASSIVE) {
311 return getaddr_info_single_addr(service,
312 INADDR_ANY,
313 &hints,
314 res);
316 return getaddr_info_single_addr(service,
317 INADDR_LOOPBACK,
318 &hints,
319 res);
323 void freeaddrinfo(struct addrinfo *res)
325 struct addrinfo *next = NULL;
327 for (;res; res = next) {
328 next = res->ai_next;
329 if (res->ai_canonname) {
330 free(res->ai_canonname);
332 if (res->ai_addr) {
333 free(res->ai_addr);
335 free(res);
340 const char *gai_strerror(int errcode)
342 #ifdef HAVE_HSTRERROR
343 int hcode;
345 switch (errcode)
347 case EAI_NONAME:
348 hcode = HOST_NOT_FOUND;
349 break;
350 case EAI_AGAIN:
351 hcode = TRY_AGAIN;
352 break;
353 case EAI_FAIL:
354 default:
355 hcode = NO_RECOVERY;
356 break;
359 return hstrerror(hcode);
360 #else /* !HAVE_HSTRERROR */
362 switch (errcode)
364 case EAI_NONAME:
365 return "Unknown host";
366 case EAI_AGAIN:
367 return "Host name lookup failure";
368 #ifdef EAI_BADFLAGS
369 case EAI_BADFLAGS:
370 return "Invalid argument";
371 #endif
372 #ifdef EAI_FAMILY
373 case EAI_FAMILY:
374 return "Address family not supported";
375 #endif
376 #ifdef EAI_MEMORY
377 case EAI_MEMORY:
378 return "Not enough memory";
379 #endif
380 #ifdef EAI_NODATA
381 case EAI_NODATA:
382 return "No host data of that type was found";
383 #endif
384 #ifdef EAI_SERVICE
385 case EAI_SERVICE:
386 return "Class type not found";
387 #endif
388 #ifdef EAI_SOCKTYPE
389 case EAI_SOCKTYPE:
390 return "Socket type not supported";
391 #endif
392 default:
393 return "Unknown server error";
395 #endif /* HAVE_HSTRERROR */
398 static int gethostnameinfo(const struct sockaddr *sa,
399 char *node,
400 size_t nodelen,
401 int flags)
403 int ret = -1;
404 char *p = NULL;
406 if (!(flags & NI_NUMERICHOST)) {
407 struct hostent *hp = gethostbyaddr(
408 (void *)&((struct sockaddr_in *)sa)->sin_addr,
409 sizeof (struct in_addr),
410 sa->sa_family);
411 ret = check_hostent_err(hp);
412 if (ret == 0) {
413 /* Name looked up successfully. */
414 ret = snprintf(node, nodelen, "%s", hp->h_name);
415 if (ret < 0 || (size_t)ret >= nodelen) {
416 return EAI_MEMORY;
418 if (flags & NI_NOFQDN) {
419 p = strchr(node,'.');
420 if (p) {
421 *p = '\0';
424 return 0;
427 if (flags & NI_NAMEREQD) {
428 /* If we require a name and didn't get one,
429 * automatically fail. */
430 return ret;
432 /* Otherwise just fall into the numeric host code... */
434 p = inet_ntoa(((struct sockaddr_in *)sa)->sin_addr);
435 ret = snprintf(node, nodelen, "%s", p);
436 if (ret < 0 || (size_t)ret >= nodelen) {
437 return EAI_MEMORY;
439 return 0;
442 static int getservicenameinfo(const struct sockaddr *sa,
443 char *service,
444 size_t servicelen,
445 int flags)
447 int ret = -1;
448 int port = ntohs(((struct sockaddr_in *)sa)->sin_port);
450 if (!(flags & NI_NUMERICSERV)) {
451 struct servent *se = getservbyport(
452 port,
453 (flags & NI_DGRAM) ? "udp" : "tcp");
454 if (se && se->s_name) {
455 /* Service name looked up successfully. */
456 ret = snprintf(service, servicelen, "%s", se->s_name);
457 if (ret < 0 || (size_t)ret >= servicelen) {
458 return EAI_MEMORY;
460 return 0;
462 /* Otherwise just fall into the numeric service code... */
464 ret = snprintf(service, servicelen, "%d", port);
465 if (ret < 0 || (size_t)ret >= servicelen) {
466 return EAI_MEMORY;
468 return 0;
472 * Convert an ipv4 address to a hostname.
474 * Bugs: - No IPv6 support.
476 int getnameinfo(const struct sockaddr *sa, socklen_t salen,
477 char *node, size_t nodelen,
478 char *service, size_t servicelen, int flags)
481 /* Invalid arguments. */
482 if (sa == NULL || (node == NULL && service == NULL)) {
483 return EAI_FAIL;
486 if (sa->sa_family != AF_INET) {
487 return EAI_FAIL;
490 if (salen < (socklen_t)sizeof (struct sockaddr_in)) {
491 return EAI_FAIL;
494 if (node) {
495 int ret = gethostnameinfo(sa, node, nodelen, flags);
496 if (ret)
497 return ret;
500 if (service) {
501 return getservicenameinfo(sa, service, servicelen, flags);
503 return 0;