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
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 /*-------------------------------------------------------------------------
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 *-------------------------------------------------------------------------
49 #define SMB_MALLOC(s) malloc(s)
53 #define SMB_STRDUP(s) strdup(s)
56 static int check_hostent_err(struct hostent *hp)
70 if (!hp->h_name || hp->h_addrtype != AF_INET) {
76 static char *canon_name_from_hostent(struct hostent *hp,
81 *perr = check_hostent_err(hp);
85 ret = SMB_STRDUP(hp->h_name);
92 static char *get_my_canon_name(int *perr)
94 char name[HOST_NAME_MAX+1];
96 if (gethostname(name, HOST_NAME_MAX) == -1) {
100 /* Ensure null termination. */
101 name[HOST_NAME_MAX] = '\0';
102 return canon_name_from_hostent(gethostbyname(name), perr);
105 static char *get_canon_name_from_addr(struct in_addr ip,
108 return canon_name_from_hostent(
109 gethostbyaddr(&ip, sizeof(ip), AF_INET),
113 static struct addrinfo *alloc_entry(const struct addrinfo *hints,
117 struct sockaddr_in *psin = NULL;
118 struct addrinfo *ai = SMB_MALLOC(sizeof(*ai));
123 memset(ai, '\0', sizeof(*ai));
125 psin = SMB_MALLOC(sizeof(*psin));
131 memset(psin, '\0', sizeof(*psin));
133 psin->sin_family = AF_INET;
134 psin->sin_port = htons(port);
138 ai->ai_family = AF_INET;
139 ai->ai_socktype = hints->ai_socktype;
140 ai->ai_protocol = hints->ai_protocol;
141 ai->ai_addrlen = sizeof(*psin);
142 ai->ai_addr = (struct sockaddr *) psin;
143 ai->ai_canonname = NULL;
150 * get address info for a single ipv4 address.
152 * Bugs: - servname can only be a number, not text.
155 static int getaddr_info_single_addr(const char *service,
157 const struct addrinfo *hints,
158 struct addrinfo **res)
161 struct addrinfo *ai = NULL;
163 unsigned short port = 0;
166 port = (unsigned short)atoi(service);
168 ip.s_addr = htonl(addr);
170 ai = alloc_entry(hints, ip, port);
175 /* If we're asked for the canonical name,
176 * make sure it returns correctly. */
177 if (!(hints->ai_flags & AI_NUMERICSERV) &&
178 hints->ai_flags & AI_CANONNAME) {
180 if (addr == INADDR_LOOPBACK || addr == INADDR_ANY) {
181 ai->ai_canonname = get_my_canon_name(&err);
184 get_canon_name_from_addr(ip,&err);
186 if (ai->ai_canonname == NULL) {
197 * get address info for multiple ipv4 addresses.
199 * Bugs: - servname can only be a number, not text.
202 static int getaddr_info_name(const char *node,
204 const struct addrinfo *hints,
205 struct addrinfo **res)
207 struct addrinfo *listp = NULL, *prevp = NULL;
210 struct hostent *hp = NULL;
211 unsigned short port = 0;
214 port = (unsigned short)atoi(service);
217 hp = gethostbyname(node);
218 err = check_hostent_err(hp);
223 for(pptr = hp->h_addr_list; *pptr; pptr++) {
224 struct in_addr ip = *(struct in_addr *)*pptr;
225 struct addrinfo *ai = alloc_entry(hints, ip, port);
235 ai->ai_canonname = SMB_STRDUP(hp->h_name);
236 if (!ai->ai_canonname) {
250 * get address info for ipv4 sockets.
252 * Bugs: - servname can only be a number, not text.
255 int getaddrinfo(const char *node,
257 const struct addrinfo * hintp,
258 struct addrinfo ** res)
260 struct addrinfo hints;
262 /* Setup the hints struct. */
264 memset(&hints, 0, sizeof(hints));
265 hints.ai_family = AF_INET;
266 hints.ai_socktype = SOCK_STREAM;
268 memcpy(&hints, hintp, sizeof(hints));
271 if (hints.ai_family != AF_INET && hints.ai_family != AF_UNSPEC) {
275 if (hints.ai_socktype == 0) {
276 hints.ai_socktype = SOCK_STREAM;
279 if (!node && !service) {
284 if (node[0] == '\0') {
285 return getaddr_info_single_addr(service,
289 } else if (hints.ai_flags & AI_NUMERICHOST) {
291 if (!inet_aton(node, &ip)) {
294 return getaddr_info_single_addr(service,
299 return getaddr_info_name(node,
304 } else if (hints.ai_flags & AI_PASSIVE) {
305 return getaddr_info_single_addr(service,
310 return getaddr_info_single_addr(service,
317 void freeaddrinfo(struct addrinfo *res)
319 struct addrinfo *next = NULL;
321 for (;res; res = next) {
323 if (res->ai_canonname) {
324 free(res->ai_canonname);
334 const char *gai_strerror(int errcode)
336 #ifdef HAVE_HSTRERROR
342 hcode = HOST_NOT_FOUND;
353 return hstrerror(hcode);
354 #else /* !HAVE_HSTRERROR */
359 return "Unknown host";
361 return "Host name lookup failure";
364 return "Invalid argument";
368 return "Address family not supported";
372 return "Not enough memory";
376 return "No host data of that type was found";
380 return "Class type not found";
384 return "Socket type not supported";
387 return "Unknown server error";
389 #endif /* HAVE_HSTRERROR */
392 static int gethostnameinfo(const struct sockaddr *sa,
400 if (!(flags & NI_NUMERICHOST)) {
401 struct hostent *hp = gethostbyaddr(
402 &((struct sockaddr_in *)sa)->sin_addr,
403 sizeof(struct in_addr),
405 ret = check_hostent_err(hp);
407 /* Name looked up successfully. */
408 ret = snprintf(node, nodelen, "%s", hp->h_name);
409 if (ret < 0 || (size_t)ret >= nodelen) {
412 if (flags & NI_NOFQDN) {
413 p = strchr(node,'.');
421 if (flags & NI_NAMEREQD) {
422 /* If we require a name and didn't get one,
423 * automatically fail. */
426 /* Otherwise just fall into the numeric host code... */
428 p = inet_ntoa(((struct sockaddr_in *)sa)->sin_addr);
429 ret = snprintf(node, nodelen, "%s", p);
430 if (ret < 0 || (size_t)ret >= nodelen) {
436 static int getservicenameinfo(const struct sockaddr *sa,
442 int port = ntohs(((struct sockaddr_in *)sa)->sin_port);
444 if (!(flags & NI_NUMERICSERV)) {
445 struct servent *se = getservbyport(
447 (flags & NI_DGRAM) ? "udp" : "tcp");
448 if (se && se->s_name) {
449 /* Service name looked up successfully. */
450 ret = snprintf(service, servicelen, "%s", se->s_name);
451 if (ret < 0 || (size_t)ret >= servicelen) {
456 /* Otherwise just fall into the numeric service code... */
458 ret = snprintf(service, servicelen, "%d", port);
459 if (ret < 0 || (size_t)ret >= servicelen) {
466 * Convert an ipv4 address to a hostname.
468 * Bugs: - No IPv6 support.
470 int getnameinfo(const struct sockaddr *sa, socklen_t salen,
471 char *node, size_t nodelen,
472 char *service, size_t servicelen, int flags)
475 /* Invalid arguments. */
476 if (sa == NULL || (node == NULL && service == NULL)) {
480 if (sa->sa_family != AF_INET) {
484 if (salen < sizeof(struct sockaddr_in)) {
488 /* We don't support those. */
489 if ((node && !(flags & NI_NUMERICHOST))
490 || (service && !(flags & NI_NUMERICSERV)))
494 return gethostnameinfo(sa, node, nodelen, flags);
498 return getservicenameinfo(sa, service, servicelen, flags);