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.11 2003/08/04 00:43:33 momjian 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,
49 struct addrinfo hints;
53 memset(&hints, 0, sizeof(hints));
54 hints.ai_family = AF_INET;
55 hints.ai_socktype = SOCK_STREAM;
58 memcpy(&hints, hintp, sizeof(hints));
60 if (hints.ai_family != AF_INET && hints.ai_family != AF_UNSPEC)
63 if (hints.ai_socktype == 0)
64 hints.ai_socktype = SOCK_STREAM;
66 if (!node && !service)
69 memset(&sin, 0, sizeof(sin));
71 sin.sin_family = AF_INET;
76 sin.sin_addr.s_addr = htonl(INADDR_ANY);
77 else if (hints.ai_flags & AI_NUMERICHOST)
79 if (!inet_aton(node, &sin.sin_addr))
91 pqGethostbyname(node, &hpstr, buf, sizeof(buf),
94 hp = gethostbyname(node);
110 if (hp->h_addrtype != AF_INET)
113 memcpy(&(sin.sin_addr), hp->h_addr, hp->h_length);
118 if (hints.ai_flags & AI_PASSIVE)
119 sin.sin_addr.s_addr = htonl(INADDR_ANY);
121 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
125 sin.sin_port = htons((unsigned short) atoi(service));
127 #ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN
128 sin.sin_len = sizeof(sin);
131 ai = malloc(sizeof(*ai));
135 psin = malloc(sizeof(*psin));
142 memcpy(psin, &sin, sizeof(*psin));
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;
160 freeaddrinfo(struct addrinfo * res)
172 gai_strerror(int errcode)
174 #ifdef HAVE_HSTRERROR
180 hcode = HOST_NOT_FOUND;
191 return hstrerror(hcode);
193 #else /* !HAVE_HSTRERROR */
198 return "Unknown host";
200 return "Host name lookup failure";
203 return "Unknown server error";
205 #endif /* HAVE_HSTRERROR */
209 * Convert an ipv4 address to a hostname.
211 * Bugs: - Only supports NI_NUMERICHOST and NI_NUMERICSERV
212 * It will never resolv a hostname.
216 getnameinfo(const struct sockaddr * sa, int salen,
217 char *node, int nodelen,
218 char *service, int servicelen, int flags)
220 /* Invalid arguments. */
221 if (sa == NULL || (node == NULL && service == NULL))
224 /* We don't support those. */
225 if ((node && !(flags & NI_NUMERICHOST))
226 || (service && !(flags & NI_NUMERICSERV)))
230 if (sa->sa_family == AF_INET6)
238 if (sa->sa_family == AF_INET)
242 p = inet_ntoa(((struct sockaddr_in *) sa)->sin_addr);
243 ret = snprintf(node, nodelen, "%s", p);
245 if (ret == -1 || ret > nodelen)
253 if (sa->sa_family == AF_INET)
255 ret = snprintf(service, servicelen, "%d",
256 ntohs(((struct sockaddr_in *) sa)->sin_port));
258 if (ret == -1 || ret > servicelen)