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);