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 *-------------------------------------------------------------------------
47 #include "system/network.h"
50 #define SMB_MALLOC(s) malloc(s)
54 #define SMB_STRDUP(s) strdup(s)
57 static int check_hostent_err(struct hostent
*hp
)
71 if (!hp
->h_name
|| hp
->h_addrtype
!= AF_INET
) {
77 static char *canon_name_from_hostent(struct hostent
*hp
,
82 *perr
= check_hostent_err(hp
);
86 ret
= SMB_STRDUP(hp
->h_name
);
93 static char *get_my_canon_name(int *perr
)
95 char name
[HOST_NAME_MAX
+1];
97 if (gethostname(name
, HOST_NAME_MAX
) == -1) {
101 /* Ensure null termination. */
102 name
[HOST_NAME_MAX
] = '\0';
103 return canon_name_from_hostent(gethostbyname(name
), perr
);
106 static char *get_canon_name_from_addr(struct in_addr ip
,
109 return canon_name_from_hostent(
110 gethostbyaddr(&ip
, sizeof(ip
), AF_INET
),
114 static struct addrinfo
*alloc_entry(const struct addrinfo
*hints
,
118 struct sockaddr_in
*psin
= NULL
;
119 struct addrinfo
*ai
= SMB_MALLOC(sizeof(*ai
));
124 memset(ai
, '\0', sizeof(*ai
));
126 psin
= SMB_MALLOC(sizeof(*psin
));
132 memset(psin
, '\0', sizeof(*psin
));
134 psin
->sin_family
= AF_INET
;
135 psin
->sin_port
= htons(port
);
139 ai
->ai_family
= AF_INET
;
140 ai
->ai_socktype
= hints
->ai_socktype
;
141 ai
->ai_protocol
= hints
->ai_protocol
;
142 ai
->ai_addrlen
= sizeof(*psin
);
143 ai
->ai_addr
= (struct sockaddr
*) psin
;
144 ai
->ai_canonname
= NULL
;
151 * get address info for a single ipv4 address.
153 * Bugs: - servname can only be a number, not text.
156 static int getaddr_info_single_addr(const char *service
,
158 const struct addrinfo
*hints
,
159 struct addrinfo
**res
)
162 struct addrinfo
*ai
= NULL
;
164 unsigned short port
= 0;
167 port
= (unsigned short)atoi(service
);
169 ip
.s_addr
= htonl(addr
);
171 ai
= alloc_entry(hints
, ip
, port
);
176 /* If we're asked for the canonical name,
177 * make sure it returns correctly. */
178 if (!(hints
->ai_flags
& AI_NUMERICSERV
) &&
179 hints
->ai_flags
& AI_CANONNAME
) {
181 if (addr
== INADDR_LOOPBACK
|| addr
== INADDR_ANY
) {
182 ai
->ai_canonname
= get_my_canon_name(&err
);
185 get_canon_name_from_addr(ip
,&err
);
187 if (ai
->ai_canonname
== NULL
) {
198 * get address info for multiple ipv4 addresses.
200 * Bugs: - servname can only be a number, not text.
203 static int getaddr_info_name(const char *node
,
205 const struct addrinfo
*hints
,
206 struct addrinfo
**res
)
208 struct addrinfo
*listp
= NULL
, *prevp
= NULL
;
211 struct hostent
*hp
= NULL
;
212 unsigned short port
= 0;
215 port
= (unsigned short)atoi(service
);
218 hp
= gethostbyname(node
);
219 err
= check_hostent_err(hp
);
224 for(pptr
= hp
->h_addr_list
; *pptr
; pptr
++) {
225 struct in_addr ip
= *(struct in_addr
*)*pptr
;
226 struct addrinfo
*ai
= alloc_entry(hints
, ip
, port
);
236 ai
->ai_canonname
= SMB_STRDUP(hp
->h_name
);
237 if (!ai
->ai_canonname
) {
251 * get address info for ipv4 sockets.
253 * Bugs: - servname can only be a number, not text.
256 int rep_getaddrinfo(const char *node
,
258 const struct addrinfo
* hintp
,
259 struct addrinfo
** res
)
261 struct addrinfo hints
;
263 /* Setup the hints struct. */
265 memset(&hints
, 0, sizeof(hints
));
266 hints
.ai_family
= AF_INET
;
267 hints
.ai_socktype
= SOCK_STREAM
;
269 memcpy(&hints
, hintp
, sizeof(hints
));
272 if (hints
.ai_family
!= AF_INET
&& hints
.ai_family
!= AF_UNSPEC
) {
276 if (hints
.ai_socktype
== 0) {
277 hints
.ai_socktype
= SOCK_STREAM
;
280 if (!node
&& !service
) {
285 if (node
[0] == '\0') {
286 return getaddr_info_single_addr(service
,
290 } else if (hints
.ai_flags
& AI_NUMERICHOST
) {
292 if (!inet_aton(node
, &ip
)) {
295 return getaddr_info_single_addr(service
,
300 return getaddr_info_name(node
,
305 } else if (hints
.ai_flags
& AI_PASSIVE
) {
306 return getaddr_info_single_addr(service
,
311 return getaddr_info_single_addr(service
,
318 void rep_freeaddrinfo(struct addrinfo
*res
)
320 struct addrinfo
*next
= NULL
;
322 for (;res
; res
= next
) {
324 if (res
->ai_canonname
) {
325 free(res
->ai_canonname
);
335 const char *rep_gai_strerror(int errcode
)
337 #ifdef HAVE_HSTRERROR
343 hcode
= HOST_NOT_FOUND
;
354 return hstrerror(hcode
);
355 #else /* !HAVE_HSTRERROR */
360 return "Unknown host";
362 return "Host name lookup failure";
365 return "Invalid argument";
369 return "Address family not supported";
373 return "Not enough memory";
377 return "No host data of that type was found";
381 return "Class type not found";
385 return "Socket type not supported";
388 return "Unknown server error";
390 #endif /* HAVE_HSTRERROR */
393 static int gethostnameinfo(const struct sockaddr
*sa
,
401 if (!(flags
& NI_NUMERICHOST
)) {
402 struct hostent
*hp
= gethostbyaddr(
403 &((struct sockaddr_in
*)sa
)->sin_addr
,
404 sizeof(struct in_addr
),
406 ret
= check_hostent_err(hp
);
408 /* Name looked up successfully. */
409 ret
= snprintf(node
, nodelen
, "%s", hp
->h_name
);
410 if (ret
< 0 || (size_t)ret
>= nodelen
) {
413 if (flags
& NI_NOFQDN
) {
414 p
= strchr(node
,'.');
422 if (flags
& NI_NAMEREQD
) {
423 /* If we require a name and didn't get one,
424 * automatically fail. */
427 /* Otherwise just fall into the numeric host code... */
429 p
= inet_ntoa(((struct sockaddr_in
*)sa
)->sin_addr
);
430 ret
= snprintf(node
, nodelen
, "%s", p
);
431 if (ret
< 0 || (size_t)ret
>= nodelen
) {
437 static int getservicenameinfo(const struct sockaddr
*sa
,
443 int port
= ntohs(((struct sockaddr_in
*)sa
)->sin_port
);
445 if (!(flags
& NI_NUMERICSERV
)) {
446 struct servent
*se
= getservbyport(
448 (flags
& NI_DGRAM
) ? "udp" : "tcp");
449 if (se
&& se
->s_name
) {
450 /* Service name looked up successfully. */
451 ret
= snprintf(service
, servicelen
, "%s", se
->s_name
);
452 if (ret
< 0 || (size_t)ret
>= servicelen
) {
457 /* Otherwise just fall into the numeric service code... */
459 ret
= snprintf(service
, servicelen
, "%d", port
);
460 if (ret
< 0 || (size_t)ret
>= servicelen
) {
467 * Convert an ipv4 address to a hostname.
469 * Bugs: - No IPv6 support.
471 int rep_getnameinfo(const struct sockaddr
*sa
, socklen_t salen
,
472 char *node
, size_t nodelen
,
473 char *service
, size_t servicelen
, int flags
)
476 /* Invalid arguments. */
477 if (sa
== NULL
|| (node
== NULL
&& service
== NULL
)) {
481 if (sa
->sa_family
!= AF_INET
) {
485 if (salen
< sizeof(struct sockaddr_in
)) {
490 return gethostnameinfo(sa
, node
, nodelen
, flags
);
494 return getservicenameinfo(sa
, service
, servicelen
, flags
);