2
* Copyright 2007 by Paul Mattes.
3
* Permission to use, copy, modify, and distribute this software and its
4
* documentation for any purpose and without fee is hereby granted,
5
* provided that the above copyright notice appear in all copies and that
6
* both that copyright notice and this permission notice appear in
7
* supporting documentation.
9
* x3270, c3270, wc3270, s3270, tcl3270, pr3287 and wpr3287 are distributed in
10
* the hope that they will be useful, but WITHOUT ANY WARRANTY; without even
11
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
* See the file LICENSE for more details.
2
* Copyright (c) 2007-2009, Paul Mattes.
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions are met:
7
* * Redistributions of source code must retain the above copyright
8
* notice, this list of conditions and the following disclaimer.
9
* * Redistributions in binary form must reproduce the above copyright
10
* notice, this list of conditions and the following disclaimer in the
11
* documentation and/or other materials provided with the distribution.
12
* * Neither the names of Paul Mattes nor the names of his contributors
13
* may be used to endorse or promote products derived from this software
14
* without specific prior written permission.
16
* THIS SOFTWARE IS PROVIDED BY PAUL MATTES "AS IS" AND ANY EXPRESS OR IMPLIED
17
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19
* EVENT SHALL PAUL MATTES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
77
69
* Returns 0 for success, -1 for fatal error (name resolution impossible),
78
70
* -2 for simple error (cannot resolve the name).
80
#if !defined(ISDLL) /*[*/
82
resolve_host_and_port(const char *host, char *portname, unsigned short *pport,
83
struct sockaddr *sa, socklen_t *sa_len, char *errmsg, int em_len)
86
dresolve_host_and_port(const char *host, char *portname, unsigned short *pport,
87
struct sockaddr *sa, socklen_t *sa_len, char *errmsg, int em_len)
90
#if !defined(_WIN32) || defined(ISDLL) /*[*/
92
/* Non-Windows version, or Windows DLL version. */
93
#if defined(AF_INET6) /*[*/
94
struct addrinfo hints, *res;
97
/* Use getaddrinfo() to resolve the hostname and port together. */
98
(void) memset(&hints, '\0', sizeof(struct addrinfo));
100
hints.ai_family = PF_UNSPEC;
101
hints.ai_socktype = SOCK_STREAM;
102
hints.ai_protocol = IPPROTO_TCP;
103
rc = getaddrinfo(host, portname, &hints, &res);
105
snprintf(errmsg, em_len, "%s/%s: %s", host, portname,
109
switch (res->ai_family) {
112
ntohs(((struct sockaddr_in *)res->ai_addr)->sin_port);
116
ntohs(((struct sockaddr_in6 *)res->ai_addr)->sin6_port);
119
snprintf(errmsg, em_len, "%s: unknown family %d", host,
124
(void) memcpy(sa, res->ai_addr, res->ai_addrlen);
125
*sa_len = res->ai_addrlen;
135
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
137
/* Get the port number. */
138
lport = strtoul(portname, &ptr, 0);
139
if (ptr == portname || *ptr != '\0' || lport == 0L || lport & ~0xffff) {
140
if (!(sp = getservbyname(portname, "tcp"))) {
141
snprintf(errmsg, em_len,
142
"Unknown port number or service: %s",
148
port = htons((unsigned short)lport);
149
*pport = ntohs(port);
151
/* Use gethostbyname() to resolve the hostname. */
152
hp = gethostbyname(host);
153
if (hp == (struct hostent *) 0) {
154
sin->sin_family = AF_INET;
155
sin->sin_addr.s_addr = inet_addr(host);
156
if (sin->sin_addr.s_addr == (unsigned long)-1) {
157
snprintf(errmsg, em_len, "Unknown host:\n%s", host);
161
sin->sin_family = hp->h_addrtype;
162
(void) memmove(&sin->sin_addr, hp->h_addr, hp->h_length);
164
sin->sin_port = port;
165
*sa_len = sizeof(struct sockaddr_in);
170
/* Win32 version: Use the right DLL. */
171
static int loaded = FALSE;
172
static FARPROC p = NULL;
179
/* Figure out if we are pre- or post XP. */
180
memset(&info, '\0', sizeof(info));
181
info.dwOSVersionInfoSize = sizeof(info);
183
if (GetVersionEx(&info) == 0) {
184
snprintf(errmsg, em_len,
185
"Can't retrieve OS version: %s",
186
win32_strerror(GetLastError()));
191
* For pre-XP, load the IPv4-only DLL.
192
* For XP and later, use the IPv4/IPv6 DLL.
194
if (info.dwMajorVersion < 5 ||
195
(info.dwMajorVersion == 5 && info.dwMinorVersion < 1))
196
dllname = "w3n4.dll";
198
dllname = "w3n46.dll";
199
handle = LoadLibrary(dllname);
200
if (handle == NULL) {
201
snprintf(errmsg, em_len, "Can't load %s: %s",
202
dllname, win32_strerror(GetLastError()));
206
/* Look up the entry point we need. */
207
p = GetProcAddress(handle, DLL_RESOLVER_NAME);
209
snprintf(errmsg, em_len,
210
"Can't resolve " DLL_RESOLVER_NAME
211
" in %s: %s", dllname,
212
win32_strerror(GetLastError()));
219
/* Use the DLL function to resolve the hostname and port. */
220
return ((rhproc *)p)(host, portname, pport, sa, sa_len, errmsg, em_len);
73
resolve_host_and_port(const char *host, char *portname, int ix,
74
unsigned short *pport, struct sockaddr *sa, socklen_t *sa_len,
75
char *errmsg, int em_len, int *lastp)
77
#if defined(_WIN32) /*[*/
79
Boolean has_getaddrinfo = False;
81
/* Figure out if we should use gethostbyname() or getaddrinfo(). */
82
memset(&info, '\0', sizeof(info));
83
info.dwOSVersionInfoSize = sizeof(info);
84
if (GetVersionEx(&info) == 0) {
85
fprintf(stderr, "Can't get Windows version\n");
89
(info.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS &&
90
info.dwMajorVersion >= 5 &&
91
info.dwMinorVersion >= 1);
96
#if defined(AF_INET6) /*[*/
97
struct addrinfo hints, *res0, *res;
101
* Use getaddrinfo() to resolve the hostname and port
104
(void) memset(&hints, '\0', sizeof(struct addrinfo));
106
hints.ai_family = PF_UNSPEC;
107
hints.ai_socktype = SOCK_STREAM;
108
hints.ai_protocol = IPPROTO_TCP;
109
rc = getaddrinfo(host, portname, &hints, &res0);
111
snprintf(errmsg, em_len, "%s/%s:\n%s", host,
112
portname? portname: "(none)",
119
* Return the reqested element.
120
* Hopefully the list will not change between calls.
122
while (ix && res->ai_next != NULL) {
127
/* Ran off the end? The list must have changed. */
128
snprintf(errmsg, em_len, "%s/%s:\n%s", host,
129
portname? portname: "(none)",
130
gai_strerror(EAI_AGAIN));
135
switch (res->ai_family) {
137
*pport = ntohs(((struct sockaddr_in *)
138
res->ai_addr)->sin_port);
141
*pport = ntohs(((struct sockaddr_in6 *)
142
res->ai_addr)->sin6_port);
145
snprintf(errmsg, em_len, "%s:\nunknown family %d", host,
150
(void) memcpy(sa, res->ai_addr, res->ai_addrlen);
151
*sa_len = res->ai_addrlen;
153
*lastp = (res->ai_next == NULL);
157
#if defined(_WIN32) /*[*/
161
#if defined(_WIN32) || !defined(AF_INET6) /*[*/
168
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
170
/* Get the port number. */
171
lport = strtoul(portname, &ptr, 0);
172
if (ptr == portname || *ptr != '\0' || lport == 0L ||
174
if (!(sp = getservbyname(portname, "tcp"))) {
175
snprintf(errmsg, em_len,
176
"Unknown port number or service: %s",
182
port = htons((unsigned short)lport);
183
*pport = ntohs(port);
185
/* Use gethostbyname() to resolve the hostname. */
186
hp = gethostbyname(host);
187
if (hp == (struct hostent *) 0) {
188
sin->sin_family = AF_INET;
189
sin->sin_addr.s_addr = inet_addr(host);
190
if (sin->sin_addr.s_addr == (unsigned long)-1) {
191
snprintf(errmsg, em_len,
192
"Unknown host:\n%s", host);
200
for (i = 0; i < ix; i++) {
201
if (hp->h_addr_list[i] == NULL) {
202
snprintf(errmsg, em_len,
203
"Unknown host:\n%s", host);
207
sin->sin_family = hp->h_addrtype;
208
(void) memmove(&sin->sin_addr,
212
*lastp = (hp->h_addr_list[i + 1] == NULL);
214
sin->sin_port = port;
215
*sa_len = sizeof(struct sockaddr_in);
224
* Resolve a sockaddr into a numeric hostname and port.
225
* Returns 0 for success, -1 for failure.
228
numeric_host_and_port(const struct sockaddr *sa, socklen_t salen, char *host,
229
size_t hostlen, char *serv, size_t servlen, char *errmsg, int em_len)
231
#if defined(_WIN32) /*[*/
233
Boolean has_getnameinfo = False;
235
/* Figure out if we should use inet_ntoa() or getnameinfo(). */
236
memset(&info, '\0', sizeof(info));
237
info.dwOSVersionInfoSize = sizeof(info);
238
if (GetVersionEx(&info) == 0) {
239
fprintf(stderr, "Can't get Windows version\n");
243
(info.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS &&
244
info.dwMajorVersion >= 5 &&
245
info.dwMinorVersion >= 1);
250
#if defined(AF_INET6) /*[*/
253
/* Use getnameinfo(). */
254
rc = getnameinfo(sa, salen, host, hostlen, serv, servlen,
255
NI_NUMERICHOST | NI_NUMERICSERV);
257
snprintf(errmsg, em_len, "%s", gai_strerror(rc));
262
#if defined(_WIN32) /*[*/
266
#if defined(_WIN32) || !defined(AF_INET6) /*[*/
268
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
270
/* Use inet_ntoa() and snprintf(). */
271
snprintf(host, hostlen, "%s", inet_ntoa(sin->sin_addr));
272
snprintf(serv, servlen, "%u", ntohs(sin->sin_port));
280
#if defined(_WIN32) /*[*/
282
* Windows-specific versions of getaddrinfo(), freeaddrinfo() and
284
* The symbols are resolved from ws2_32.dll at run-time, instead of
285
* by linking against ws2_32.lib, because they are not defined on all
286
* versions of Windows.
288
typedef int (__stdcall *gai_fn)(const char *, const char *,
289
const struct addrinfo *, struct addrinfo **);
290
typedef void (__stdcall *fai_fn)(struct addrinfo*);
291
typedef int (__stdcall *gni_fn)(const struct sockaddr *, socklen_t, char *,
292
size_t, char *, size_t, int);
294
/* Resolve a symbol in ws2_32.dll. */
296
get_ws2_32(const char *symbol)
298
static HMODULE ws2_32_handle = NULL;
301
if (ws2_32_handle == NULL) {
302
ws2_32_handle = LoadLibrary("ws2_32.dll");
303
if (ws2_32_handle == NULL) {
304
fprintf(stderr, "Can't load ws2_32.dll: %s\n",
305
win32_strerror(GetLastError()));
309
p = GetProcAddress(ws2_32_handle, symbol);
311
fprintf(stderr, "Can't resolve %s in ws2_32.dll: %s\n",
312
symbol, win32_strerror(GetLastError()));
319
win32_getaddrinfo(const char *node, const char *service,
320
const struct addrinfo *hints, struct addrinfo **res)
322
static FARPROC gai_p = NULL;
325
gai_p = get_ws2_32("getaddrinfo");
326
return ((gai_fn)gai_p)(node, service, hints, res);
330
win32_freeaddrinfo(struct addrinfo *res)
332
static FARPROC fai_p = NULL;
335
fai_p = get_ws2_32("freeaddrinfo");
336
((fai_fn)fai_p)(res);
340
win32_getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host,
341
size_t hostlen, char *serv, size_t servlen, int flags)
343
static FARPROC gni_p = NULL;
346
gni_p = get_ws2_32("getnameinfo");
347
return ((gni_fn)gni_p)(sa, salen, host, hostlen, serv, servlen, flags);