]> granicus.if.org Git - postgresql/blob - src/port/getaddrinfo.c
Attached is the complete diff against current CVS.
[postgresql] / src / port / getaddrinfo.c
1 /*-------------------------------------------------------------------------
2  *
3  * getaddrinfo.c
4  *        Support getaddrinfo() on platforms that don't have it.
5  *
6  *
7  * Copyright (c) 2003, PostgreSQL Global Development Group
8  *
9  *
10  * IDENTIFICATION
11  *        $Header: /cvsroot/pgsql/src/port/getaddrinfo.c,v 1.7 2003/06/12 08:15:29 momjian Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15
16 /* This is intended to be used in both frontend and backend, so use c.h */
17 #include "c.h"
18
19 #if !defined(_MSC_VER) && !defined(__BORLANDC__)
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <netdb.h>
23 #include <netinet/in.h>
24 #include <arpa/inet.h>
25 #ifdef  HAVE_UNIX_SOCKETS
26 #include <sys/un.h>
27 #endif
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, *psin;
47         struct addrinfo         hints;
48
49         if (hintp == NULL)      
50         {
51                 memset(&hints, 0, sizeof(hints));
52                 hints.ai_family = AF_INET;
53                 hints.ai_socktype = SOCK_STREAM;
54         }
55         else
56         {
57                 memcpy(&hints, hintp, sizeof(hints));
58         }
59
60         if (hints.ai_family != AF_INET && hints.ai_family != AF_UNSPEC)
61                 return EAI_FAMILY;
62
63         if (hints.ai_socktype == 0)
64                 hints.ai_socktype = SOCK_STREAM;
65
66         if (!node && !service)
67                 return EAI_NONAME;
68
69         memset(&sin, 0, sizeof(sin));
70
71         sin.sin_family = AF_INET;
72
73         if (node)
74         {
75                 if (node[0] == '\0')
76                         sin.sin_addr.s_addr = htonl(INADDR_ANY);
77                 else if (hints.ai_flags & AI_NUMERICHOST)
78                 {
79                         if (!inet_aton(node, &sin.sin_addr))
80                         {
81                                 return EAI_FAIL;
82                         }
83                 }
84                 else
85                 {
86                         struct hostent *hp;
87
88                         hp = gethostbyname(node);
89                         if (hp == NULL)
90                         {
91                                 switch (h_errno)
92                                 {
93                                         case HOST_NOT_FOUND:
94                                         case NO_DATA:
95                                                 return EAI_NONAME;
96                                         case TRY_AGAIN:
97                                                 return EAI_AGAIN;
98                                         case NO_RECOVERY:
99                                         default:
100                                                 return EAI_FAIL;
101                                 }
102                         }
103                         if (hp->h_addrtype != AF_INET)
104                                 return EAI_FAIL;
105
106                         memcpy(&(sin.sin_addr), hp->h_addr, hp->h_length);
107                 }
108         }
109         else
110         {
111                 if (hints.ai_flags & AI_PASSIVE)
112                         sin.sin_addr.s_addr = htonl(INADDR_ANY);
113                 else
114                         sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
115         }
116
117         if (service)
118                 sin.sin_port = htons((unsigned short) atoi(service));
119 #if SALEN
120         sin.sin_len = sizeof(sin);
121 #endif
122
123         ai = malloc(sizeof(*ai));
124         if (!ai)
125         {
126                 return EAI_MEMORY;
127         }
128
129         psin = malloc(sizeof(*psin));
130         if (!psin)
131         {
132                 free(ai);
133                 return EAI_MEMORY;
134         }
135
136         memcpy(psin, &sin, sizeof(*psin));
137
138         ai->ai_flags = 0;
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;
145         ai->ai_next = NULL;
146
147         *res = ai;
148
149         return 0;
150 }
151
152
153 void
154 freeaddrinfo(struct addrinfo *res)
155 {
156         if (res)
157         {
158                 if (res->ai_addr)
159                         free(res->ai_addr);
160                 free(res);
161         }
162 }
163
164
165 const char *
166 gai_strerror(int errcode)
167 {
168 #ifdef HAVE_HSTRERROR
169         int hcode;
170
171         switch (errcode)
172         {
173                 case EAI_NONAME:
174                         hcode = HOST_NOT_FOUND;
175                         break;
176                 case EAI_AGAIN:
177                         hcode = TRY_AGAIN;
178                         break;
179                 case EAI_FAIL:
180                 default:
181                         hcode = NO_RECOVERY;
182                         break;
183         }
184
185         return hstrerror(hcode);
186
187 #else /* !HAVE_HSTRERROR */
188
189         switch (errcode)
190         {
191                 case EAI_NONAME:
192                         return "Unknown host";
193                 case EAI_AGAIN:
194                         return "Host name lookup failure";
195                 case EAI_FAIL:
196                 default:
197                         return "Unknown server error";
198         }
199
200 #endif /* HAVE_HSTRERROR */
201 }
202
203 /*
204  * Convert an address to a hostname.
205  * 
206  * Bugs:        - Only supports NI_NUMERICHOST and NI_NUMERICSERV
207  *                It will never resolv a hostname.
208  *              - No IPv6 support.
209  */
210 int
211 getnameinfo(const struct sockaddr *sa, int salen,
212                 char *node, int nodelen,
213                 char *service, int servicelen, int flags)
214 {
215         sa_family_t     family;
216         int             ret = -1;
217
218         /* Invalid arguments. */
219         if (sa == NULL || (node == NULL && service == NULL))
220         {
221                 return EAI_FAIL;
222         }
223
224         /* We don't support those. */
225         if ((node && !(flags & NI_NUMERICHOST))
226                 || (service && !(flags & NI_NUMERICSERV)))
227         {
228                 return EAI_FAIL;
229         }
230
231         family = sa->sa_family;
232 #ifdef  HAVE_IPV6
233         if (family == AF_INET6)
234         {
235                 return  EAI_FAMILY;
236         }
237 #endif
238
239         if (service)
240         {
241                 if (family == AF_INET)
242                 {
243                         ret = snprintf(service, servicelen, "%d",
244                                 ntohs(((struct sockaddr_in *)sa)->sin_port));
245                 }
246 #ifdef  HAVE_UNIX_SOCKETS
247                 else if (family == AF_UNIX)
248                 {
249                         ret = snprintf(service, servicelen, "%s",
250                                 ((struct sockaddr_un *)sa)->sun_path);
251                 }
252 #endif
253                 if (ret == -1 || ret > servicelen)
254                 {
255                         return EAI_MEMORY;
256                 }
257         }
258
259         if (node)
260         {
261                 if (family == AF_INET)
262                 {
263                         char    *p;
264                         p = inet_ntoa(((struct sockaddr_in *)sa)->sin_addr);
265                         ret = snprintf(node, nodelen, "%s", p);
266                 }
267 #ifdef  HAVE_UNIX_SOCKETS
268                 else if (family == AF_UNIX)
269                 {
270                         ret = snprintf(node, nodelen, "%s", "localhost");
271                 }
272 #endif
273                 if (ret == -1 || ret > nodelen)
274                 {
275                         return EAI_MEMORY;
276                 }
277         }
278
279         return 0;
280 }