typedef rettype (WINAPI *t_##name) params; \
linkage t_##name p_##name
#define GET_WINSOCK_FUNCTION(module, name) \
- p_##name = (t_##name) GetProcAddress(module, #name)
+ p_##name = module ? (t_##name) GetProcAddress(module, #name) : NULL
DECL_WINSOCK_FUNCTION(NOTHING, int, WSAAsyncSelect,
(SOCKET, HWND, u_int, long));
(const struct sockaddr FAR * sa, socklen_t salen,
char FAR * host, size_t hostlen, char FAR * serv,
size_t servlen, int flags));
+DECL_WINSOCK_FUNCTION(static, char *, gai_strerror, (int ecode));
+DECL_WINSOCK_FUNCTION(static, int, WSAAddressToStringA,
+ (LPSOCKADDR, DWORD, LPWSAPROTOCOL_INFO,
+ LPTSTR, LPDWORD));
#endif
-static HMODULE winsock_module;
+static HMODULE winsock_module = NULL;
+static WSADATA wsadata;
#ifndef NO_IPV6
-static HMODULE wship6_module;
+static HMODULE winsock2_module = NULL;
+static HMODULE wship6_module = NULL;
#endif
-void sk_init(void)
+int sk_startup(int hi, int lo)
{
WORD winsock_ver;
- WSADATA wsadata;
- winsock_ver = MAKEWORD(2, 0);
- winsock_module = LoadLibrary("WS2_32.DLL");
+ winsock_ver = MAKEWORD(hi, lo);
+
+ if (p_WSAStartup(winsock_ver, &wsadata)) {
+ return FALSE;
+ }
+
+ if (LOBYTE(wsadata.wVersion) != LOBYTE(winsock_ver)) {
+ return FALSE;
+ }
+
+#ifdef NET_SETUP_DIAGNOSTICS
+ {
+ char buf[80];
+ sprintf(buf, "Using WinSock %d.%d", hi, lo);
+ logevent(NULL, buf);
+ }
+#endif
+ return TRUE;
+}
+
+void sk_init(void)
+{
+#ifndef NO_IPV6
+ winsock2_module =
+#endif
+ winsock_module = LoadLibrary("WS2_32.DLL");
if (!winsock_module) {
winsock_module = LoadLibrary("WSOCK32.DLL");
- winsock_ver = MAKEWORD(1, 1);
}
if (!winsock_module)
fatalbox("Unable to load any WinSock library");
#ifndef NO_IPV6
- wship6_module = LoadLibrary("wship6.dll");
- if (wship6_module) {
- GET_WINSOCK_FUNCTION(wship6_module, getaddrinfo);
- GET_WINSOCK_FUNCTION(wship6_module, freeaddrinfo);
- GET_WINSOCK_FUNCTION(wship6_module, getnameinfo);
+ /* Check if we have getaddrinfo in Winsock */
+ if (GetProcAddress(winsock_module, "getaddrinfo") != NULL) {
+#ifdef NET_SETUP_DIAGNOSTICS
+ logevent(NULL, "Native WinSock IPv6 support detected");
+#endif
+ GET_WINSOCK_FUNCTION(winsock_module, getaddrinfo);
+ GET_WINSOCK_FUNCTION(winsock_module, freeaddrinfo);
+ GET_WINSOCK_FUNCTION(winsock_module, getnameinfo);
+ GET_WINSOCK_FUNCTION(winsock_module, gai_strerror);
+ } else {
+ /* Fall back to wship6.dll for Windows 2000 */
+ wship6_module = LoadLibrary("wship6.dll");
+ if (wship6_module) {
+#ifdef NET_SETUP_DIAGNOSTICS
+ logevent(NULL, "WSH IPv6 support detected");
+#endif
+ GET_WINSOCK_FUNCTION(wship6_module, getaddrinfo);
+ GET_WINSOCK_FUNCTION(wship6_module, freeaddrinfo);
+ GET_WINSOCK_FUNCTION(wship6_module, getnameinfo);
+ GET_WINSOCK_FUNCTION(wship6_module, gai_strerror);
+ } else {
+#ifdef NET_SETUP_DIAGNOSTICS
+ logevent(NULL, "No IPv6 support detected");
+#endif
+ }
}
+ GET_WINSOCK_FUNCTION(winsock2_module, WSAAddressToStringA);
+#else
+#ifdef NET_SETUP_DIAGNOSTICS
+ logevent(NULL, "PuTTY was built without IPv6 support");
+#endif
#endif
GET_WINSOCK_FUNCTION(winsock_module, WSAAsyncSelect);
GET_WINSOCK_FUNCTION(winsock_module, recv);
GET_WINSOCK_FUNCTION(winsock_module, WSAIoctl);
- if (p_WSAStartup(winsock_ver, &wsadata)) {
+ /* Try to get the best WinSock version we can get */
+ if (!sk_startup(2,2) &&
+ !sk_startup(2,0) &&
+ !sk_startup(1,1)) {
fatalbox("Unable to initialise WinSock");
}
- if (LOBYTE(wsadata.wVersion) != LOBYTE(winsock_ver)) {
- p_WSACleanup();
- fatalbox("WinSock version is incompatible with %d.%d",
- LOBYTE(winsock_ver), HIBYTE(winsock_ver));
- }
sktree = newtree234(cmpfortree);
}
p_WSACleanup();
if (winsock_module)
FreeLibrary(winsock_module);
+#ifndef NO_IPV6
if (wship6_module)
FreeLibrary(wship6_module);
+#endif
}
char *winsock_error_string(int error)
address_family == ADDRTYPE_IPV6 ? AF_INET6 :
#endif
AF_UNSPEC);
+#ifndef NO_IPV6
+ ret->ai = ret->ais = NULL;
+#endif
+ ret->addresses = NULL;
ret_family = AF_UNSPEC;
*realhost = '\0';
*/
if (p_getaddrinfo) {
struct addrinfo hints;
+#ifdef NET_SETUP_DIAGNOSTICS
+ logevent(NULL, "Using getaddrinfo() for resolving");
+#endif
memset(&hints, 0, sizeof(hints));
hints.ai_family = ret->family;
+ hints.ai_flags = AI_CANONNAME;
if ((err = p_getaddrinfo(host, NULL, &hints, &ret->ais)) == 0)
ret_family = ret->ais->ai_family;
ret->ai = ret->ais;
} else
#endif
{
+#ifdef NET_SETUP_DIAGNOSTICS
+ logevent(NULL, "Using gethostbyname() for resolving");
+#endif
/*
* Otherwise use the IPv4-only gethostbyname...
* (NOTE: we don't use gethostbyname as a fallback!)
err == WSAHOST_NOT_FOUND ? "Host does not exist" :
err == WSATRY_AGAIN ? "Host not found" :
#ifndef NO_IPV6
- p_getaddrinfo ? "getaddrinfo: unknown error" :
+ p_getaddrinfo&&p_gai_strerror ? p_gai_strerror(err) :
#endif
"gethostbyname: unknown error");
} else {
(char *) &((SOCKADDR_IN *) ret->ai->
ai_addr)->sin_addr, sizeof(a));
- /* Now let's find that canonicalname... */
- if (p_getnameinfo) {
- if (p_getnameinfo
- ((struct sockaddr *) ret->ai->ai_addr,
- ret->family ==
- AF_INET ? sizeof(SOCKADDR_IN) :
- sizeof(SOCKADDR_IN6), realhost,
- sizeof(realhost), NULL, 0, 0) != 0) {
- strncpy(realhost, host, sizeof(realhost));
- }
- }
+ if (ret->ai->ai_canonname)
+ strncpy(realhost, ret->ai->ai_canonname, lenof(realhost));
+ else
+ strncpy(realhost, host, lenof(realhost));
}
/* We used the IPv4-only gethostbyname()... */
else
SockAddr ret = snew(struct SockAddr_tag);
ret->error = NULL;
ret->family = AF_UNSPEC;
+#ifndef NO_IPV6
+ ret->ai = ret->ais = NULL;
+#endif
+ ret->addresses = NULL;
+ ret->naddresses = 0;
strncpy(ret->hostname, host, lenof(ret->hostname));
ret->hostname[lenof(ret->hostname)-1] = '\0';
return ret;
{
#ifndef NO_IPV6
if (addr->ai) {
- /* Try to get the WSAAddressToStringA() function from wship6.dll */
- /* This way one doesn't need to have IPv6 dll's to use PuTTY and
- * it will fallback to IPv4. */
- typedef int (CALLBACK * FADDRTOSTR) (LPSOCKADDR lpsaAddress,
- DWORD dwAddressLength,
- LPWSAPROTOCOL_INFO lpProtocolInfo,
- OUT LPTSTR lpszAddressString,
- IN OUT LPDWORD lpdwAddressStringLength
- );
- FADDRTOSTR fAddrToStr = NULL;
-
- HINSTANCE dllWS2 = LoadLibrary("ws2_32.dll");
- if (dllWS2) {
- fAddrToStr = (FADDRTOSTR)GetProcAddress(dllWS2,
- "WSAAddressToStringA");
- if (fAddrToStr) {
- fAddrToStr(addr->ai->ai_addr, addr->ai->ai_addrlen,
- NULL, buf, &buflen);
- }
- else strncpy(buf, "IPv6", buflen);
- FreeLibrary(dllWS2);
- }
+ if (p_WSAAddressToStringA) {
+ p_WSAAddressToStringA(addr->ai->ai_addr, addr->ai->ai_addrlen,
+ NULL, buf, &buflen);
+ } else
+ strncpy(buf, "IPv6", buflen);
} else
#endif
if (addr->family == AF_INET) {
} else
#endif
if (addr->family == AF_INET) {
- struct in_addr a;
- assert(addr->addresses && addr->curraddr < addr->naddresses);
- a.s_addr = p_htonl(addr->addresses[addr->curraddr]);
- return ipv4_is_local_addr(a);
+#ifndef NO_IPV6
+ if (addr->ai) {
+ return ipv4_is_local_addr(((struct sockaddr_in *)addr->ai->ai_addr)
+ ->sin_addr);
+ } else
+#endif
+ {
+ struct in_addr a;
+ assert(addr->addresses && addr->curraddr < addr->naddresses);
+ a.s_addr = p_htonl(addr->addresses[addr->curraddr]);
+ return ipv4_is_local_addr(a);
+ }
} else {
assert(addr->family == AF_UNSPEC);
return 0; /* we don't know; assume not */
a6.sin6_port = p_htons((short) sock->port);
a6.sin6_addr =
((struct sockaddr_in6 *) sock->addr->ai->ai_addr)->sin6_addr;
+ a6.sin6_flowinfo = ((struct sockaddr_in6 *) sock->addr->ai->ai_addr)->sin6_flowinfo;
+ a6.sin6_scope_id = ((struct sockaddr_in6 *) sock->addr->ai->ai_addr)->sin6_scope_id;
} else {
a.sin_family = AF_INET;
a.sin_addr =
#ifndef NO_IPV6
if (isa.ss_family == AF_INET &&
s->localhost_only &&
- !ipv4_is_local_addr(((struct sockaddr_in *)&isa)->sin_addr)) {
+ !ipv4_is_local_addr(((struct sockaddr_in *)&isa)->sin_addr))
#else
- if (s->localhost_only && !ipv4_is_local_addr(isa.sin_addr)) {
+ if (s->localhost_only && !ipv4_is_local_addr(isa.sin_addr))
#endif
+ {
p_closesocket(t); /* dodgy WinSock let nonlocal through */
} else if (plug_accepting(s->plug, (void*)t)) {
p_closesocket(t); /* denied or error */
if (s->frozen == is_frozen)
return;
s->frozen = is_frozen;
- if (!is_frozen && s->frozen_readable) {
- char c;
- p_recv(s->s, &c, 1, MSG_PEEK);
+ if (!is_frozen) {
+ do_select(s->s, 1);
+ if (s->frozen_readable) {
+ char c;
+ p_recv(s->s, &c, 1, MSG_PEEK);
+ }
}
s->frozen_readable = 0;
}
+void socket_reselect_all(void)
+{
+ Actual_Socket s;
+ int i;
+
+ for (i = 0; (s = index234(sktree, i)) != NULL; i++) {
+ if (!s->frozen)
+ do_select(s->s, 1);
+ }
+}
+
/*
* For Plink: enumerate all sockets currently active.
*/