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_pton(AF_INET
, node
, &ip
) <= 0)
300 return getaddr_info_single_addr(service
,
305 return getaddr_info_name(node
,
310 } else if (hints
.ai_flags
& AI_PASSIVE
) {
311 return getaddr_info_single_addr(service
,
316 return getaddr_info_single_addr(service
,
323 void freeaddrinfo(struct addrinfo
*res
)
325 struct addrinfo
*next
= NULL
;
327 for (;res
; res
= next
) {
329 if (res
->ai_canonname
) {
330 free(res
->ai_canonname
);
340 const char *gai_strerror(int errcode
)
342 #ifdef HAVE_HSTRERROR
348 hcode
= HOST_NOT_FOUND
;
359 return hstrerror(hcode
);
360 #else /* !HAVE_HSTRERROR */
365 return "Unknown host";
367 return "Host name lookup failure";
370 return "Invalid argument";
374 return "Address family not supported";
378 return "Not enough memory";
382 return "No host data of that type was found";
386 return "Class type not found";
390 return "Socket type not supported";
393 return "Unknown server error";
395 #endif /* HAVE_HSTRERROR */
398 static int gethostnameinfo(const struct sockaddr
*sa
,
406 if (!(flags
& NI_NUMERICHOST
)) {
407 struct hostent
*hp
= gethostbyaddr(
408 (void *)&((struct sockaddr_in
*)sa
)->sin_addr
,
409 sizeof (struct in_addr
),
411 ret
= check_hostent_err(hp
);
413 /* Name looked up successfully. */
414 ret
= snprintf(node
, nodelen
, "%s", hp
->h_name
);
415 if (ret
< 0 || (size_t)ret
>= nodelen
) {
418 if (flags
& NI_NOFQDN
) {
419 p
= strchr(node
,'.');
427 if (flags
& NI_NAMEREQD
) {
428 /* If we require a name and didn't get one,
429 * automatically fail. */
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
) {
442 static int getservicenameinfo(const struct sockaddr
*sa
,
448 int port
= ntohs(((struct sockaddr_in
*)sa
)->sin_port
);
450 if (!(flags
& NI_NUMERICSERV
)) {
451 struct servent
*se
= getservbyport(
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
) {
462 /* Otherwise just fall into the numeric service code... */
464 ret
= snprintf(service
, servicelen
, "%d", port
);
465 if (ret
< 0 || (size_t)ret
>= servicelen
) {
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
)) {
486 if (sa
->sa_family
!= AF_INET
) {
490 if (salen
< (socklen_t
)sizeof (struct sockaddr_in
)) {
495 int ret
= gethostnameinfo(sa
, node
, nodelen
, flags
);
501 return getservicenameinfo(sa
, service
, servicelen
, flags
);