1 /*-------------------------------------------------------------------------
4 * Support getaddrinfo() on platforms that don't have it.
6 * We also supply getnameinfo() here, assuming that the platform will have
7 * it if and only if it has getaddrinfo(). If this proves false on some
8 * platform, we'll need to split this file and provide a separate configure
9 * test for getnameinfo().
12 * Copyright (c) 2003, PostgreSQL Global Development Group
15 * $Header: /cvsroot/pgsql/src/port/getaddrinfo.c,v 1.10 2003/07/23 23:30:41 tgl Exp $
17 *-------------------------------------------------------------------------
20 /* This is intended to be used in both frontend and backend, so use c.h */
23 #if !defined(_MSC_VER) && !defined(__BORLANDC__)
24 #include <sys/types.h>
25 #include <sys/socket.h>
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
31 #include "getaddrinfo.h"
34 * get address info for ipv4 sockets.
36 * Bugs: - only one addrinfo is set even though hintp is NULL or
38 * - AI_CANONNAME is not supported.
39 * - servname can only be a number, not text.
42 getaddrinfo(const char *node, const char *service,
43 const struct addrinfo *hintp,
44 struct addrinfo **res)
47 struct sockaddr_in sin, *psin;
48 struct addrinfo hints;
52 memset(&hints, 0, sizeof(hints));
53 hints.ai_family = AF_INET;
54 hints.ai_socktype = SOCK_STREAM;
58 memcpy(&hints, hintp, sizeof(hints));
61 if (hints.ai_family != AF_INET && hints.ai_family != AF_UNSPEC)
64 if (hints.ai_socktype == 0)
65 hints.ai_socktype = SOCK_STREAM;
67 if (!node && !service)
70 memset(&sin, 0, sizeof(sin));
72 sin.sin_family = AF_INET;
77 sin.sin_addr.s_addr = htonl(INADDR_ANY);
78 else if (hints.ai_flags & AI_NUMERICHOST)
80 if (!inet_aton(node, &sin.sin_addr))
93 pqGethostbyname(node, &hpstr, buf, sizeof(buf),
96 hp = gethostbyname(node);
112 if (hp->h_addrtype != AF_INET)
115 memcpy(&(sin.sin_addr), hp->h_addr, hp->h_length);
120 if (hints.ai_flags & AI_PASSIVE)
121 sin.sin_addr.s_addr = htonl(INADDR_ANY);
123 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
127 sin.sin_port = htons((unsigned short) atoi(service));
129 #ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN
130 sin.sin_len = sizeof(sin);
133 ai = malloc(sizeof(*ai));
139 psin = malloc(sizeof(*psin));
146 memcpy(psin, &sin, sizeof(*psin));
149 ai->ai_family = AF_INET;
150 ai->ai_socktype = hints.ai_socktype;
151 ai->ai_protocol = hints.ai_protocol;
152 ai->ai_addrlen = sizeof(*psin);
153 ai->ai_addr = (struct sockaddr *) psin;
154 ai->ai_canonname = NULL;
164 freeaddrinfo(struct addrinfo *res)
176 gai_strerror(int errcode)
178 #ifdef HAVE_HSTRERROR
184 hcode = HOST_NOT_FOUND;
195 return hstrerror(hcode);
197 #else /* !HAVE_HSTRERROR */
202 return "Unknown host";
204 return "Host name lookup failure";
207 return "Unknown server error";
210 #endif /* HAVE_HSTRERROR */
214 * Convert an ipv4 address to a hostname.
216 * Bugs: - Only supports NI_NUMERICHOST and NI_NUMERICSERV
217 * It will never resolv a hostname.
221 getnameinfo(const struct sockaddr *sa, int salen,
222 char *node, int nodelen,
223 char *service, int servicelen, int flags)
225 /* Invalid arguments. */
226 if (sa == NULL || (node == NULL && service == NULL))
231 /* We don't support those. */
232 if ((node && !(flags & NI_NUMERICHOST))
233 || (service && !(flags & NI_NUMERICSERV)))
239 if (sa->sa_family == AF_INET6)
249 if (sa->sa_family == AF_INET)
252 p = inet_ntoa(((struct sockaddr_in *)sa)->sin_addr);
253 ret = snprintf(node, nodelen, "%s", p);
255 if (ret == -1 || ret > nodelen)
265 if (sa->sa_family == AF_INET)
267 ret = snprintf(service, servicelen, "%d",
268 ntohs(((struct sockaddr_in *)sa)->sin_port));
270 if (ret == -1 || ret > servicelen)