]> granicus.if.org Git - postgresql/blob - src/port/getaddrinfo.c
Remove references to sa_family_t, except when SOCKADDR_STORAGE requires
[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.9 2003/06/23 23:52:00 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 #ifdef FRONTEND
88                         struct hostent hpstr;
89                         char buf[BUFSIZ];
90                         int herrno = 0;
91
92                         pqGethostbyname(node, &hpstr, buf, sizeof(buf),
93                                         &hp, &herrno);
94 #else
95                         hp = gethostbyname(node);
96 #endif
97                         if (hp == NULL)
98                         {
99                                 switch (h_errno)
100                                 {
101                                         case HOST_NOT_FOUND:
102                                         case NO_DATA:
103                                                 return EAI_NONAME;
104                                         case TRY_AGAIN:
105                                                 return EAI_AGAIN;
106                                         case NO_RECOVERY:
107                                         default:
108                                                 return EAI_FAIL;
109                                 }
110                         }
111                         if (hp->h_addrtype != AF_INET)
112                                 return EAI_FAIL;
113
114                         memcpy(&(sin.sin_addr), hp->h_addr, hp->h_length);
115                 }
116         }
117         else
118         {
119                 if (hints.ai_flags & AI_PASSIVE)
120                         sin.sin_addr.s_addr = htonl(INADDR_ANY);
121                 else
122                         sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
123         }
124
125         if (service)
126                 sin.sin_port = htons((unsigned short) atoi(service));
127 #if SALEN
128         sin.sin_len = sizeof(sin);
129 #endif
130
131         ai = malloc(sizeof(*ai));
132         if (!ai)
133         {
134                 return EAI_MEMORY;
135         }
136
137         psin = malloc(sizeof(*psin));
138         if (!psin)
139         {
140                 free(ai);
141                 return EAI_MEMORY;
142         }
143
144         memcpy(psin, &sin, sizeof(*psin));
145
146         ai->ai_flags = 0;
147         ai->ai_family = AF_INET;
148         ai->ai_socktype = hints.ai_socktype;
149         ai->ai_protocol = hints.ai_protocol;
150         ai->ai_addrlen = sizeof(*psin);
151         ai->ai_addr = (struct sockaddr *) psin;
152         ai->ai_canonname = NULL;
153         ai->ai_next = NULL;
154
155         *res = ai;
156
157         return 0;
158 }
159
160
161 void
162 freeaddrinfo(struct addrinfo *res)
163 {
164         if (res)
165         {
166                 if (res->ai_addr)
167                         free(res->ai_addr);
168                 free(res);
169         }
170 }
171
172
173 const char *
174 gai_strerror(int errcode)
175 {
176 #ifdef HAVE_HSTRERROR
177         int hcode;
178
179         switch (errcode)
180         {
181                 case EAI_NONAME:
182                         hcode = HOST_NOT_FOUND;
183                         break;
184                 case EAI_AGAIN:
185                         hcode = TRY_AGAIN;
186                         break;
187                 case EAI_FAIL:
188                 default:
189                         hcode = NO_RECOVERY;
190                         break;
191         }
192
193         return hstrerror(hcode);
194
195 #else /* !HAVE_HSTRERROR */
196
197         switch (errcode)
198         {
199                 case EAI_NONAME:
200                         return "Unknown host";
201                 case EAI_AGAIN:
202                         return "Host name lookup failure";
203                 case EAI_FAIL:
204                 default:
205                         return "Unknown server error";
206         }
207
208 #endif /* HAVE_HSTRERROR */
209 }
210
211 /*
212  * Convert an address to a hostname.
213  * 
214  * Bugs:        - Only supports NI_NUMERICHOST and NI_NUMERICSERV
215  *                It will never resolv a hostname.
216  *              - No IPv6 support.
217  */
218 int
219 getnameinfo(const struct sockaddr *sa, int salen,
220                 char *node, int nodelen,
221                 char *service, int servicelen, int flags)
222 {
223         int             ret = -1;
224
225         /* Invalid arguments. */
226         if (sa == NULL || (node == NULL && service == NULL))
227         {
228                 return EAI_FAIL;
229         }
230
231         /* We don't support those. */
232         if ((node && !(flags & NI_NUMERICHOST))
233                 || (service && !(flags & NI_NUMERICSERV)))
234         {
235                 return EAI_FAIL;
236         }
237
238 #ifdef  HAVE_IPV6
239         if (sa->sa_family == AF_INET6)
240         {
241                 return  EAI_FAMILY;
242         }
243 #endif
244
245         if (service)
246         {
247                 if (sa->sa_family == AF_INET)
248                 {
249                         ret = snprintf(service, servicelen, "%d",
250                                 ntohs(((struct sockaddr_in *)sa)->sin_port));
251                 }
252 #ifdef  HAVE_UNIX_SOCKETS
253                 else if (sa->sa_family == AF_UNIX)
254                 {
255                         ret = snprintf(service, servicelen, "%s",
256                                 ((struct sockaddr_un *)sa)->sun_path);
257                 }
258 #endif
259                 if (ret == -1 || ret > servicelen)
260                 {
261                         return EAI_MEMORY;
262                 }
263         }
264
265         if (node)
266         {
267                 if (sa->sa_family == AF_INET)
268                 {
269                         char    *p;
270                         p = inet_ntoa(((struct sockaddr_in *)sa)->sin_addr);
271                         ret = snprintf(node, nodelen, "%s", p);
272                 }
273 #ifdef  HAVE_UNIX_SOCKETS
274                 else if (sa->sa_family == AF_UNIX)
275                 {
276                         ret = snprintf(node, nodelen, "%s", "localhost");
277                 }
278 #endif
279                 if (ret == -1 || ret > nodelen)
280                 {
281                         return EAI_MEMORY;
282                 }
283         }
284
285         return 0;
286 }