~vcs-imports/mammoth-replicator/trunk

« back to all changes in this revision

Viewing changes to src/port/getaddrinfo.c

  • Committer: alvherre
  • Date: 2005-12-16 21:24:52 UTC
  • Revision ID: svn-v4:db760fc0-0f08-0410-9d63-cc6633f64896:trunk:1
Initial import of the REL8_0_3 sources from the Pgsql CVS repository.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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.16 2005-01-01 20:44:33 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/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
}