]> granicus.if.org Git - postgresql/blob - src/port/getaddrinfo.c
Fix a whole bunch of #includes that were either wrong or redundant.
[postgresql] / src / port / getaddrinfo.c
1 /*-------------------------------------------------------------------------
2  *
3  * getaddrinfo.c
4  *        Support getaddrinfo() on platforms that don't have it.
5  *
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().
10  *
11  *
12  * Copyright (c) 2003-2005, PostgreSQL Global Development Group
13  *
14  * IDENTIFICATION
15  *        $PostgreSQL: pgsql/src/port/getaddrinfo.c,v 1.17 2005/07/28 04:03:14 tgl Exp $
16  *
17  *-------------------------------------------------------------------------
18  */
19
20 /* This is intended to be used in both frontend and backend, so use c.h */
21 #include "c.h"
22
23 #ifndef WIN32_CLIENT_ONLY
24 #include <sys/socket.h>
25 #include <netdb.h>
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
28 #endif
29
30 #include "getaddrinfo.h"
31
32 /*
33  * get address info for ipv4 sockets.
34  *
35  *      Bugs:   - only one addrinfo is set even though hintp is NULL or
36  *                ai_socktype is 0
37  *              - AI_CANONNAME is not supported.
38  *              - servname can only be a number, not text.
39  */
40 int
41 getaddrinfo(const char *node, const char *service,
42                         const struct addrinfo * hintp,
43                         struct addrinfo ** res)
44 {
45         struct addrinfo *ai;
46         struct sockaddr_in sin,
47                            *psin;
48         struct addrinfo hints;
49
50         if (hintp == NULL)
51         {
52                 memset(&hints, 0, sizeof(hints));
53                 hints.ai_family = AF_INET;
54                 hints.ai_socktype = SOCK_STREAM;
55         }
56         else
57                 memcpy(&hints, hintp, sizeof(hints));
58
59         if (hints.ai_family != AF_INET && hints.ai_family != AF_UNSPEC)
60                 return EAI_FAMILY;
61
62         if (hints.ai_socktype == 0)
63                 hints.ai_socktype = SOCK_STREAM;
64
65         if (!node && !service)
66                 return EAI_NONAME;
67
68         memset(&sin, 0, sizeof(sin));
69
70         sin.sin_family = AF_INET;
71
72         if (node)
73         {
74                 if (node[0] == '\0')
75                         sin.sin_addr.s_addr = htonl(INADDR_ANY);
76                 else if (hints.ai_flags & AI_NUMERICHOST)
77                 {
78                         if (!inet_aton(node, &sin.sin_addr))
79                                 return EAI_FAIL;
80                 }
81                 else
82                 {
83                         struct hostent *hp;
84
85 #ifdef FRONTEND
86                         struct hostent hpstr;
87                         char            buf[BUFSIZ];
88                         int                     herrno = 0;
89
90                         pqGethostbyname(node, &hpstr, buf, sizeof(buf),
91                                                         &hp, &herrno);
92 #else
93                         hp = gethostbyname(node);
94 #endif
95                         if (hp == NULL)
96                         {
97                                 switch (h_errno)
98                                 {
99                                         case HOST_NOT_FOUND:
100                                         case NO_DATA:
101                                                 return EAI_NONAME;
102                                         case TRY_AGAIN:
103                                                 return EAI_AGAIN;
104                                         case NO_RECOVERY:
105                                         default:
106                                                 return EAI_FAIL;
107                                 }
108                         }
109                         if (hp->h_addrtype != AF_INET)
110                                 return EAI_FAIL;
111
112                         memcpy(&(sin.sin_addr), hp->h_addr, hp->h_length);
113                 }
114         }
115         else
116         {
117                 if (hints.ai_flags & AI_PASSIVE)
118                         sin.sin_addr.s_addr = htonl(INADDR_ANY);
119                 else
120                         sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
121         }
122
123         if (service)
124                 sin.sin_port = htons((unsigned short) atoi(service));
125
126 #ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN
127         sin.sin_len = sizeof(sin);
128 #endif
129
130         ai = malloc(sizeof(*ai));
131         if (!ai)
132                 return EAI_MEMORY;
133
134         psin = malloc(sizeof(*psin));
135         if (!psin)
136         {
137                 free(ai);
138                 return EAI_MEMORY;
139         }
140
141         memcpy(psin, &sin, sizeof(*psin));
142
143         ai->ai_flags = 0;
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;
150         ai->ai_next = NULL;
151
152         *res = ai;
153
154         return 0;
155 }
156
157
158 void
159 freeaddrinfo(struct addrinfo * res)
160 {
161         if (res)
162         {
163                 if (res->ai_addr)
164                         free(res->ai_addr);
165                 free(res);
166         }
167 }
168
169
170 const char *
171 gai_strerror(int errcode)
172 {
173 #ifdef HAVE_HSTRERROR
174         int                     hcode;
175
176         switch (errcode)
177         {
178                 case EAI_NONAME:
179                         hcode = HOST_NOT_FOUND;
180                         break;
181                 case EAI_AGAIN:
182                         hcode = TRY_AGAIN;
183                         break;
184                 case EAI_FAIL:
185                 default:
186                         hcode = NO_RECOVERY;
187                         break;
188         }
189
190         return hstrerror(hcode);
191
192 #else                                                   /* !HAVE_HSTRERROR */
193
194         switch (errcode)
195         {
196                 case EAI_NONAME:
197                         return "Unknown host";
198                 case EAI_AGAIN:
199                         return "Host name lookup failure";
200                 case EAI_FAIL:
201                 default:
202                         return "Unknown server error";
203         }
204 #endif   /* HAVE_HSTRERROR */
205 }
206
207 /*
208  * Convert an ipv4 address to a hostname.
209  *
210  * Bugs:        - Only supports NI_NUMERICHOST and NI_NUMERICSERV
211  *                It will never resolv a hostname.
212  *              - No IPv6 support.
213  */
214 int
215 getnameinfo(const struct sockaddr * sa, int salen,
216                         char *node, int nodelen,
217                         char *service, int servicelen, int flags)
218 {
219         /* Invalid arguments. */
220         if (sa == NULL || (node == NULL && service == NULL))
221                 return EAI_FAIL;
222
223         /* We don't support those. */
224         if ((node && !(flags & NI_NUMERICHOST))
225                 || (service && !(flags & NI_NUMERICSERV)))
226                 return EAI_FAIL;
227
228 #ifdef  HAVE_IPV6
229         if (sa->sa_family == AF_INET6)
230                 return EAI_FAMILY;
231 #endif
232
233         if (node)
234         {
235                 int                     ret = -1;
236
237                 if (sa->sa_family == AF_INET)
238                 {
239                         char       *p;
240
241                         p = inet_ntoa(((struct sockaddr_in *) sa)->sin_addr);
242                         ret = snprintf(node, nodelen, "%s", p);
243                 }
244                 if (ret == -1 || ret > nodelen)
245                         return EAI_MEMORY;
246         }
247
248         if (service)
249         {
250                 int                     ret = -1;
251
252                 if (sa->sa_family == AF_INET)
253                 {
254                         ret = snprintf(service, servicelen, "%d",
255                                                    ntohs(((struct sockaddr_in *) sa)->sin_port));
256                 }
257                 if (ret == -1 || ret > servicelen)
258                         return EAI_MEMORY;
259         }
260
261         return 0;
262 }