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