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-2005, PostgreSQL Global Development Group
15 * $PostgreSQL: pgsql/src/port/getaddrinfo.c,v 1.17 2005/07/28 04:03:14 tgl Exp $
17 *-------------------------------------------------------------------------
20 /* This is intended to be used in both frontend and backend, so use c.h */
23 #ifndef WIN32_CLIENT_ONLY
24 #include <sys/socket.h>
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
30 #include "getaddrinfo.h"
33 * get address info for ipv4 sockets.
35 * Bugs: - only one addrinfo is set even though hintp is NULL or
37 * - AI_CANONNAME is not supported.
38 * - servname can only be a number, not text.
41 getaddrinfo(const char *node, const char *service,
42 const struct addrinfo * hintp,
43 struct addrinfo ** res)
46 struct sockaddr_in sin,
48 struct addrinfo hints;
52 memset(&hints, 0, sizeof(hints));
53 hints.ai_family = AF_INET;
54 hints.ai_socktype = SOCK_STREAM;
57 memcpy(&hints, hintp, sizeof(hints));
59 if (hints.ai_family != AF_INET && hints.ai_family != AF_UNSPEC)
62 if (hints.ai_socktype == 0)
63 hints.ai_socktype = SOCK_STREAM;
65 if (!node && !service)
68 memset(&sin, 0, sizeof(sin));
70 sin.sin_family = AF_INET;
75 sin.sin_addr.s_addr = htonl(INADDR_ANY);
76 else if (hints.ai_flags & AI_NUMERICHOST)
78 if (!inet_aton(node, &sin.sin_addr))
90 pqGethostbyname(node, &hpstr, buf, sizeof(buf),
93 hp = gethostbyname(node);
109 if (hp->h_addrtype != AF_INET)
112 memcpy(&(sin.sin_addr), hp->h_addr, hp->h_length);
117 if (hints.ai_flags & AI_PASSIVE)
118 sin.sin_addr.s_addr = htonl(INADDR_ANY);
120 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
124 sin.sin_port = htons((unsigned short) atoi(service));
126 #ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN
127 sin.sin_len = sizeof(sin);
130 ai = malloc(sizeof(*ai));
134 psin = malloc(sizeof(*psin));
141 memcpy(psin, &sin, sizeof(*psin));
144 ai->ai_family = AF_INET;
145 ai->ai_socktype = hints.ai_socktype;
146 ai->ai_protocol = hints.ai_protocol;
147 ai->ai_addrlen = sizeof(*psin);
148 ai->ai_addr = (struct sockaddr *) psin;
149 ai->ai_canonname = NULL;
159 freeaddrinfo(struct addrinfo * res)
171 gai_strerror(int errcode)
173 #ifdef HAVE_HSTRERROR
179 hcode = HOST_NOT_FOUND;
190 return hstrerror(hcode);
192 #else /* !HAVE_HSTRERROR */
197 return "Unknown host";
199 return "Host name lookup failure";
202 return "Unknown server error";
204 #endif /* HAVE_HSTRERROR */
208 * Convert an ipv4 address to a hostname.
210 * Bugs: - Only supports NI_NUMERICHOST and NI_NUMERICSERV
211 * It will never resolv a hostname.
215 getnameinfo(const struct sockaddr * sa, int salen,
216 char *node, int nodelen,
217 char *service, int servicelen, int flags)
219 /* Invalid arguments. */
220 if (sa == NULL || (node == NULL && service == NULL))
223 /* We don't support those. */
224 if ((node && !(flags & NI_NUMERICHOST))
225 || (service && !(flags & NI_NUMERICSERV)))
229 if (sa->sa_family == AF_INET6)
237 if (sa->sa_family == AF_INET)
241 p = inet_ntoa(((struct sockaddr_in *) sa)->sin_addr);
242 ret = snprintf(node, nodelen, "%s", p);
244 if (ret == -1 || ret > nodelen)
252 if (sa->sa_family == AF_INET)
254 ret = snprintf(service, servicelen, "%d",
255 ntohs(((struct sockaddr_in *) sa)->sin_port));
257 if (ret == -1 || ret > servicelen)