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)
57 #define HOST_NAME_MAX 255
60 static int check_hostent_err(struct hostent *hp)
77 if (!hp->h_name || hp->h_addrtype != AF_INET) {
83 static char *canon_name_from_hostent(struct hostent *hp,
88 *perr = check_hostent_err(hp);
92 ret = SMB_STRDUP(hp->h_name);
99 static char *get_my_canon_name(int *perr)
101 char name[HOST_NAME_MAX+1];
103 if (gethostname(name, HOST_NAME_MAX) == -1) {
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,
115 return canon_name_from_hostent(
116 gethostbyaddr((void *)&ip, sizeof ip, AF_INET),
120 static struct addrinfo *alloc_entry(const struct addrinfo *hints,
124 struct sockaddr_in *psin = NULL;
125 struct addrinfo *ai = SMB_MALLOC(sizeof(*ai));
130 memset(ai, '\0', sizeof(*ai));
132 psin = SMB_MALLOC(sizeof(*psin));
138 memset(psin, '\0', sizeof(*psin));
140 psin->sin_family = AF_INET;
141 psin->sin_port = htons(port);
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;
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,
164 const struct addrinfo *hints,
165 struct addrinfo **res)
168 struct addrinfo *ai = NULL;
170 unsigned short port = 0;
173 port = (unsigned short)atoi(service);
175 ip.s_addr = htonl(addr);
177 ai = alloc_entry(hints, ip, port);
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) {
187 if (addr == INADDR_LOOPBACK || addr == INADDR_ANY) {
188 ai->ai_canonname = get_my_canon_name(&err);
191 get_canon_name_from_addr(ip,&err);
193 if (ai->ai_canonname == NULL) {
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,
211 const struct addrinfo *hints,
212 struct addrinfo **res)
214 struct addrinfo *listp = NULL, *prevp = NULL;
217 struct hostent *hp = NULL;
218 unsigned short port = 0;
221 port = (unsigned short)atoi(service);
224 hp = gethostbyname(node);
225 err = check_hostent_err(hp);
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);
242 ai->ai_canonname = SMB_STRDUP(hp->h_name);
243 if (!ai->ai_canonname) {
257 * get address info for ipv4 sockets.
259 * Bugs: - servname can only be a number, not text.
262 int getaddrinfo(const char *node,
264 const struct addrinfo * hintp,
265 struct addrinfo ** res)
267 struct addrinfo hints;
269 /* Setup the hints struct. */
271 memset(&hints, 0, sizeof(hints));
272 hints.ai_family = AF_INET;
273 hints.ai_socktype = SOCK_STREAM;
275 memcpy(&hints, hintp, sizeof(hints));
278 if (hints.ai_family != AF_INET && hints.ai_family != AF_UNSPEC) {
282 if (hints.ai_socktype == 0) {
283 hints.ai_socktype = SOCK_STREAM;
286 if (!node && !service) {
291 if (node[0] == '\0') {
292 return getaddr_info_single_addr(service,
296 } else if (hints.ai_flags & AI_NUMERICHOST) {
298 if (!inet_aton(node, &ip)) {
301 return getaddr_info_single_addr(service,
306 return getaddr_info_name(node,
311 } else if (hints.ai_flags & AI_PASSIVE) {
312 return getaddr_info_single_addr(service,
317 return getaddr_info_single_addr(service,
324 void freeaddrinfo(struct addrinfo *res)
326 struct addrinfo *next = NULL;
328 for (;res; res = next) {
330 if (res->ai_canonname) {
331 free(res->ai_canonname);
341 const char *gai_strerror(int errcode)
343 #ifdef HAVE_HSTRERROR
349 hcode = HOST_NOT_FOUND;
360 return hstrerror(hcode);
361 #else /* !HAVE_HSTRERROR */
366 return "Unknown host";
368 return "Host name lookup failure";
371 return "Invalid argument";
375 return "Address family not supported";
379 return "Not enough memory";
383 return "No host data of that type was found";
387 return "Class type not found";
391 return "Socket type not supported";
394 return "Unknown server error";
396 #endif /* HAVE_HSTRERROR */
399 static int gethostnameinfo(const struct sockaddr *sa,
407 if (!(flags & NI_NUMERICHOST)) {
408 struct hostent *hp = gethostbyaddr(
409 (void *)&((struct sockaddr_in *)sa)->sin_addr,
410 sizeof (struct in_addr),
412 ret = check_hostent_err(hp);
414 /* Name looked up successfully. */
415 ret = snprintf(node, nodelen, "%s", hp->h_name);
416 if (ret < 0 || (size_t)ret >= nodelen) {
419 if (flags & NI_NOFQDN) {
420 p = strchr(node,'.');
428 if (flags & NI_NAMEREQD) {
429 /* If we require a name and didn't get one,
430 * automatically fail. */
433 /* Otherwise just fall into the numeric host code... */
435 p = inet_ntoa(((struct sockaddr_in *)sa)->sin_addr);
436 ret = snprintf(node, nodelen, "%s", p);
437 if (ret < 0 || (size_t)ret >= nodelen) {
443 static int getservicenameinfo(const struct sockaddr *sa,
449 int port = ntohs(((struct sockaddr_in *)sa)->sin_port);
451 if (!(flags & NI_NUMERICSERV)) {
452 struct servent *se = getservbyport(
454 (flags & NI_DGRAM) ? "udp" : "tcp");
455 if (se && se->s_name) {
456 /* Service name looked up successfully. */
457 ret = snprintf(service, servicelen, "%s", se->s_name);
458 if (ret < 0 || (size_t)ret >= servicelen) {
463 /* Otherwise just fall into the numeric service code... */
465 ret = snprintf(service, servicelen, "%d", port);
466 if (ret < 0 || (size_t)ret >= servicelen) {
473 * Convert an ipv4 address to a hostname.
475 * Bugs: - No IPv6 support.
477 int getnameinfo(const struct sockaddr *sa, socklen_t salen,
478 char *node, size_t nodelen,
479 char *service, size_t servicelen, int flags)
482 /* Invalid arguments. */
483 if (sa == NULL || (node == NULL && service == NULL)) {
487 if (sa->sa_family != AF_INET) {
491 if (salen < (socklen_t)sizeof (struct sockaddr_in)) {
495 /* We don't support those. */
496 if ((node && !(flags & NI_NUMERICHOST))
497 || (service && !(flags & NI_NUMERICSERV)))
501 return gethostnameinfo(sa, node, nodelen, flags);
505 return getservicenameinfo(sa, service, servicelen, flags);