2000-10-23 11:55:11 +00:00
|
|
|
/*
|
|
|
|
* Windows networking abstraction.
|
2001-01-07 19:16:16 +00:00
|
|
|
*
|
2004-12-30 16:45:11 +00:00
|
|
|
* For the IPv6 code in here I am indebted to Jeroen Massar and
|
|
|
|
* unfix.org.
|
2000-10-23 11:55:11 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
2000-10-24 10:47:49 +00:00
|
|
|
#include <stdlib.h>
|
2001-08-25 17:09:23 +00:00
|
|
|
#include <assert.h>
|
2000-10-23 11:55:11 +00:00
|
|
|
|
2001-03-13 10:22:45 +00:00
|
|
|
#define DEFINE_PLUG_METHOD_MACROS
|
2000-10-23 11:55:11 +00:00
|
|
|
#include "putty.h"
|
|
|
|
#include "network.h"
|
|
|
|
#include "tree234.h"
|
|
|
|
|
2003-10-12 13:46:12 +00:00
|
|
|
#include <ws2tcpip.h>
|
2004-12-30 16:45:11 +00:00
|
|
|
|
|
|
|
#ifndef NO_IPV6
|
|
|
|
const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
|
|
|
|
const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
|
2003-10-12 13:46:12 +00:00
|
|
|
#endif
|
|
|
|
|
2002-12-18 11:39:25 +00:00
|
|
|
#define ipv4_is_loopback(addr) \
|
2003-10-12 13:46:12 +00:00
|
|
|
((p_ntohl(addr.s_addr) & 0xFF000000L) == 0x7F000000L)
|
2002-12-18 11:39:25 +00:00
|
|
|
|
2005-01-08 14:45:26 +00:00
|
|
|
/*
|
|
|
|
* We used to typedef struct Socket_tag *Socket.
|
|
|
|
*
|
|
|
|
* Since we have made the networking abstraction slightly more
|
|
|
|
* abstract, Socket no longer means a tcp socket (it could mean
|
|
|
|
* an ssl socket). So now we must use Actual_Socket when we know
|
|
|
|
* we are talking about a tcp socket.
|
|
|
|
*/
|
|
|
|
typedef struct Socket_tag *Actual_Socket;
|
|
|
|
|
2008-11-08 16:45:45 +00:00
|
|
|
/*
|
|
|
|
* Mutable state that goes with a SockAddr: stores information
|
|
|
|
* about where in the list of candidate IP(v*) addresses we've
|
|
|
|
* currently got to.
|
|
|
|
*/
|
|
|
|
typedef struct SockAddrStep_tag SockAddrStep;
|
|
|
|
struct SockAddrStep_tag {
|
|
|
|
#ifndef NO_IPV6
|
|
|
|
struct addrinfo *ai; /* steps along addr->ais */
|
|
|
|
#endif
|
|
|
|
int curraddr;
|
|
|
|
};
|
|
|
|
|
2000-10-23 11:55:11 +00:00
|
|
|
struct Socket_tag {
|
2003-01-14 18:43:45 +00:00
|
|
|
const struct socket_function_table *fn;
|
2001-03-13 10:22:45 +00:00
|
|
|
/* the above variable absolutely *must* be the first in this structure */
|
2000-10-23 11:55:11 +00:00
|
|
|
char *error;
|
|
|
|
SOCKET s;
|
2001-03-13 10:22:45 +00:00
|
|
|
Plug plug;
|
2001-08-25 17:09:23 +00:00
|
|
|
bufchain output_data;
|
2001-09-07 22:39:01 +00:00
|
|
|
int connected;
|
2000-10-23 11:55:11 +00:00
|
|
|
int writable;
|
2001-08-25 17:09:23 +00:00
|
|
|
int frozen; /* this causes readability notifications to be ignored */
|
|
|
|
int frozen_readable; /* this means we missed at least one readability
|
|
|
|
* notification while we were frozen */
|
2001-10-12 19:32:13 +00:00
|
|
|
int localhost_only; /* for listening sockets */
|
2001-08-25 17:09:23 +00:00
|
|
|
char oobdata[1];
|
2001-01-29 14:49:21 +00:00
|
|
|
int sending_oob;
|
2005-01-16 14:29:34 +00:00
|
|
|
int oobinline, nodelay, keepalive, privport;
|
2011-09-13 11:44:03 +00:00
|
|
|
enum { EOF_NO, EOF_PENDING, EOF_SENT } outgoingeof;
|
2005-01-16 14:29:34 +00:00
|
|
|
SockAddr addr;
|
2008-11-08 16:45:45 +00:00
|
|
|
SockAddrStep step;
|
2005-01-16 14:29:34 +00:00
|
|
|
int port;
|
2001-10-28 09:57:47 +00:00
|
|
|
int pending_error; /* in case send() returns error */
|
2005-01-08 14:45:26 +00:00
|
|
|
/*
|
|
|
|
* We sometimes need pairs of Socket structures to be linked:
|
|
|
|
* if we are listening on the same IPv6 and v4 port, for
|
|
|
|
* example. So here we define `parent' and `child' pointers to
|
|
|
|
* track this link.
|
|
|
|
*/
|
|
|
|
Actual_Socket parent, child;
|
2000-10-23 11:55:11 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct SockAddr_tag {
|
2008-11-08 16:58:55 +00:00
|
|
|
int refcount;
|
2000-10-23 11:55:11 +00:00
|
|
|
char *error;
|
2008-11-08 16:45:45 +00:00
|
|
|
int resolved;
|
2013-11-17 14:05:41 +00:00
|
|
|
int namedpipe; /* indicates that this SockAddr is phony, holding a Windows
|
|
|
|
* named pipe pathname instead of a network address */
|
2004-12-30 16:45:11 +00:00
|
|
|
#ifndef NO_IPV6
|
2005-01-16 14:29:34 +00:00
|
|
|
struct addrinfo *ais; /* Addresses IPv6 style. */
|
2001-01-07 19:16:16 +00:00
|
|
|
#endif
|
2005-01-16 14:29:34 +00:00
|
|
|
unsigned long *addresses; /* Addresses IPv4 style. */
|
2008-11-08 16:45:45 +00:00
|
|
|
int naddresses;
|
2002-12-18 16:23:11 +00:00
|
|
|
char hostname[512]; /* Store an unresolved host name. */
|
2000-10-23 11:55:11 +00:00
|
|
|
};
|
|
|
|
|
2008-11-08 16:45:45 +00:00
|
|
|
/*
|
|
|
|
* Which address family this address belongs to. AF_INET for IPv4;
|
|
|
|
* AF_INET6 for IPv6; AF_UNSPEC indicates that name resolution has
|
|
|
|
* not been done and a simple host name is held in this SockAddr
|
|
|
|
* structure.
|
|
|
|
*/
|
|
|
|
#ifndef NO_IPV6
|
|
|
|
#define SOCKADDR_FAMILY(addr, step) \
|
|
|
|
(!(addr)->resolved ? AF_UNSPEC : \
|
|
|
|
(step).ai ? (step).ai->ai_family : AF_INET)
|
|
|
|
#else
|
|
|
|
#define SOCKADDR_FAMILY(addr, step) \
|
|
|
|
(!(addr)->resolved ? AF_UNSPEC : AF_INET)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Start a SockAddrStep structure to step through multiple
|
|
|
|
* addresses.
|
|
|
|
*/
|
|
|
|
#ifndef NO_IPV6
|
|
|
|
#define START_STEP(addr, step) \
|
|
|
|
((step).ai = (addr)->ais, (step).curraddr = 0)
|
|
|
|
#else
|
|
|
|
#define START_STEP(addr, step) \
|
|
|
|
((step).curraddr = 0)
|
|
|
|
#endif
|
|
|
|
|
2000-10-23 11:55:11 +00:00
|
|
|
static tree234 *sktree;
|
|
|
|
|
2001-05-06 14:35:20 +00:00
|
|
|
static int cmpfortree(void *av, void *bv)
|
|
|
|
{
|
|
|
|
Actual_Socket a = (Actual_Socket) av, b = (Actual_Socket) bv;
|
|
|
|
unsigned long as = (unsigned long) a->s, bs = (unsigned long) b->s;
|
|
|
|
if (as < bs)
|
|
|
|
return -1;
|
|
|
|
if (as > bs)
|
|
|
|
return +1;
|
2007-11-26 21:09:54 +00:00
|
|
|
if (a < b)
|
|
|
|
return -1;
|
|
|
|
if (a > b)
|
|
|
|
return +1;
|
2000-10-23 11:55:11 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2001-05-06 14:35:20 +00:00
|
|
|
static int cmpforsearch(void *av, void *bv)
|
|
|
|
{
|
|
|
|
Actual_Socket b = (Actual_Socket) bv;
|
|
|
|
unsigned long as = (unsigned long) av, bs = (unsigned long) b->s;
|
|
|
|
if (as < bs)
|
|
|
|
return -1;
|
|
|
|
if (as > bs)
|
|
|
|
return +1;
|
2000-10-23 11:55:11 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-11-08 18:47:41 +00:00
|
|
|
DECL_WINDOWS_FUNCTION(static, int, WSAStartup, (WORD, LPWSADATA));
|
|
|
|
DECL_WINDOWS_FUNCTION(static, int, WSACleanup, (void));
|
|
|
|
DECL_WINDOWS_FUNCTION(static, int, closesocket, (SOCKET));
|
|
|
|
DECL_WINDOWS_FUNCTION(static, u_long, ntohl, (u_long));
|
|
|
|
DECL_WINDOWS_FUNCTION(static, u_long, htonl, (u_long));
|
|
|
|
DECL_WINDOWS_FUNCTION(static, u_short, htons, (u_short));
|
|
|
|
DECL_WINDOWS_FUNCTION(static, u_short, ntohs, (u_short));
|
|
|
|
DECL_WINDOWS_FUNCTION(static, int, gethostname, (char *, int));
|
|
|
|
DECL_WINDOWS_FUNCTION(static, struct hostent FAR *, gethostbyname,
|
2003-10-12 13:46:12 +00:00
|
|
|
(const char FAR *));
|
2009-11-08 18:47:41 +00:00
|
|
|
DECL_WINDOWS_FUNCTION(static, struct servent FAR *, getservbyname,
|
2003-10-12 13:46:12 +00:00
|
|
|
(const char FAR *, const char FAR *));
|
2009-11-08 18:47:41 +00:00
|
|
|
DECL_WINDOWS_FUNCTION(static, unsigned long, inet_addr, (const char FAR *));
|
|
|
|
DECL_WINDOWS_FUNCTION(static, char FAR *, inet_ntoa, (struct in_addr));
|
|
|
|
DECL_WINDOWS_FUNCTION(static, int, connect,
|
2003-10-12 13:46:12 +00:00
|
|
|
(SOCKET, const struct sockaddr FAR *, int));
|
2009-11-08 18:47:41 +00:00
|
|
|
DECL_WINDOWS_FUNCTION(static, int, bind,
|
2003-10-12 13:46:12 +00:00
|
|
|
(SOCKET, const struct sockaddr FAR *, int));
|
2009-11-08 18:47:41 +00:00
|
|
|
DECL_WINDOWS_FUNCTION(static, int, setsockopt,
|
2003-10-12 13:46:12 +00:00
|
|
|
(SOCKET, int, int, const char FAR *, int));
|
2009-11-08 18:47:41 +00:00
|
|
|
DECL_WINDOWS_FUNCTION(static, SOCKET, socket, (int, int, int));
|
|
|
|
DECL_WINDOWS_FUNCTION(static, int, listen, (SOCKET, int));
|
|
|
|
DECL_WINDOWS_FUNCTION(static, int, send, (SOCKET, const char FAR *, int, int));
|
2011-09-13 11:44:03 +00:00
|
|
|
DECL_WINDOWS_FUNCTION(static, int, shutdown, (SOCKET, int));
|
2009-11-08 18:47:41 +00:00
|
|
|
DECL_WINDOWS_FUNCTION(static, int, ioctlsocket,
|
2003-10-12 13:46:12 +00:00
|
|
|
(SOCKET, long, u_long FAR *));
|
2009-11-08 18:47:41 +00:00
|
|
|
DECL_WINDOWS_FUNCTION(static, SOCKET, accept,
|
2003-10-12 13:46:12 +00:00
|
|
|
(SOCKET, struct sockaddr FAR *, int FAR *));
|
2009-11-08 18:47:41 +00:00
|
|
|
DECL_WINDOWS_FUNCTION(static, int, recv, (SOCKET, char FAR *, int, int));
|
|
|
|
DECL_WINDOWS_FUNCTION(static, int, WSAIoctl,
|
2003-10-12 14:12:54 +00:00
|
|
|
(SOCKET, DWORD, LPVOID, DWORD, LPVOID, DWORD,
|
|
|
|
LPDWORD, LPWSAOVERLAPPED,
|
|
|
|
LPWSAOVERLAPPED_COMPLETION_ROUTINE));
|
2005-01-16 14:29:34 +00:00
|
|
|
#ifndef NO_IPV6
|
2009-11-08 18:47:41 +00:00
|
|
|
DECL_WINDOWS_FUNCTION(static, int, getaddrinfo,
|
2005-01-16 14:29:34 +00:00
|
|
|
(const char *nodename, const char *servname,
|
|
|
|
const struct addrinfo *hints, struct addrinfo **res));
|
2009-11-08 18:47:41 +00:00
|
|
|
DECL_WINDOWS_FUNCTION(static, void, freeaddrinfo, (struct addrinfo *res));
|
|
|
|
DECL_WINDOWS_FUNCTION(static, int, getnameinfo,
|
2005-01-16 14:29:34 +00:00
|
|
|
(const struct sockaddr FAR * sa, socklen_t salen,
|
|
|
|
char FAR * host, size_t hostlen, char FAR * serv,
|
|
|
|
size_t servlen, int flags));
|
2009-11-08 18:47:41 +00:00
|
|
|
DECL_WINDOWS_FUNCTION(static, char *, gai_strerror, (int ecode));
|
|
|
|
DECL_WINDOWS_FUNCTION(static, int, WSAAddressToStringA,
|
2006-12-23 09:04:27 +00:00
|
|
|
(LPSOCKADDR, DWORD, LPWSAPROTOCOL_INFO,
|
2009-08-21 22:29:58 +00:00
|
|
|
LPSTR, LPDWORD));
|
2005-01-16 14:29:34 +00:00
|
|
|
#endif
|
2003-10-12 13:46:12 +00:00
|
|
|
|
2006-12-23 09:04:27 +00:00
|
|
|
static HMODULE winsock_module = NULL;
|
|
|
|
static WSADATA wsadata;
|
2005-01-16 14:29:34 +00:00
|
|
|
#ifndef NO_IPV6
|
2006-12-23 09:04:27 +00:00
|
|
|
static HMODULE winsock2_module = NULL;
|
|
|
|
static HMODULE wship6_module = NULL;
|
2005-01-16 14:29:34 +00:00
|
|
|
#endif
|
2003-10-12 13:46:12 +00:00
|
|
|
|
2006-12-23 09:04:27 +00:00
|
|
|
int sk_startup(int hi, int lo)
|
2001-05-06 14:35:20 +00:00
|
|
|
{
|
2003-10-12 13:46:12 +00:00
|
|
|
WORD winsock_ver;
|
|
|
|
|
2006-12-23 09:04:27 +00:00
|
|
|
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)
|
|
|
|
{
|
2007-01-05 18:43:58 +00:00
|
|
|
#ifndef NO_IPV6
|
|
|
|
winsock2_module =
|
|
|
|
#endif
|
2010-09-13 08:29:45 +00:00
|
|
|
winsock_module = load_system32_dll("ws2_32.dll");
|
2003-10-12 13:46:12 +00:00
|
|
|
if (!winsock_module) {
|
2010-09-13 08:29:45 +00:00
|
|
|
winsock_module = load_system32_dll("wsock32.dll");
|
2003-10-12 13:46:12 +00:00
|
|
|
}
|
|
|
|
if (!winsock_module)
|
|
|
|
fatalbox("Unable to load any WinSock library");
|
|
|
|
|
2005-01-16 14:29:34 +00:00
|
|
|
#ifndef NO_IPV6
|
2006-12-23 09:04:27 +00:00
|
|
|
/* 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
|
2009-11-08 18:47:41 +00:00
|
|
|
GET_WINDOWS_FUNCTION(winsock_module, getaddrinfo);
|
|
|
|
GET_WINDOWS_FUNCTION(winsock_module, freeaddrinfo);
|
|
|
|
GET_WINDOWS_FUNCTION(winsock_module, getnameinfo);
|
|
|
|
GET_WINDOWS_FUNCTION(winsock_module, gai_strerror);
|
2006-12-23 09:04:27 +00:00
|
|
|
} else {
|
|
|
|
/* Fall back to wship6.dll for Windows 2000 */
|
2010-09-13 08:29:45 +00:00
|
|
|
wship6_module = load_system32_dll("wship6.dll");
|
2006-12-23 09:04:27 +00:00
|
|
|
if (wship6_module) {
|
|
|
|
#ifdef NET_SETUP_DIAGNOSTICS
|
|
|
|
logevent(NULL, "WSH IPv6 support detected");
|
|
|
|
#endif
|
2009-11-08 18:47:41 +00:00
|
|
|
GET_WINDOWS_FUNCTION(wship6_module, getaddrinfo);
|
|
|
|
GET_WINDOWS_FUNCTION(wship6_module, freeaddrinfo);
|
|
|
|
GET_WINDOWS_FUNCTION(wship6_module, getnameinfo);
|
|
|
|
GET_WINDOWS_FUNCTION(wship6_module, gai_strerror);
|
2006-12-23 09:04:27 +00:00
|
|
|
} else {
|
|
|
|
#ifdef NET_SETUP_DIAGNOSTICS
|
|
|
|
logevent(NULL, "No IPv6 support detected");
|
|
|
|
#endif
|
|
|
|
}
|
2005-01-16 14:29:34 +00:00
|
|
|
}
|
2009-11-08 18:47:41 +00:00
|
|
|
GET_WINDOWS_FUNCTION(winsock2_module, WSAAddressToStringA);
|
2006-12-23 09:04:27 +00:00
|
|
|
#else
|
|
|
|
#ifdef NET_SETUP_DIAGNOSTICS
|
|
|
|
logevent(NULL, "PuTTY was built without IPv6 support");
|
|
|
|
#endif
|
2005-01-16 14:29:34 +00:00
|
|
|
#endif
|
|
|
|
|
2009-11-08 18:47:41 +00:00
|
|
|
GET_WINDOWS_FUNCTION(winsock_module, WSAAsyncSelect);
|
|
|
|
GET_WINDOWS_FUNCTION(winsock_module, WSAEventSelect);
|
|
|
|
GET_WINDOWS_FUNCTION(winsock_module, select);
|
|
|
|
GET_WINDOWS_FUNCTION(winsock_module, WSAGetLastError);
|
|
|
|
GET_WINDOWS_FUNCTION(winsock_module, WSAEnumNetworkEvents);
|
|
|
|
GET_WINDOWS_FUNCTION(winsock_module, WSAStartup);
|
|
|
|
GET_WINDOWS_FUNCTION(winsock_module, WSACleanup);
|
|
|
|
GET_WINDOWS_FUNCTION(winsock_module, closesocket);
|
|
|
|
GET_WINDOWS_FUNCTION(winsock_module, ntohl);
|
|
|
|
GET_WINDOWS_FUNCTION(winsock_module, htonl);
|
|
|
|
GET_WINDOWS_FUNCTION(winsock_module, htons);
|
|
|
|
GET_WINDOWS_FUNCTION(winsock_module, ntohs);
|
|
|
|
GET_WINDOWS_FUNCTION(winsock_module, gethostname);
|
|
|
|
GET_WINDOWS_FUNCTION(winsock_module, gethostbyname);
|
|
|
|
GET_WINDOWS_FUNCTION(winsock_module, getservbyname);
|
|
|
|
GET_WINDOWS_FUNCTION(winsock_module, inet_addr);
|
|
|
|
GET_WINDOWS_FUNCTION(winsock_module, inet_ntoa);
|
|
|
|
GET_WINDOWS_FUNCTION(winsock_module, connect);
|
|
|
|
GET_WINDOWS_FUNCTION(winsock_module, bind);
|
|
|
|
GET_WINDOWS_FUNCTION(winsock_module, setsockopt);
|
|
|
|
GET_WINDOWS_FUNCTION(winsock_module, socket);
|
|
|
|
GET_WINDOWS_FUNCTION(winsock_module, listen);
|
|
|
|
GET_WINDOWS_FUNCTION(winsock_module, send);
|
2011-09-13 11:44:03 +00:00
|
|
|
GET_WINDOWS_FUNCTION(winsock_module, shutdown);
|
2009-11-08 18:47:41 +00:00
|
|
|
GET_WINDOWS_FUNCTION(winsock_module, ioctlsocket);
|
|
|
|
GET_WINDOWS_FUNCTION(winsock_module, accept);
|
|
|
|
GET_WINDOWS_FUNCTION(winsock_module, recv);
|
|
|
|
GET_WINDOWS_FUNCTION(winsock_module, WSAIoctl);
|
2003-10-12 13:46:12 +00:00
|
|
|
|
2006-12-23 09:04:27 +00:00
|
|
|
/* Try to get the best WinSock version we can get */
|
|
|
|
if (!sk_startup(2,2) &&
|
|
|
|
!sk_startup(2,0) &&
|
|
|
|
!sk_startup(1,1)) {
|
2003-10-12 13:46:12 +00:00
|
|
|
fatalbox("Unable to initialise WinSock");
|
|
|
|
}
|
|
|
|
|
2000-10-23 11:55:11 +00:00
|
|
|
sktree = newtree234(cmpfortree);
|
|
|
|
}
|
|
|
|
|
2002-03-06 20:13:22 +00:00
|
|
|
void sk_cleanup(void)
|
|
|
|
{
|
|
|
|
Actual_Socket s;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (sktree) {
|
|
|
|
for (i = 0; (s = index234(sktree, i)) != NULL; i++) {
|
2003-10-12 13:46:12 +00:00
|
|
|
p_closesocket(s->s);
|
2002-03-06 20:13:22 +00:00
|
|
|
}
|
2003-12-19 12:44:46 +00:00
|
|
|
freetree234(sktree);
|
|
|
|
sktree = NULL;
|
2002-03-06 20:13:22 +00:00
|
|
|
}
|
2003-10-12 13:46:12 +00:00
|
|
|
|
2009-08-21 20:05:24 +00:00
|
|
|
if (p_WSACleanup)
|
|
|
|
p_WSACleanup();
|
2003-10-12 13:46:12 +00:00
|
|
|
if (winsock_module)
|
|
|
|
FreeLibrary(winsock_module);
|
2005-02-07 12:23:10 +00:00
|
|
|
#ifndef NO_IPV6
|
2005-01-16 14:29:34 +00:00
|
|
|
if (wship6_module)
|
|
|
|
FreeLibrary(wship6_module);
|
2005-02-07 12:23:10 +00:00
|
|
|
#endif
|
2002-03-06 20:13:22 +00:00
|
|
|
}
|
|
|
|
|
2012-11-13 18:36:27 +00:00
|
|
|
struct errstring {
|
|
|
|
int error;
|
|
|
|
char *text;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int errstring_find(void *av, void *bv)
|
|
|
|
{
|
|
|
|
int *a = (int *)av;
|
|
|
|
struct errstring *b = (struct errstring *)bv;
|
|
|
|
if (*a < b->error)
|
|
|
|
return -1;
|
|
|
|
if (*a > b->error)
|
|
|
|
return +1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
static int errstring_compare(void *av, void *bv)
|
|
|
|
{
|
|
|
|
struct errstring *a = (struct errstring *)av;
|
|
|
|
return errstring_find(&a->error, bv);
|
|
|
|
}
|
|
|
|
|
|
|
|
static tree234 *errstrings = NULL;
|
|
|
|
|
2001-05-06 14:35:20 +00:00
|
|
|
char *winsock_error_string(int error)
|
|
|
|
{
|
2012-11-13 18:36:27 +00:00
|
|
|
const char prefix[] = "Network error: ";
|
|
|
|
struct errstring *es;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Error codes we know about and have historically had reasonably
|
|
|
|
* sensible error messages for.
|
|
|
|
*/
|
2000-12-18 09:20:26 +00:00
|
|
|
switch (error) {
|
2001-05-06 14:35:20 +00:00
|
|
|
case WSAEACCES:
|
|
|
|
return "Network error: Permission denied";
|
|
|
|
case WSAEADDRINUSE:
|
|
|
|
return "Network error: Address already in use";
|
|
|
|
case WSAEADDRNOTAVAIL:
|
|
|
|
return "Network error: Cannot assign requested address";
|
|
|
|
case WSAEAFNOSUPPORT:
|
|
|
|
return
|
|
|
|
"Network error: Address family not supported by protocol family";
|
|
|
|
case WSAEALREADY:
|
|
|
|
return "Network error: Operation already in progress";
|
|
|
|
case WSAECONNABORTED:
|
|
|
|
return "Network error: Software caused connection abort";
|
|
|
|
case WSAECONNREFUSED:
|
|
|
|
return "Network error: Connection refused";
|
|
|
|
case WSAECONNRESET:
|
|
|
|
return "Network error: Connection reset by peer";
|
|
|
|
case WSAEDESTADDRREQ:
|
|
|
|
return "Network error: Destination address required";
|
|
|
|
case WSAEFAULT:
|
|
|
|
return "Network error: Bad address";
|
|
|
|
case WSAEHOSTDOWN:
|
|
|
|
return "Network error: Host is down";
|
|
|
|
case WSAEHOSTUNREACH:
|
|
|
|
return "Network error: No route to host";
|
|
|
|
case WSAEINPROGRESS:
|
|
|
|
return "Network error: Operation now in progress";
|
|
|
|
case WSAEINTR:
|
|
|
|
return "Network error: Interrupted function call";
|
|
|
|
case WSAEINVAL:
|
|
|
|
return "Network error: Invalid argument";
|
|
|
|
case WSAEISCONN:
|
|
|
|
return "Network error: Socket is already connected";
|
|
|
|
case WSAEMFILE:
|
|
|
|
return "Network error: Too many open files";
|
|
|
|
case WSAEMSGSIZE:
|
|
|
|
return "Network error: Message too long";
|
|
|
|
case WSAENETDOWN:
|
|
|
|
return "Network error: Network is down";
|
|
|
|
case WSAENETRESET:
|
|
|
|
return "Network error: Network dropped connection on reset";
|
|
|
|
case WSAENETUNREACH:
|
|
|
|
return "Network error: Network is unreachable";
|
|
|
|
case WSAENOBUFS:
|
|
|
|
return "Network error: No buffer space available";
|
|
|
|
case WSAENOPROTOOPT:
|
|
|
|
return "Network error: Bad protocol option";
|
|
|
|
case WSAENOTCONN:
|
|
|
|
return "Network error: Socket is not connected";
|
|
|
|
case WSAENOTSOCK:
|
|
|
|
return "Network error: Socket operation on non-socket";
|
|
|
|
case WSAEOPNOTSUPP:
|
|
|
|
return "Network error: Operation not supported";
|
|
|
|
case WSAEPFNOSUPPORT:
|
|
|
|
return "Network error: Protocol family not supported";
|
|
|
|
case WSAEPROCLIM:
|
|
|
|
return "Network error: Too many processes";
|
|
|
|
case WSAEPROTONOSUPPORT:
|
|
|
|
return "Network error: Protocol not supported";
|
|
|
|
case WSAEPROTOTYPE:
|
|
|
|
return "Network error: Protocol wrong type for socket";
|
|
|
|
case WSAESHUTDOWN:
|
|
|
|
return "Network error: Cannot send after socket shutdown";
|
|
|
|
case WSAESOCKTNOSUPPORT:
|
|
|
|
return "Network error: Socket type not supported";
|
|
|
|
case WSAETIMEDOUT:
|
|
|
|
return "Network error: Connection timed out";
|
|
|
|
case WSAEWOULDBLOCK:
|
|
|
|
return "Network error: Resource temporarily unavailable";
|
|
|
|
case WSAEDISCON:
|
|
|
|
return "Network error: Graceful shutdown in progress";
|
2000-12-18 09:20:26 +00:00
|
|
|
}
|
2012-11-13 18:36:27 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Generic code to handle any other error.
|
|
|
|
*
|
|
|
|
* Slightly nasty hack here: we want to return a static string
|
|
|
|
* which the caller will never have to worry about freeing, but on
|
|
|
|
* the other hand if we call FormatMessage to get it then it will
|
|
|
|
* want to either allocate a buffer or write into one we own.
|
|
|
|
*
|
|
|
|
* So what we do is to maintain a tree234 of error strings we've
|
|
|
|
* already used. New ones are allocated from the heap, but then
|
|
|
|
* put in this tree and kept forever.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (!errstrings)
|
|
|
|
errstrings = newtree234(errstring_compare);
|
|
|
|
|
|
|
|
es = find234(errstrings, &error, errstring_find);
|
|
|
|
|
|
|
|
if (!es) {
|
|
|
|
int bufsize, bufused;
|
|
|
|
|
|
|
|
es = snew(struct errstring);
|
|
|
|
es->error = error;
|
|
|
|
/* maximum size for FormatMessage is 64K */
|
|
|
|
bufsize = 65535 + sizeof(prefix);
|
|
|
|
es->text = snewn(bufsize, char);
|
|
|
|
strcpy(es->text, prefix);
|
|
|
|
bufused = strlen(es->text);
|
|
|
|
if (!FormatMessage((FORMAT_MESSAGE_FROM_SYSTEM |
|
|
|
|
FORMAT_MESSAGE_IGNORE_INSERTS), NULL, error,
|
|
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
|
|
es->text + bufused, bufsize - bufused, NULL)) {
|
|
|
|
sprintf(es->text + bufused,
|
|
|
|
"Windows error code %d (and FormatMessage returned %d)",
|
|
|
|
error, GetLastError());
|
|
|
|
} else {
|
|
|
|
int len = strlen(es->text);
|
|
|
|
if (len > 0 && es->text[len-1] == '\n')
|
|
|
|
es->text[len-1] = '\0';
|
|
|
|
}
|
|
|
|
es->text = sresize(es->text, strlen(es->text) + 1, char);
|
|
|
|
add234(errstrings, es);
|
|
|
|
}
|
|
|
|
|
|
|
|
return es->text;
|
2000-12-18 09:20:26 +00:00
|
|
|
}
|
|
|
|
|
2004-12-30 16:45:11 +00:00
|
|
|
SockAddr sk_namelookup(const char *host, char **canonicalname,
|
|
|
|
int address_family)
|
2001-01-07 19:16:16 +00:00
|
|
|
{
|
2003-03-29 16:14:26 +00:00
|
|
|
SockAddr ret = snew(struct SockAddr_tag);
|
2000-10-23 11:55:11 +00:00
|
|
|
unsigned long a;
|
2001-05-09 14:01:15 +00:00
|
|
|
char realhost[8192];
|
2008-11-08 16:45:45 +00:00
|
|
|
int hint_family;
|
2000-10-23 11:55:11 +00:00
|
|
|
|
2008-11-08 16:45:45 +00:00
|
|
|
/* Default to IPv4. */
|
|
|
|
hint_family = (address_family == ADDRTYPE_IPV4 ? AF_INET :
|
2004-12-30 16:45:11 +00:00
|
|
|
#ifndef NO_IPV6
|
|
|
|
address_family == ADDRTYPE_IPV6 ? AF_INET6 :
|
|
|
|
#endif
|
|
|
|
AF_UNSPEC);
|
2008-11-08 16:45:45 +00:00
|
|
|
|
|
|
|
/* Clear the structure and default to IPv4. */
|
|
|
|
memset(ret, 0, sizeof(struct SockAddr_tag));
|
2005-02-14 11:43:27 +00:00
|
|
|
#ifndef NO_IPV6
|
2008-11-08 16:45:45 +00:00
|
|
|
ret->ais = NULL;
|
2005-02-14 11:43:27 +00:00
|
|
|
#endif
|
2013-11-17 14:05:41 +00:00
|
|
|
ret->namedpipe = FALSE;
|
2006-08-26 08:37:42 +00:00
|
|
|
ret->addresses = NULL;
|
2008-11-08 16:45:45 +00:00
|
|
|
ret->resolved = FALSE;
|
2008-11-08 16:58:55 +00:00
|
|
|
ret->refcount = 1;
|
2001-05-09 14:01:15 +00:00
|
|
|
*realhost = '\0';
|
2001-01-07 19:16:16 +00:00
|
|
|
|
2003-10-12 13:46:12 +00:00
|
|
|
if ((a = p_inet_addr(host)) == (unsigned long) INADDR_NONE) {
|
2009-09-27 16:07:10 +00:00
|
|
|
struct hostent *h = NULL;
|
|
|
|
int err;
|
2004-12-30 16:45:11 +00:00
|
|
|
#ifndef NO_IPV6
|
2001-01-07 19:16:16 +00:00
|
|
|
/*
|
2005-01-16 14:29:34 +00:00
|
|
|
* Use getaddrinfo when it's available
|
2001-01-07 19:16:16 +00:00
|
|
|
*/
|
2005-01-16 14:29:34 +00:00
|
|
|
if (p_getaddrinfo) {
|
2005-01-08 14:02:06 +00:00
|
|
|
struct addrinfo hints;
|
2006-12-23 09:04:27 +00:00
|
|
|
#ifdef NET_SETUP_DIAGNOSTICS
|
|
|
|
logevent(NULL, "Using getaddrinfo() for resolving");
|
|
|
|
#endif
|
2005-01-08 14:02:06 +00:00
|
|
|
memset(&hints, 0, sizeof(hints));
|
2008-11-08 16:45:45 +00:00
|
|
|
hints.ai_family = hint_family;
|
2005-04-07 22:33:42 +00:00
|
|
|
hints.ai_flags = AI_CANONNAME;
|
2014-01-25 15:58:54 +00:00
|
|
|
{
|
|
|
|
/* strip [] on IPv6 address literals */
|
|
|
|
char *trimmed_host = host_strduptrim(host);
|
|
|
|
err = p_getaddrinfo(trimmed_host, NULL, &hints, &ret->ais);
|
|
|
|
sfree(trimmed_host);
|
|
|
|
}
|
|
|
|
if (err == 0)
|
2008-11-08 16:45:45 +00:00
|
|
|
ret->resolved = TRUE;
|
2001-05-06 14:35:20 +00:00
|
|
|
} else
|
2001-01-07 19:16:16 +00:00
|
|
|
#endif
|
2001-05-06 14:35:20 +00:00
|
|
|
{
|
2006-12-23 09:04:27 +00:00
|
|
|
#ifdef NET_SETUP_DIAGNOSTICS
|
|
|
|
logevent(NULL, "Using gethostbyname() for resolving");
|
|
|
|
#endif
|
2001-01-07 19:16:16 +00:00
|
|
|
/*
|
|
|
|
* Otherwise use the IPv4-only gethostbyname...
|
2004-12-30 16:45:11 +00:00
|
|
|
* (NOTE: we don't use gethostbyname as a fallback!)
|
2001-01-07 19:16:16 +00:00
|
|
|
*/
|
2005-01-08 14:02:06 +00:00
|
|
|
if ( (h = p_gethostbyname(host)) )
|
2008-11-08 16:45:45 +00:00
|
|
|
ret->resolved = TRUE;
|
2005-01-08 14:02:06 +00:00
|
|
|
else
|
|
|
|
err = p_WSAGetLastError();
|
2001-01-07 19:16:16 +00:00
|
|
|
}
|
|
|
|
|
2008-11-08 16:45:45 +00:00
|
|
|
if (!ret->resolved) {
|
2001-01-07 19:16:16 +00:00
|
|
|
ret->error = (err == WSAENETDOWN ? "Network is down" :
|
2005-01-08 14:02:06 +00:00
|
|
|
err == WSAHOST_NOT_FOUND ? "Host does not exist" :
|
|
|
|
err == WSATRY_AGAIN ? "Host not found" :
|
2004-12-30 16:45:11 +00:00
|
|
|
#ifndef NO_IPV6
|
2006-12-23 09:04:27 +00:00
|
|
|
p_getaddrinfo&&p_gai_strerror ? p_gai_strerror(err) :
|
2001-01-07 19:16:16 +00:00
|
|
|
#endif
|
|
|
|
"gethostbyname: unknown error");
|
2001-05-06 14:35:20 +00:00
|
|
|
} else {
|
2001-01-07 19:16:16 +00:00
|
|
|
ret->error = NULL;
|
|
|
|
|
2004-12-30 16:45:11 +00:00
|
|
|
#ifndef NO_IPV6
|
2001-01-07 19:16:16 +00:00
|
|
|
/* If we got an address info use that... */
|
2008-11-08 16:45:45 +00:00
|
|
|
if (ret->ais) {
|
2001-01-07 19:16:16 +00:00
|
|
|
/* Are we in IPv4 fallback mode? */
|
|
|
|
/* We put the IPv4 address into the a variable so we can further-on use the IPv4 code... */
|
2008-11-08 16:45:45 +00:00
|
|
|
if (ret->ais->ai_family == AF_INET)
|
2001-05-06 14:35:20 +00:00
|
|
|
memcpy(&a,
|
2008-11-08 16:45:45 +00:00
|
|
|
(char *) &((SOCKADDR_IN *) ret->ais->
|
2001-05-06 14:35:20 +00:00
|
|
|
ai_addr)->sin_addr, sizeof(a));
|
2001-01-07 19:16:16 +00:00
|
|
|
|
2008-11-08 16:45:45 +00:00
|
|
|
if (ret->ais->ai_canonname)
|
|
|
|
strncpy(realhost, ret->ais->ai_canonname, lenof(realhost));
|
2005-04-07 22:33:42 +00:00
|
|
|
else
|
|
|
|
strncpy(realhost, host, lenof(realhost));
|
2001-01-07 19:16:16 +00:00
|
|
|
}
|
|
|
|
/* We used the IPv4-only gethostbyname()... */
|
|
|
|
else
|
|
|
|
#endif
|
2001-05-06 14:35:20 +00:00
|
|
|
{
|
2005-01-16 14:29:34 +00:00
|
|
|
int n;
|
|
|
|
for (n = 0; h->h_addr_list[n]; n++);
|
|
|
|
ret->addresses = snewn(n, unsigned long);
|
|
|
|
ret->naddresses = n;
|
|
|
|
for (n = 0; n < ret->naddresses; n++) {
|
|
|
|
memcpy(&a, h->h_addr_list[n], sizeof(a));
|
|
|
|
ret->addresses[n] = p_ntohl(a);
|
|
|
|
}
|
2001-01-07 19:16:16 +00:00
|
|
|
memcpy(&a, h->h_addr, sizeof(a));
|
|
|
|
/* This way we are always sure the h->h_name is valid :) */
|
2001-05-09 14:01:15 +00:00
|
|
|
strncpy(realhost, h->h_name, sizeof(realhost));
|
2001-01-07 19:16:16 +00:00
|
|
|
}
|
|
|
|
}
|
2001-05-06 14:35:20 +00:00
|
|
|
} else {
|
2001-04-28 11:24:45 +00:00
|
|
|
/*
|
|
|
|
* This must be a numeric IPv4 address because it caused a
|
|
|
|
* success return from inet_addr.
|
|
|
|
*/
|
2005-01-16 14:29:34 +00:00
|
|
|
ret->addresses = snewn(1, unsigned long);
|
|
|
|
ret->naddresses = 1;
|
|
|
|
ret->addresses[0] = p_ntohl(a);
|
2008-11-08 16:45:45 +00:00
|
|
|
ret->resolved = TRUE;
|
2001-05-09 14:01:15 +00:00
|
|
|
strncpy(realhost, host, sizeof(realhost));
|
2000-10-23 11:55:11 +00:00
|
|
|
}
|
2001-05-09 14:01:15 +00:00
|
|
|
realhost[lenof(realhost)-1] = '\0';
|
2003-03-29 16:14:26 +00:00
|
|
|
*canonicalname = snewn(1+strlen(realhost), char);
|
2001-05-09 14:01:15 +00:00
|
|
|
strcpy(*canonicalname, realhost);
|
2000-10-23 11:55:11 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2003-01-12 15:26:10 +00:00
|
|
|
SockAddr sk_nonamelookup(const char *host)
|
2002-12-18 16:23:11 +00:00
|
|
|
{
|
2003-03-29 16:14:26 +00:00
|
|
|
SockAddr ret = snew(struct SockAddr_tag);
|
2003-01-02 10:07:50 +00:00
|
|
|
ret->error = NULL;
|
2008-11-08 16:45:45 +00:00
|
|
|
ret->resolved = FALSE;
|
2005-02-14 11:43:27 +00:00
|
|
|
#ifndef NO_IPV6
|
2008-11-08 16:45:45 +00:00
|
|
|
ret->ais = NULL;
|
2005-02-14 11:43:27 +00:00
|
|
|
#endif
|
2013-11-17 14:05:41 +00:00
|
|
|
ret->namedpipe = FALSE;
|
2006-08-26 08:37:42 +00:00
|
|
|
ret->addresses = NULL;
|
2005-02-14 11:43:27 +00:00
|
|
|
ret->naddresses = 0;
|
2008-11-08 16:58:55 +00:00
|
|
|
ret->refcount = 1;
|
2002-12-18 16:23:11 +00:00
|
|
|
strncpy(ret->hostname, host, lenof(ret->hostname));
|
|
|
|
ret->hostname[lenof(ret->hostname)-1] = '\0';
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-11-17 14:05:41 +00:00
|
|
|
SockAddr sk_namedpipe_addr(const char *pipename)
|
|
|
|
{
|
|
|
|
SockAddr ret = snew(struct SockAddr_tag);
|
|
|
|
ret->error = NULL;
|
|
|
|
ret->resolved = FALSE;
|
|
|
|
#ifndef NO_IPV6
|
|
|
|
ret->ais = NULL;
|
|
|
|
#endif
|
|
|
|
ret->namedpipe = TRUE;
|
|
|
|
ret->addresses = NULL;
|
|
|
|
ret->naddresses = 0;
|
|
|
|
ret->refcount = 1;
|
|
|
|
strncpy(ret->hostname, pipename, lenof(ret->hostname));
|
|
|
|
ret->hostname[lenof(ret->hostname)-1] = '\0';
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2008-11-08 16:45:45 +00:00
|
|
|
int sk_nextaddr(SockAddr addr, SockAddrStep *step)
|
2005-01-16 14:29:34 +00:00
|
|
|
{
|
|
|
|
#ifndef NO_IPV6
|
2008-11-08 16:45:45 +00:00
|
|
|
if (step->ai) {
|
|
|
|
if (step->ai->ai_next) {
|
|
|
|
step->ai = step->ai->ai_next;
|
2005-01-16 14:29:34 +00:00
|
|
|
return TRUE;
|
|
|
|
} else
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
#endif
|
2008-11-08 16:45:45 +00:00
|
|
|
if (step->curraddr+1 < addr->naddresses) {
|
|
|
|
step->curraddr++;
|
2005-01-16 14:29:34 +00:00
|
|
|
return TRUE;
|
|
|
|
} else {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-09-07 22:39:01 +00:00
|
|
|
void sk_getaddr(SockAddr addr, char *buf, int buflen)
|
|
|
|
{
|
2008-11-08 16:45:45 +00:00
|
|
|
SockAddrStep step;
|
|
|
|
START_STEP(addr, step);
|
|
|
|
|
2004-12-30 16:45:11 +00:00
|
|
|
#ifndef NO_IPV6
|
2008-11-08 16:45:45 +00:00
|
|
|
if (step.ai) {
|
2009-11-08 18:25:29 +00:00
|
|
|
int err = 0;
|
2006-12-23 09:04:27 +00:00
|
|
|
if (p_WSAAddressToStringA) {
|
2009-11-08 18:25:29 +00:00
|
|
|
DWORD dwbuflen = buflen;
|
|
|
|
err = p_WSAAddressToStringA(step.ai->ai_addr, step.ai->ai_addrlen,
|
|
|
|
NULL, buf, &dwbuflen);
|
2006-12-23 09:04:27 +00:00
|
|
|
} else
|
2009-11-08 18:25:29 +00:00
|
|
|
err = -1;
|
|
|
|
if (err) {
|
|
|
|
strncpy(buf, addr->hostname, buflen);
|
|
|
|
if (!buf[0])
|
|
|
|
strncpy(buf, "<unknown>", buflen);
|
|
|
|
buf[buflen-1] = '\0';
|
|
|
|
}
|
2002-12-18 16:23:11 +00:00
|
|
|
} else
|
2001-09-07 22:39:01 +00:00
|
|
|
#endif
|
2008-11-08 16:45:45 +00:00
|
|
|
if (SOCKADDR_FAMILY(addr, step) == AF_INET) {
|
2001-09-07 22:39:01 +00:00
|
|
|
struct in_addr a;
|
2008-11-08 16:45:45 +00:00
|
|
|
assert(addr->addresses && step.curraddr < addr->naddresses);
|
|
|
|
a.s_addr = p_htonl(addr->addresses[step.curraddr]);
|
2003-10-12 13:46:12 +00:00
|
|
|
strncpy(buf, p_inet_ntoa(a), buflen);
|
2002-12-18 16:23:11 +00:00
|
|
|
buf[buflen-1] = '\0';
|
2001-09-07 22:39:01 +00:00
|
|
|
} else {
|
2002-12-18 16:23:11 +00:00
|
|
|
strncpy(buf, addr->hostname, buflen);
|
|
|
|
buf[buflen-1] = '\0';
|
2001-09-07 22:39:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-17 14:05:41 +00:00
|
|
|
int sk_addr_needs_port(SockAddr addr)
|
|
|
|
{
|
|
|
|
return addr->namedpipe ? FALSE : TRUE;
|
|
|
|
}
|
|
|
|
|
2013-07-27 18:35:48 +00:00
|
|
|
int sk_hostname_is_local(const char *name)
|
2002-12-18 12:18:54 +00:00
|
|
|
{
|
2009-01-05 02:45:38 +00:00
|
|
|
return !strcmp(name, "localhost") ||
|
|
|
|
!strcmp(name, "::1") ||
|
|
|
|
!strncmp(name, "127.", 4);
|
2002-12-18 12:18:54 +00:00
|
|
|
}
|
|
|
|
|
2003-10-12 14:12:54 +00:00
|
|
|
static INTERFACE_INFO local_interfaces[16];
|
|
|
|
static int n_local_interfaces; /* 0=not yet, -1=failed, >0=number */
|
|
|
|
|
|
|
|
static int ipv4_is_local_addr(struct in_addr addr)
|
|
|
|
{
|
|
|
|
if (ipv4_is_loopback(addr))
|
|
|
|
return 1; /* loopback addresses are local */
|
|
|
|
if (!n_local_interfaces) {
|
|
|
|
SOCKET s = p_socket(AF_INET, SOCK_DGRAM, 0);
|
|
|
|
DWORD retbytes;
|
|
|
|
|
|
|
|
if (p_WSAIoctl &&
|
|
|
|
p_WSAIoctl(s, SIO_GET_INTERFACE_LIST, NULL, 0,
|
|
|
|
local_interfaces, sizeof(local_interfaces),
|
|
|
|
&retbytes, NULL, NULL) == 0)
|
|
|
|
n_local_interfaces = retbytes / sizeof(INTERFACE_INFO);
|
|
|
|
else
|
|
|
|
logevent(NULL, "Unable to get list of local IP addresses");
|
|
|
|
}
|
|
|
|
if (n_local_interfaces > 0) {
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < n_local_interfaces; i++) {
|
|
|
|
SOCKADDR_IN *address =
|
|
|
|
(SOCKADDR_IN *)&local_interfaces[i].iiAddress;
|
|
|
|
if (address->sin_addr.s_addr == addr.s_addr)
|
|
|
|
return 1; /* this address is local */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0; /* this address is not local */
|
|
|
|
}
|
|
|
|
|
2002-12-18 12:18:54 +00:00
|
|
|
int sk_address_is_local(SockAddr addr)
|
|
|
|
{
|
2008-11-08 16:45:45 +00:00
|
|
|
SockAddrStep step;
|
|
|
|
int family;
|
|
|
|
START_STEP(addr, step);
|
|
|
|
family = SOCKADDR_FAMILY(addr, step);
|
|
|
|
|
2004-12-30 16:45:11 +00:00
|
|
|
#ifndef NO_IPV6
|
2008-11-08 16:45:45 +00:00
|
|
|
if (family == AF_INET6) {
|
2012-10-17 20:48:07 +00:00
|
|
|
return IN6_IS_ADDR_LOOPBACK(&((const struct sockaddr_in6 *)step.ai->ai_addr)->sin6_addr);
|
2002-12-18 16:23:11 +00:00
|
|
|
} else
|
2002-12-18 12:18:54 +00:00
|
|
|
#endif
|
2008-11-08 16:45:45 +00:00
|
|
|
if (family == AF_INET) {
|
2005-04-01 08:46:26 +00:00
|
|
|
#ifndef NO_IPV6
|
2008-11-08 16:45:45 +00:00
|
|
|
if (step.ai) {
|
|
|
|
return ipv4_is_local_addr(((struct sockaddr_in *)step.ai->ai_addr)
|
2005-04-01 08:46:26 +00:00
|
|
|
->sin_addr);
|
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
struct in_addr a;
|
2008-11-08 16:45:45 +00:00
|
|
|
assert(addr->addresses && step.curraddr < addr->naddresses);
|
|
|
|
a.s_addr = p_htonl(addr->addresses[step.curraddr]);
|
2005-04-01 08:46:26 +00:00
|
|
|
return ipv4_is_local_addr(a);
|
|
|
|
}
|
2002-12-18 12:18:54 +00:00
|
|
|
} else {
|
2008-11-08 16:45:45 +00:00
|
|
|
assert(family == AF_UNSPEC);
|
2002-12-18 16:23:11 +00:00
|
|
|
return 0; /* we don't know; assume not */
|
2002-12-18 12:18:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-16 20:15:51 +00:00
|
|
|
int sk_address_is_special_local(SockAddr addr)
|
|
|
|
{
|
|
|
|
return 0; /* no Unix-domain socket analogue here */
|
|
|
|
}
|
|
|
|
|
2002-04-27 15:01:18 +00:00
|
|
|
int sk_addrtype(SockAddr addr)
|
|
|
|
{
|
2008-11-08 16:45:45 +00:00
|
|
|
SockAddrStep step;
|
|
|
|
int family;
|
|
|
|
START_STEP(addr, step);
|
|
|
|
family = SOCKADDR_FAMILY(addr, step);
|
|
|
|
|
|
|
|
return (family == AF_INET ? ADDRTYPE_IPV4 :
|
2004-12-30 16:45:11 +00:00
|
|
|
#ifndef NO_IPV6
|
2008-11-08 16:45:45 +00:00
|
|
|
family == AF_INET6 ? ADDRTYPE_IPV6 :
|
2002-12-18 16:23:11 +00:00
|
|
|
#endif
|
|
|
|
ADDRTYPE_NAME);
|
2002-04-27 15:01:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void sk_addrcopy(SockAddr addr, char *buf)
|
|
|
|
{
|
2008-11-08 16:45:45 +00:00
|
|
|
SockAddrStep step;
|
|
|
|
int family;
|
|
|
|
START_STEP(addr, step);
|
|
|
|
family = SOCKADDR_FAMILY(addr, step);
|
|
|
|
|
|
|
|
assert(family != AF_UNSPEC);
|
2004-12-30 16:45:11 +00:00
|
|
|
#ifndef NO_IPV6
|
2008-11-08 16:45:45 +00:00
|
|
|
if (step.ai) {
|
|
|
|
if (family == AF_INET)
|
|
|
|
memcpy(buf, &((struct sockaddr_in *)step.ai->ai_addr)->sin_addr,
|
2005-01-16 14:29:34 +00:00
|
|
|
sizeof(struct in_addr));
|
2008-11-08 16:45:45 +00:00
|
|
|
else if (family == AF_INET6)
|
|
|
|
memcpy(buf, &((struct sockaddr_in6 *)step.ai->ai_addr)->sin6_addr,
|
2005-01-16 14:29:34 +00:00
|
|
|
sizeof(struct in6_addr));
|
|
|
|
else
|
|
|
|
assert(FALSE);
|
2002-12-18 16:23:11 +00:00
|
|
|
} else
|
2002-04-27 15:01:18 +00:00
|
|
|
#endif
|
2008-11-08 16:45:45 +00:00
|
|
|
if (family == AF_INET) {
|
2002-04-27 15:01:18 +00:00
|
|
|
struct in_addr a;
|
2008-11-08 16:45:45 +00:00
|
|
|
assert(addr->addresses && step.curraddr < addr->naddresses);
|
|
|
|
a.s_addr = p_htonl(addr->addresses[step.curraddr]);
|
2002-09-20 17:54:17 +00:00
|
|
|
memcpy(buf, (char*) &a.s_addr, 4);
|
2002-04-27 15:01:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-05-06 14:35:20 +00:00
|
|
|
void sk_addr_free(SockAddr addr)
|
|
|
|
{
|
2008-11-08 16:58:55 +00:00
|
|
|
if (--addr->refcount > 0)
|
|
|
|
return;
|
2005-01-16 14:29:34 +00:00
|
|
|
#ifndef NO_IPV6
|
|
|
|
if (addr->ais && p_freeaddrinfo)
|
|
|
|
p_freeaddrinfo(addr->ais);
|
|
|
|
#endif
|
|
|
|
if (addr->addresses)
|
|
|
|
sfree(addr->addresses);
|
2000-10-23 11:55:11 +00:00
|
|
|
sfree(addr);
|
|
|
|
}
|
|
|
|
|
2008-11-08 16:58:55 +00:00
|
|
|
SockAddr sk_addr_dup(SockAddr addr)
|
|
|
|
{
|
|
|
|
addr->refcount++;
|
|
|
|
return addr;
|
|
|
|
}
|
|
|
|
|
2001-05-06 14:35:20 +00:00
|
|
|
static Plug sk_tcp_plug(Socket sock, Plug p)
|
|
|
|
{
|
2001-03-13 10:22:45 +00:00
|
|
|
Actual_Socket s = (Actual_Socket) sock;
|
|
|
|
Plug ret = s->plug;
|
2001-05-06 14:35:20 +00:00
|
|
|
if (p)
|
|
|
|
s->plug = p;
|
2001-03-13 10:22:45 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2001-05-06 14:35:20 +00:00
|
|
|
static void sk_tcp_flush(Socket s)
|
|
|
|
{
|
2001-03-13 10:22:45 +00:00
|
|
|
/*
|
|
|
|
* We send data to the socket as soon as we can anyway,
|
|
|
|
* so we don't need to do anything here. :-)
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
2001-05-13 14:02:28 +00:00
|
|
|
static void sk_tcp_close(Socket s);
|
2003-01-10 18:33:35 +00:00
|
|
|
static int sk_tcp_write(Socket s, const char *data, int len);
|
|
|
|
static int sk_tcp_write_oob(Socket s, const char *data, int len);
|
2011-09-13 11:44:03 +00:00
|
|
|
static void sk_tcp_write_eof(Socket s);
|
2002-03-23 17:47:21 +00:00
|
|
|
static void sk_tcp_set_frozen(Socket s, int is_frozen);
|
2003-05-04 14:18:18 +00:00
|
|
|
static const char *sk_tcp_socket_error(Socket s);
|
2001-03-13 10:22:45 +00:00
|
|
|
|
2001-08-08 20:44:35 +00:00
|
|
|
extern char *do_select(SOCKET skt, int startup);
|
|
|
|
|
2013-11-17 14:03:55 +00:00
|
|
|
static Socket sk_tcp_accept(accept_ctx_t ctx, Plug plug)
|
2001-08-08 20:44:35 +00:00
|
|
|
{
|
2003-01-14 18:43:45 +00:00
|
|
|
static const struct socket_function_table fn_table = {
|
2001-08-08 20:44:35 +00:00
|
|
|
sk_tcp_plug,
|
|
|
|
sk_tcp_close,
|
|
|
|
sk_tcp_write,
|
|
|
|
sk_tcp_write_oob,
|
2011-09-13 11:44:03 +00:00
|
|
|
sk_tcp_write_eof,
|
2001-08-08 20:44:35 +00:00
|
|
|
sk_tcp_flush,
|
2002-03-23 17:47:21 +00:00
|
|
|
sk_tcp_set_frozen,
|
2001-08-08 20:44:35 +00:00
|
|
|
sk_tcp_socket_error
|
|
|
|
};
|
|
|
|
|
|
|
|
DWORD err;
|
|
|
|
char *errstr;
|
|
|
|
Actual_Socket ret;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create Socket structure.
|
|
|
|
*/
|
2003-03-29 16:14:26 +00:00
|
|
|
ret = snew(struct Socket_tag);
|
2001-08-08 20:44:35 +00:00
|
|
|
ret->fn = &fn_table;
|
|
|
|
ret->error = NULL;
|
|
|
|
ret->plug = plug;
|
2001-08-25 17:09:23 +00:00
|
|
|
bufchain_init(&ret->output_data);
|
2001-08-08 20:44:35 +00:00
|
|
|
ret->writable = 1; /* to start with */
|
|
|
|
ret->sending_oob = 0;
|
2011-09-13 11:44:03 +00:00
|
|
|
ret->outgoingeof = EOF_NO;
|
2001-08-08 20:44:35 +00:00
|
|
|
ret->frozen = 1;
|
2001-08-25 17:09:23 +00:00
|
|
|
ret->frozen_readable = 0;
|
2001-10-12 19:32:13 +00:00
|
|
|
ret->localhost_only = 0; /* unused, but best init anyway */
|
2001-10-28 09:57:47 +00:00
|
|
|
ret->pending_error = 0;
|
2005-01-08 14:45:26 +00:00
|
|
|
ret->parent = ret->child = NULL;
|
2005-01-16 14:29:34 +00:00
|
|
|
ret->addr = NULL;
|
2001-08-08 20:44:35 +00:00
|
|
|
|
2013-11-17 14:03:55 +00:00
|
|
|
ret->s = (SOCKET)ctx.p;
|
2001-08-08 20:44:35 +00:00
|
|
|
|
|
|
|
if (ret->s == INVALID_SOCKET) {
|
2003-10-12 13:46:12 +00:00
|
|
|
err = p_WSAGetLastError();
|
2001-08-08 20:44:35 +00:00
|
|
|
ret->error = winsock_error_string(err);
|
|
|
|
return (Socket) ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret->oobinline = 0;
|
|
|
|
|
|
|
|
/* Set up a select mechanism. This could be an AsyncSelect on a
|
|
|
|
* window, or an EventSelect on an event object. */
|
|
|
|
errstr = do_select(ret->s, 1);
|
|
|
|
if (errstr) {
|
|
|
|
ret->error = errstr;
|
|
|
|
return (Socket) ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
add234(sktree, ret);
|
|
|
|
|
|
|
|
return (Socket) ret;
|
|
|
|
}
|
|
|
|
|
2005-01-16 14:29:34 +00:00
|
|
|
static DWORD try_connect(Actual_Socket sock)
|
2001-03-13 10:22:45 +00:00
|
|
|
{
|
2000-10-23 11:55:11 +00:00
|
|
|
SOCKET s;
|
2004-12-30 16:45:11 +00:00
|
|
|
#ifndef NO_IPV6
|
2001-01-07 19:16:16 +00:00
|
|
|
SOCKADDR_IN6 a6;
|
|
|
|
#endif
|
2000-10-23 11:55:11 +00:00
|
|
|
SOCKADDR_IN a;
|
|
|
|
DWORD err;
|
|
|
|
char *errstr;
|
2001-01-19 10:10:37 +00:00
|
|
|
short localport;
|
2005-01-16 14:29:34 +00:00
|
|
|
int family;
|
2000-10-23 11:55:11 +00:00
|
|
|
|
2005-01-16 14:29:34 +00:00
|
|
|
if (sock->s != INVALID_SOCKET) {
|
|
|
|
do_select(sock->s, 0);
|
|
|
|
p_closesocket(sock->s);
|
|
|
|
}
|
|
|
|
|
|
|
|
plug_log(sock->plug, 0, sock->addr, sock->port, NULL, 0);
|
2000-10-23 11:55:11 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Open socket.
|
|
|
|
*/
|
2008-11-08 16:45:45 +00:00
|
|
|
family = SOCKADDR_FAMILY(sock->addr, sock->step);
|
2005-01-16 14:29:34 +00:00
|
|
|
|
2007-11-26 21:09:54 +00:00
|
|
|
/*
|
|
|
|
* Remove the socket from the tree before we overwrite its
|
|
|
|
* internal socket id, because that forms part of the tree's
|
|
|
|
* sorting criterion. We'll add it back before exiting this
|
|
|
|
* function, whether we changed anything or not.
|
|
|
|
*/
|
|
|
|
del234(sktree, sock);
|
|
|
|
|
2005-01-16 14:29:34 +00:00
|
|
|
s = p_socket(family, SOCK_STREAM, 0);
|
|
|
|
sock->s = s;
|
2000-10-23 11:55:11 +00:00
|
|
|
|
|
|
|
if (s == INVALID_SOCKET) {
|
2003-10-12 13:46:12 +00:00
|
|
|
err = p_WSAGetLastError();
|
2005-01-16 14:29:34 +00:00
|
|
|
sock->error = winsock_error_string(err);
|
|
|
|
goto ret;
|
2000-10-23 11:55:11 +00:00
|
|
|
}
|
2001-02-01 14:11:04 +00:00
|
|
|
|
2005-01-16 14:29:34 +00:00
|
|
|
if (sock->oobinline) {
|
2001-01-29 14:49:21 +00:00
|
|
|
BOOL b = TRUE;
|
2003-10-12 13:46:12 +00:00
|
|
|
p_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (void *) &b, sizeof(b));
|
2001-01-29 14:49:21 +00:00
|
|
|
}
|
2000-10-23 11:55:11 +00:00
|
|
|
|
2005-01-16 14:29:34 +00:00
|
|
|
if (sock->nodelay) {
|
2001-11-29 21:47:11 +00:00
|
|
|
BOOL b = TRUE;
|
2003-10-12 13:46:12 +00:00
|
|
|
p_setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (void *) &b, sizeof(b));
|
2001-11-29 21:47:11 +00:00
|
|
|
}
|
|
|
|
|
2005-01-16 14:29:34 +00:00
|
|
|
if (sock->keepalive) {
|
2004-06-20 17:07:38 +00:00
|
|
|
BOOL b = TRUE;
|
|
|
|
p_setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (void *) &b, sizeof(b));
|
|
|
|
}
|
|
|
|
|
2000-10-23 11:55:11 +00:00
|
|
|
/*
|
|
|
|
* Bind to local address.
|
|
|
|
*/
|
2005-01-16 14:29:34 +00:00
|
|
|
if (sock->privport)
|
2001-05-06 14:35:20 +00:00
|
|
|
localport = 1023; /* count from 1023 downwards */
|
2001-01-07 19:16:16 +00:00
|
|
|
else
|
2001-05-06 14:35:20 +00:00
|
|
|
localport = 0; /* just use port 0 (ie winsock picks) */
|
2001-01-19 10:10:37 +00:00
|
|
|
|
|
|
|
/* Loop round trying to bind */
|
|
|
|
while (1) {
|
2005-01-16 14:29:34 +00:00
|
|
|
int sockcode;
|
2001-01-19 10:10:37 +00:00
|
|
|
|
2004-12-30 16:45:11 +00:00
|
|
|
#ifndef NO_IPV6
|
2005-01-16 14:29:34 +00:00
|
|
|
if (family == AF_INET6) {
|
2001-05-06 14:35:20 +00:00
|
|
|
memset(&a6, 0, sizeof(a6));
|
|
|
|
a6.sin6_family = AF_INET6;
|
2004-12-30 16:45:11 +00:00
|
|
|
/*a6.sin6_addr = in6addr_any; */ /* == 0 done by memset() */
|
2003-10-12 13:46:12 +00:00
|
|
|
a6.sin6_port = p_htons(localport);
|
2001-05-06 14:35:20 +00:00
|
|
|
} else
|
2001-01-07 19:16:16 +00:00
|
|
|
#endif
|
2001-05-06 14:35:20 +00:00
|
|
|
{
|
|
|
|
a.sin_family = AF_INET;
|
2003-10-12 13:46:12 +00:00
|
|
|
a.sin_addr.s_addr = p_htonl(INADDR_ANY);
|
|
|
|
a.sin_port = p_htons(localport);
|
2001-05-06 14:35:20 +00:00
|
|
|
}
|
2004-12-30 16:45:11 +00:00
|
|
|
#ifndef NO_IPV6
|
2008-11-08 16:45:45 +00:00
|
|
|
sockcode = p_bind(s, (family == AF_INET6 ?
|
|
|
|
(struct sockaddr *) &a6 :
|
|
|
|
(struct sockaddr *) &a),
|
|
|
|
(family == AF_INET6 ? sizeof(a6) : sizeof(a)));
|
2001-01-07 19:16:16 +00:00
|
|
|
#else
|
2005-01-16 14:29:34 +00:00
|
|
|
sockcode = p_bind(s, (struct sockaddr *) &a, sizeof(a));
|
2001-01-07 19:16:16 +00:00
|
|
|
#endif
|
2005-01-16 14:29:34 +00:00
|
|
|
if (sockcode != SOCKET_ERROR) {
|
2001-05-06 14:35:20 +00:00
|
|
|
err = 0;
|
|
|
|
break; /* done */
|
|
|
|
} else {
|
2003-10-12 13:46:12 +00:00
|
|
|
err = p_WSAGetLastError();
|
2001-05-06 14:35:20 +00:00
|
|
|
if (err != WSAEADDRINUSE) /* failed, for a bad reason */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (localport == 0)
|
|
|
|
break; /* we're only looping once */
|
|
|
|
localport--;
|
|
|
|
if (localport == 0)
|
|
|
|
break; /* we might have got to the end */
|
2001-01-19 10:10:37 +00:00
|
|
|
}
|
|
|
|
|
2001-05-06 14:35:20 +00:00
|
|
|
if (err) {
|
2005-01-16 14:29:34 +00:00
|
|
|
sock->error = winsock_error_string(err);
|
|
|
|
goto ret;
|
2000-10-23 11:55:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Connect to remote address.
|
|
|
|
*/
|
2004-12-30 16:45:11 +00:00
|
|
|
#ifndef NO_IPV6
|
2008-11-08 16:45:45 +00:00
|
|
|
if (sock->step.ai) {
|
2005-01-16 14:29:34 +00:00
|
|
|
if (family == AF_INET6) {
|
|
|
|
a6.sin6_family = AF_INET6;
|
|
|
|
a6.sin6_port = p_htons((short) sock->port);
|
|
|
|
a6.sin6_addr =
|
2008-11-08 16:45:45 +00:00
|
|
|
((struct sockaddr_in6 *) sock->step.ai->ai_addr)->sin6_addr;
|
|
|
|
a6.sin6_flowinfo = ((struct sockaddr_in6 *) sock->step.ai->ai_addr)->sin6_flowinfo;
|
|
|
|
a6.sin6_scope_id = ((struct sockaddr_in6 *) sock->step.ai->ai_addr)->sin6_scope_id;
|
2005-01-16 14:29:34 +00:00
|
|
|
} else {
|
|
|
|
a.sin_family = AF_INET;
|
|
|
|
a.sin_addr =
|
2008-11-08 16:45:45 +00:00
|
|
|
((struct sockaddr_in *) sock->step.ai->ai_addr)->sin_addr;
|
2005-01-16 14:29:34 +00:00
|
|
|
a.sin_port = p_htons((short) sock->port);
|
|
|
|
}
|
2001-05-06 14:35:20 +00:00
|
|
|
} else
|
2001-01-07 19:16:16 +00:00
|
|
|
#endif
|
2001-05-06 14:35:20 +00:00
|
|
|
{
|
2008-11-08 16:45:45 +00:00
|
|
|
assert(sock->addr->addresses && sock->step.curraddr < sock->addr->naddresses);
|
2001-01-07 19:16:16 +00:00
|
|
|
a.sin_family = AF_INET;
|
2008-11-08 16:45:45 +00:00
|
|
|
a.sin_addr.s_addr = p_htonl(sock->addr->addresses[sock->step.curraddr]);
|
2005-01-16 14:29:34 +00:00
|
|
|
a.sin_port = p_htons((short) sock->port);
|
2001-01-07 19:16:16 +00:00
|
|
|
}
|
2001-09-07 22:39:01 +00:00
|
|
|
|
|
|
|
/* Set up a select mechanism. This could be an AsyncSelect on a
|
|
|
|
* window, or an EventSelect on an event object. */
|
|
|
|
errstr = do_select(s, 1);
|
|
|
|
if (errstr) {
|
2005-01-16 14:29:34 +00:00
|
|
|
sock->error = errstr;
|
|
|
|
err = 1;
|
|
|
|
goto ret;
|
2001-09-07 22:39:01 +00:00
|
|
|
}
|
|
|
|
|
2001-05-06 14:35:20 +00:00
|
|
|
if ((
|
2004-12-30 16:45:11 +00:00
|
|
|
#ifndef NO_IPV6
|
2005-01-16 14:29:34 +00:00
|
|
|
p_connect(s,
|
|
|
|
((family == AF_INET6) ? (struct sockaddr *) &a6 :
|
|
|
|
(struct sockaddr *) &a),
|
|
|
|
(family == AF_INET6) ? sizeof(a6) : sizeof(a))
|
2001-01-07 19:16:16 +00:00
|
|
|
#else
|
2003-10-12 13:46:12 +00:00
|
|
|
p_connect(s, (struct sockaddr *) &a, sizeof(a))
|
2001-01-07 19:16:16 +00:00
|
|
|
#endif
|
2001-05-06 14:35:20 +00:00
|
|
|
) == SOCKET_ERROR) {
|
2003-10-12 13:46:12 +00:00
|
|
|
err = p_WSAGetLastError();
|
2001-09-07 22:39:01 +00:00
|
|
|
/*
|
|
|
|
* We expect a potential EWOULDBLOCK here, because the
|
|
|
|
* chances are the front end has done a select for
|
|
|
|
* FD_CONNECT, so that connect() will complete
|
|
|
|
* asynchronously.
|
|
|
|
*/
|
|
|
|
if ( err != WSAEWOULDBLOCK ) {
|
2005-01-16 14:29:34 +00:00
|
|
|
sock->error = winsock_error_string(err);
|
|
|
|
goto ret;
|
2001-09-07 22:39:01 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* If we _don't_ get EWOULDBLOCK, the connect has completed
|
|
|
|
* and we should set the socket as writable.
|
|
|
|
*/
|
2005-01-16 14:29:34 +00:00
|
|
|
sock->writable = 1;
|
2000-10-23 11:55:11 +00:00
|
|
|
}
|
|
|
|
|
2005-01-16 14:29:34 +00:00
|
|
|
err = 0;
|
|
|
|
|
|
|
|
ret:
|
2007-11-26 21:09:54 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* No matter what happened, put the socket back in the tree.
|
|
|
|
*/
|
|
|
|
add234(sktree, sock);
|
|
|
|
|
2005-01-16 14:29:34 +00:00
|
|
|
if (err)
|
|
|
|
plug_log(sock->plug, 1, sock->addr, sock->port, sock->error, err);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
|
|
|
|
int nodelay, int keepalive, Plug plug)
|
|
|
|
{
|
|
|
|
static const struct socket_function_table fn_table = {
|
|
|
|
sk_tcp_plug,
|
|
|
|
sk_tcp_close,
|
|
|
|
sk_tcp_write,
|
|
|
|
sk_tcp_write_oob,
|
2011-09-13 11:44:03 +00:00
|
|
|
sk_tcp_write_eof,
|
2005-01-16 14:29:34 +00:00
|
|
|
sk_tcp_flush,
|
|
|
|
sk_tcp_set_frozen,
|
|
|
|
sk_tcp_socket_error
|
|
|
|
};
|
|
|
|
|
|
|
|
Actual_Socket ret;
|
|
|
|
DWORD err;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create Socket structure.
|
|
|
|
*/
|
|
|
|
ret = snew(struct Socket_tag);
|
|
|
|
ret->fn = &fn_table;
|
|
|
|
ret->error = NULL;
|
|
|
|
ret->plug = plug;
|
|
|
|
bufchain_init(&ret->output_data);
|
|
|
|
ret->connected = 0; /* to start with */
|
|
|
|
ret->writable = 0; /* to start with */
|
|
|
|
ret->sending_oob = 0;
|
2011-09-13 11:44:03 +00:00
|
|
|
ret->outgoingeof = EOF_NO;
|
2005-01-16 14:29:34 +00:00
|
|
|
ret->frozen = 0;
|
|
|
|
ret->frozen_readable = 0;
|
|
|
|
ret->localhost_only = 0; /* unused, but best init anyway */
|
|
|
|
ret->pending_error = 0;
|
|
|
|
ret->parent = ret->child = NULL;
|
|
|
|
ret->oobinline = oobinline;
|
|
|
|
ret->nodelay = nodelay;
|
|
|
|
ret->keepalive = keepalive;
|
|
|
|
ret->privport = privport;
|
|
|
|
ret->port = port;
|
|
|
|
ret->addr = addr;
|
2008-11-08 16:45:45 +00:00
|
|
|
START_STEP(ret->addr, ret->step);
|
2005-01-16 14:29:34 +00:00
|
|
|
ret->s = INVALID_SOCKET;
|
|
|
|
|
|
|
|
err = 0;
|
|
|
|
do {
|
|
|
|
err = try_connect(ret);
|
2008-11-08 16:45:45 +00:00
|
|
|
} while (err && sk_nextaddr(ret->addr, &ret->step));
|
2003-08-07 16:04:33 +00:00
|
|
|
|
2001-03-13 10:22:45 +00:00
|
|
|
return (Socket) ret;
|
2000-10-23 11:55:11 +00:00
|
|
|
}
|
|
|
|
|
2004-12-30 16:45:11 +00:00
|
|
|
Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only,
|
2005-01-08 14:45:26 +00:00
|
|
|
int orig_address_family)
|
2001-08-08 20:44:35 +00:00
|
|
|
{
|
2003-01-14 18:43:45 +00:00
|
|
|
static const struct socket_function_table fn_table = {
|
2001-08-08 20:44:35 +00:00
|
|
|
sk_tcp_plug,
|
|
|
|
sk_tcp_close,
|
|
|
|
sk_tcp_write,
|
|
|
|
sk_tcp_write_oob,
|
2011-09-13 11:44:03 +00:00
|
|
|
sk_tcp_write_eof,
|
2001-08-08 20:44:35 +00:00
|
|
|
sk_tcp_flush,
|
2002-03-23 17:47:21 +00:00
|
|
|
sk_tcp_set_frozen,
|
2001-08-08 20:44:35 +00:00
|
|
|
sk_tcp_socket_error
|
|
|
|
};
|
|
|
|
|
|
|
|
SOCKET s;
|
2004-12-30 16:45:11 +00:00
|
|
|
#ifndef NO_IPV6
|
2001-08-08 20:44:35 +00:00
|
|
|
SOCKADDR_IN6 a6;
|
|
|
|
#endif
|
|
|
|
SOCKADDR_IN a;
|
2004-12-30 16:45:11 +00:00
|
|
|
|
2001-08-08 20:44:35 +00:00
|
|
|
DWORD err;
|
|
|
|
char *errstr;
|
|
|
|
Actual_Socket ret;
|
|
|
|
int retcode;
|
|
|
|
int on = 1;
|
|
|
|
|
2005-01-08 14:45:26 +00:00
|
|
|
int address_family;
|
|
|
|
|
2001-08-08 20:44:35 +00:00
|
|
|
/*
|
|
|
|
* Create Socket structure.
|
|
|
|
*/
|
2003-03-29 16:14:26 +00:00
|
|
|
ret = snew(struct Socket_tag);
|
2001-08-08 20:44:35 +00:00
|
|
|
ret->fn = &fn_table;
|
|
|
|
ret->error = NULL;
|
|
|
|
ret->plug = plug;
|
2001-08-25 17:09:23 +00:00
|
|
|
bufchain_init(&ret->output_data);
|
2001-08-08 20:44:35 +00:00
|
|
|
ret->writable = 0; /* to start with */
|
|
|
|
ret->sending_oob = 0;
|
2011-09-13 11:44:03 +00:00
|
|
|
ret->outgoingeof = EOF_NO;
|
2001-08-08 20:44:35 +00:00
|
|
|
ret->frozen = 0;
|
2001-08-25 17:09:23 +00:00
|
|
|
ret->frozen_readable = 0;
|
2001-10-12 19:32:13 +00:00
|
|
|
ret->localhost_only = local_host_only;
|
2001-10-28 09:57:47 +00:00
|
|
|
ret->pending_error = 0;
|
2005-01-08 14:45:26 +00:00
|
|
|
ret->parent = ret->child = NULL;
|
2005-01-16 14:29:34 +00:00
|
|
|
ret->addr = NULL;
|
2001-08-08 20:44:35 +00:00
|
|
|
|
2004-12-30 16:45:11 +00:00
|
|
|
/*
|
|
|
|
* Translate address_family from platform-independent constants
|
|
|
|
* into local reality.
|
|
|
|
*/
|
2005-01-08 14:45:26 +00:00
|
|
|
address_family = (orig_address_family == ADDRTYPE_IPV4 ? AF_INET :
|
2004-12-30 16:45:11 +00:00
|
|
|
#ifndef NO_IPV6
|
2005-01-08 14:45:26 +00:00
|
|
|
orig_address_family == ADDRTYPE_IPV6 ? AF_INET6 :
|
2004-12-30 16:45:11 +00:00
|
|
|
#endif
|
|
|
|
AF_UNSPEC);
|
2005-01-08 14:45:26 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Our default, if passed the `don't care' value
|
|
|
|
* ADDRTYPE_UNSPEC, is to listen on IPv4. If IPv6 is supported,
|
|
|
|
* we will also set up a second socket listening on IPv6, but
|
|
|
|
* the v4 one is primary since that ought to work even on
|
|
|
|
* non-v6-supporting systems.
|
|
|
|
*/
|
|
|
|
if (address_family == AF_UNSPEC) address_family = AF_INET;
|
2004-12-30 16:45:11 +00:00
|
|
|
|
2001-08-08 20:44:35 +00:00
|
|
|
/*
|
|
|
|
* Open socket.
|
|
|
|
*/
|
2004-12-30 16:45:11 +00:00
|
|
|
s = p_socket(address_family, SOCK_STREAM, 0);
|
2001-08-08 20:44:35 +00:00
|
|
|
ret->s = s;
|
|
|
|
|
|
|
|
if (s == INVALID_SOCKET) {
|
2003-10-12 13:46:12 +00:00
|
|
|
err = p_WSAGetLastError();
|
2001-08-08 20:44:35 +00:00
|
|
|
ret->error = winsock_error_string(err);
|
|
|
|
return (Socket) ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret->oobinline = 0;
|
|
|
|
|
2003-10-12 13:46:12 +00:00
|
|
|
p_setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on));
|
2001-08-08 20:44:35 +00:00
|
|
|
|
2004-12-30 16:45:11 +00:00
|
|
|
#ifndef NO_IPV6
|
|
|
|
if (address_family == AF_INET6) {
|
2001-08-08 20:44:35 +00:00
|
|
|
memset(&a6, 0, sizeof(a6));
|
|
|
|
a6.sin6_family = AF_INET6;
|
2001-08-27 15:59:37 +00:00
|
|
|
if (local_host_only)
|
|
|
|
a6.sin6_addr = in6addr_loopback;
|
|
|
|
else
|
|
|
|
a6.sin6_addr = in6addr_any;
|
2014-01-25 15:58:59 +00:00
|
|
|
if (srcaddr != NULL && p_getaddrinfo) {
|
|
|
|
struct addrinfo hints;
|
|
|
|
struct addrinfo *ai;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
memset(&hints, 0, sizeof(hints));
|
|
|
|
hints.ai_family = AF_INET6;
|
|
|
|
hints.ai_flags = 0;
|
|
|
|
{
|
|
|
|
/* strip [] on IPv6 address literals */
|
|
|
|
char *trimmed_addr = host_strduptrim(srcaddr);
|
|
|
|
err = p_getaddrinfo(trimmed_addr, NULL, &hints, &ai);
|
|
|
|
sfree(trimmed_addr);
|
|
|
|
}
|
|
|
|
if (err == 0 && ai->ai_family == AF_INET6) {
|
|
|
|
a6.sin6_addr =
|
|
|
|
((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr;
|
|
|
|
}
|
|
|
|
}
|
2003-10-12 13:46:12 +00:00
|
|
|
a6.sin6_port = p_htons(port);
|
2001-08-08 20:44:35 +00:00
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
{
|
2002-12-18 11:39:25 +00:00
|
|
|
int got_addr = 0;
|
2001-08-08 20:44:35 +00:00
|
|
|
a.sin_family = AF_INET;
|
2002-12-18 11:39:25 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Bind to source address. First try an explicitly
|
|
|
|
* specified one...
|
|
|
|
*/
|
|
|
|
if (srcaddr) {
|
2003-10-12 13:46:12 +00:00
|
|
|
a.sin_addr.s_addr = p_inet_addr(srcaddr);
|
2002-12-18 11:39:25 +00:00
|
|
|
if (a.sin_addr.s_addr != INADDR_NONE) {
|
|
|
|
/* Override localhost_only with specified listen addr. */
|
|
|
|
ret->localhost_only = ipv4_is_loopback(a.sin_addr);
|
|
|
|
got_addr = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ... and failing that, go with one of the standard ones.
|
|
|
|
*/
|
|
|
|
if (!got_addr) {
|
|
|
|
if (local_host_only)
|
2003-10-12 13:46:12 +00:00
|
|
|
a.sin_addr.s_addr = p_htonl(INADDR_LOOPBACK);
|
2002-12-18 11:39:25 +00:00
|
|
|
else
|
2003-10-12 13:46:12 +00:00
|
|
|
a.sin_addr.s_addr = p_htonl(INADDR_ANY);
|
2002-12-18 11:39:25 +00:00
|
|
|
}
|
|
|
|
|
2003-10-12 13:46:12 +00:00
|
|
|
a.sin_port = p_htons((short)port);
|
2001-08-08 20:44:35 +00:00
|
|
|
}
|
2004-12-30 16:45:11 +00:00
|
|
|
#ifndef NO_IPV6
|
|
|
|
retcode = p_bind(s, (address_family == AF_INET6 ?
|
2001-08-08 20:44:35 +00:00
|
|
|
(struct sockaddr *) &a6 :
|
|
|
|
(struct sockaddr *) &a),
|
2004-12-30 16:45:11 +00:00
|
|
|
(address_family ==
|
2001-08-08 20:44:35 +00:00
|
|
|
AF_INET6 ? sizeof(a6) : sizeof(a)));
|
|
|
|
#else
|
2003-10-12 13:46:12 +00:00
|
|
|
retcode = p_bind(s, (struct sockaddr *) &a, sizeof(a));
|
2001-08-08 20:44:35 +00:00
|
|
|
#endif
|
|
|
|
if (retcode != SOCKET_ERROR) {
|
|
|
|
err = 0;
|
|
|
|
} else {
|
2003-10-12 13:46:12 +00:00
|
|
|
err = p_WSAGetLastError();
|
2001-08-08 20:44:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (err) {
|
2005-01-08 14:45:26 +00:00
|
|
|
p_closesocket(s);
|
2001-08-08 20:44:35 +00:00
|
|
|
ret->error = winsock_error_string(err);
|
|
|
|
return (Socket) ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-10-12 13:46:12 +00:00
|
|
|
if (p_listen(s, SOMAXCONN) == SOCKET_ERROR) {
|
|
|
|
p_closesocket(s);
|
2012-11-14 18:32:09 +00:00
|
|
|
ret->error = winsock_error_string(p_WSAGetLastError());
|
2001-08-08 20:44:35 +00:00
|
|
|
return (Socket) ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set up a select mechanism. This could be an AsyncSelect on a
|
|
|
|
* window, or an EventSelect on an event object. */
|
|
|
|
errstr = do_select(s, 1);
|
|
|
|
if (errstr) {
|
2005-01-08 14:45:26 +00:00
|
|
|
p_closesocket(s);
|
2001-08-08 20:44:35 +00:00
|
|
|
ret->error = errstr;
|
|
|
|
return (Socket) ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
add234(sktree, ret);
|
|
|
|
|
2005-01-08 14:45:26 +00:00
|
|
|
#ifndef NO_IPV6
|
|
|
|
/*
|
|
|
|
* If we were given ADDRTYPE_UNSPEC, we must also create an
|
|
|
|
* IPv6 listening socket and link it to this one.
|
|
|
|
*/
|
|
|
|
if (address_family == AF_INET && orig_address_family == ADDRTYPE_UNSPEC) {
|
|
|
|
Actual_Socket other;
|
|
|
|
|
|
|
|
other = (Actual_Socket) sk_newlistener(srcaddr, port, plug,
|
|
|
|
local_host_only, ADDRTYPE_IPV6);
|
|
|
|
|
|
|
|
if (other) {
|
|
|
|
if (!other->error) {
|
|
|
|
other->parent = ret;
|
|
|
|
ret->child = other;
|
|
|
|
} else {
|
|
|
|
sfree(other);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2001-08-08 20:44:35 +00:00
|
|
|
return (Socket) ret;
|
|
|
|
}
|
|
|
|
|
2001-05-06 14:35:20 +00:00
|
|
|
static void sk_tcp_close(Socket sock)
|
|
|
|
{
|
2001-01-22 11:34:52 +00:00
|
|
|
extern char *do_select(SOCKET skt, int startup);
|
2001-03-13 10:22:45 +00:00
|
|
|
Actual_Socket s = (Actual_Socket) sock;
|
2001-01-22 11:34:52 +00:00
|
|
|
|
2005-01-08 14:45:26 +00:00
|
|
|
if (s->child)
|
|
|
|
sk_tcp_close((Socket)s->child);
|
|
|
|
|
2000-10-23 11:55:11 +00:00
|
|
|
del234(sktree, s);
|
|
|
|
do_select(s->s, 0);
|
2003-10-12 13:46:12 +00:00
|
|
|
p_closesocket(s->s);
|
2005-01-16 14:29:34 +00:00
|
|
|
if (s->addr)
|
|
|
|
sk_addr_free(s->addr);
|
2000-12-12 10:33:13 +00:00
|
|
|
sfree(s);
|
2000-10-23 11:55:11 +00:00
|
|
|
}
|
|
|
|
|
2013-08-17 16:06:27 +00:00
|
|
|
/*
|
|
|
|
* Deal with socket errors detected in try_send().
|
|
|
|
*/
|
|
|
|
static void socket_error_callback(void *vs)
|
|
|
|
{
|
|
|
|
Actual_Socket s = (Actual_Socket)vs;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Just in case other socket work has caused this socket to vanish
|
|
|
|
* or become somehow non-erroneous before this callback arrived...
|
|
|
|
*/
|
|
|
|
if (!find234(sktree, s, NULL) || !s->pending_error)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* An error has occurred on this socket. Pass it to the plug.
|
|
|
|
*/
|
2013-10-09 18:36:56 +00:00
|
|
|
plug_closing(s->plug, winsock_error_string(s->pending_error),
|
|
|
|
s->pending_error, 0);
|
2013-08-17 16:06:27 +00:00
|
|
|
}
|
|
|
|
|
2000-10-23 11:55:11 +00:00
|
|
|
/*
|
|
|
|
* The function which tries to send on a socket once it's deemed
|
|
|
|
* writable.
|
|
|
|
*/
|
2001-05-06 14:35:20 +00:00
|
|
|
void try_send(Actual_Socket s)
|
|
|
|
{
|
2001-08-25 17:09:23 +00:00
|
|
|
while (s->sending_oob || bufchain_size(&s->output_data) > 0) {
|
2000-10-23 11:55:11 +00:00
|
|
|
int nsent;
|
|
|
|
DWORD err;
|
2001-08-25 17:09:23 +00:00
|
|
|
void *data;
|
2001-05-06 14:35:20 +00:00
|
|
|
int len, urgentflag;
|
|
|
|
|
|
|
|
if (s->sending_oob) {
|
|
|
|
urgentflag = MSG_OOB;
|
|
|
|
len = s->sending_oob;
|
2001-08-25 17:09:23 +00:00
|
|
|
data = &s->oobdata;
|
2001-05-06 14:35:20 +00:00
|
|
|
} else {
|
|
|
|
urgentflag = 0;
|
2001-08-25 17:09:23 +00:00
|
|
|
bufchain_prefix(&s->output_data, &data, &len);
|
2001-05-06 14:35:20 +00:00
|
|
|
}
|
2003-10-12 13:46:12 +00:00
|
|
|
nsent = p_send(s->s, data, len, urgentflag);
|
2001-05-06 14:35:20 +00:00
|
|
|
noise_ultralight(nsent);
|
2000-10-23 11:55:11 +00:00
|
|
|
if (nsent <= 0) {
|
2003-10-12 13:46:12 +00:00
|
|
|
err = (nsent < 0 ? p_WSAGetLastError() : 0);
|
2001-09-05 22:04:19 +00:00
|
|
|
if ((err < WSABASEERR && nsent < 0) || err == WSAEWOULDBLOCK) {
|
2001-03-15 13:25:48 +00:00
|
|
|
/*
|
|
|
|
* Perfectly normal: we've sent all we can for the moment.
|
|
|
|
*
|
2001-09-05 22:04:19 +00:00
|
|
|
* (Some WinSock send() implementations can return
|
|
|
|
* <0 but leave no sensible error indication -
|
|
|
|
* WSAGetLastError() is called but returns zero or
|
|
|
|
* a small number - so we check that case and treat
|
|
|
|
* it just like WSAEWOULDBLOCK.)
|
2001-03-15 13:25:48 +00:00
|
|
|
*/
|
2000-10-23 11:55:11 +00:00
|
|
|
s->writable = FALSE;
|
2001-05-06 14:35:20 +00:00
|
|
|
return;
|
2000-10-23 11:55:11 +00:00
|
|
|
} else if (nsent == 0 ||
|
2001-05-06 14:35:20 +00:00
|
|
|
err == WSAECONNABORTED || err == WSAECONNRESET) {
|
|
|
|
/*
|
2001-10-28 09:57:47 +00:00
|
|
|
* If send() returns CONNABORTED or CONNRESET, we
|
|
|
|
* unfortunately can't just call plug_closing(),
|
|
|
|
* because it's quite likely that we're currently
|
|
|
|
* _in_ a call from the code we'd be calling back
|
|
|
|
* to, so we'd have to make half the SSH code
|
|
|
|
* reentrant. Instead we flag a pending error on
|
|
|
|
* the socket, to be dealt with (by calling
|
|
|
|
* plug_closing()) at some suitable future moment.
|
2001-05-06 14:35:20 +00:00
|
|
|
*/
|
2001-10-28 09:57:47 +00:00
|
|
|
s->pending_error = err;
|
2013-08-17 16:06:27 +00:00
|
|
|
queue_toplevel_callback(socket_error_callback, s);
|
2001-10-28 09:57:47 +00:00
|
|
|
return;
|
2000-10-23 11:55:11 +00:00
|
|
|
} else {
|
2002-10-26 12:58:13 +00:00
|
|
|
/* We're inside the Windows frontend here, so we know
|
|
|
|
* that the frontend handle is unnecessary. */
|
|
|
|
logevent(NULL, winsock_error_string(err));
|
2002-03-23 18:04:27 +00:00
|
|
|
fatalbox("%s", winsock_error_string(err));
|
2000-10-23 11:55:11 +00:00
|
|
|
}
|
|
|
|
} else {
|
2001-08-25 17:09:23 +00:00
|
|
|
if (s->sending_oob) {
|
|
|
|
if (nsent < len) {
|
|
|
|
memmove(s->oobdata, s->oobdata+nsent, len-nsent);
|
|
|
|
s->sending_oob = len - nsent;
|
|
|
|
} else {
|
|
|
|
s->sending_oob = 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
bufchain_consume(&s->output_data, nsent);
|
2000-10-23 11:55:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-09-13 11:44:03 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If we reach here, we've finished sending everything we might
|
|
|
|
* have needed to send. Send EOF, if we need to.
|
|
|
|
*/
|
|
|
|
if (s->outgoingeof == EOF_PENDING) {
|
|
|
|
p_shutdown(s->s, SD_SEND);
|
|
|
|
s->outgoingeof = EOF_SENT;
|
|
|
|
}
|
2000-10-23 11:55:11 +00:00
|
|
|
}
|
|
|
|
|
2003-01-10 18:33:35 +00:00
|
|
|
static int sk_tcp_write(Socket sock, const char *buf, int len)
|
2001-05-06 14:35:20 +00:00
|
|
|
{
|
2001-03-13 10:22:45 +00:00
|
|
|
Actual_Socket s = (Actual_Socket) sock;
|
|
|
|
|
2011-09-13 11:44:03 +00:00
|
|
|
assert(s->outgoingeof == EOF_NO);
|
|
|
|
|
2000-10-23 11:55:11 +00:00
|
|
|
/*
|
|
|
|
* Add the data to the buffer list on the socket.
|
|
|
|
*/
|
2001-08-25 17:09:23 +00:00
|
|
|
bufchain_add(&s->output_data, buf, len);
|
2000-10-23 11:55:11 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Now try sending from the start of the buffer list.
|
|
|
|
*/
|
|
|
|
if (s->writable)
|
|
|
|
try_send(s);
|
2001-08-25 17:09:23 +00:00
|
|
|
|
|
|
|
return bufchain_size(&s->output_data);
|
2000-10-23 11:55:11 +00:00
|
|
|
}
|
|
|
|
|
2003-01-10 18:33:35 +00:00
|
|
|
static int sk_tcp_write_oob(Socket sock, const char *buf, int len)
|
2001-05-06 14:35:20 +00:00
|
|
|
{
|
2001-03-13 10:22:45 +00:00
|
|
|
Actual_Socket s = (Actual_Socket) sock;
|
|
|
|
|
2011-09-13 11:44:03 +00:00
|
|
|
assert(s->outgoingeof == EOF_NO);
|
|
|
|
|
2000-10-23 11:55:11 +00:00
|
|
|
/*
|
|
|
|
* Replace the buffer list on the socket with the data.
|
|
|
|
*/
|
2001-08-25 17:09:23 +00:00
|
|
|
bufchain_clear(&s->output_data);
|
|
|
|
assert(len <= sizeof(s->oobdata));
|
|
|
|
memcpy(s->oobdata, buf, len);
|
2000-10-23 11:55:11 +00:00
|
|
|
s->sending_oob = len;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now try sending from the start of the buffer list.
|
|
|
|
*/
|
|
|
|
if (s->writable)
|
|
|
|
try_send(s);
|
2001-08-25 17:09:23 +00:00
|
|
|
|
|
|
|
return s->sending_oob;
|
2000-10-23 11:55:11 +00:00
|
|
|
}
|
|
|
|
|
2011-09-13 11:44:03 +00:00
|
|
|
static void sk_tcp_write_eof(Socket sock)
|
|
|
|
{
|
|
|
|
Actual_Socket s = (Actual_Socket) sock;
|
|
|
|
|
|
|
|
assert(s->outgoingeof == EOF_NO);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Mark the socket as pending outgoing EOF.
|
|
|
|
*/
|
|
|
|
s->outgoingeof = EOF_PENDING;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now try sending from the start of the buffer list.
|
|
|
|
*/
|
|
|
|
if (s->writable)
|
|
|
|
try_send(s);
|
|
|
|
}
|
|
|
|
|
2001-05-06 14:35:20 +00:00
|
|
|
int select_result(WPARAM wParam, LPARAM lParam)
|
|
|
|
{
|
2001-01-29 15:10:56 +00:00
|
|
|
int ret, open;
|
2000-10-23 11:55:11 +00:00
|
|
|
DWORD err;
|
2001-04-16 12:25:03 +00:00
|
|
|
char buf[20480]; /* nice big buffer for plenty of speed */
|
2001-03-13 10:22:45 +00:00
|
|
|
Actual_Socket s;
|
2000-10-24 10:47:49 +00:00
|
|
|
u_long atmark;
|
2000-10-23 11:55:11 +00:00
|
|
|
|
|
|
|
/* wParam is the socket itself */
|
2002-12-08 11:00:47 +00:00
|
|
|
|
2003-01-09 19:26:12 +00:00
|
|
|
if (wParam == 0)
|
|
|
|
return 1; /* boggle */
|
2002-12-08 11:00:47 +00:00
|
|
|
|
2001-05-06 14:35:20 +00:00
|
|
|
s = find234(sktree, (void *) wParam, cmpforsearch);
|
2000-10-23 11:55:11 +00:00
|
|
|
if (!s)
|
|
|
|
return 1; /* boggle */
|
|
|
|
|
|
|
|
if ((err = WSAGETSELECTERROR(lParam)) != 0) {
|
2001-05-06 14:35:20 +00:00
|
|
|
/*
|
|
|
|
* An error has occurred on this socket. Pass it to the
|
|
|
|
* plug.
|
|
|
|
*/
|
2005-01-16 14:29:34 +00:00
|
|
|
if (s->addr) {
|
|
|
|
plug_log(s->plug, 1, s->addr, s->port,
|
|
|
|
winsock_error_string(err), err);
|
2008-11-08 16:45:45 +00:00
|
|
|
while (s->addr && sk_nextaddr(s->addr, &s->step)) {
|
2005-01-16 14:29:34 +00:00
|
|
|
err = try_connect(s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (err != 0)
|
|
|
|
return plug_closing(s->plug, winsock_error_string(err), err, 0);
|
|
|
|
else
|
|
|
|
return 1;
|
2000-10-23 11:55:11 +00:00
|
|
|
}
|
|
|
|
|
2000-10-23 15:20:05 +00:00
|
|
|
noise_ultralight(lParam);
|
|
|
|
|
2000-10-23 11:55:11 +00:00
|
|
|
switch (WSAGETSELECTEVENT(lParam)) {
|
2001-09-07 22:39:01 +00:00
|
|
|
case FD_CONNECT:
|
|
|
|
s->connected = s->writable = 1;
|
2005-01-16 14:29:34 +00:00
|
|
|
/*
|
|
|
|
* Once a socket is connected, we can stop falling
|
|
|
|
* back through the candidate addresses to connect
|
|
|
|
* to.
|
|
|
|
*/
|
|
|
|
if (s->addr) {
|
|
|
|
sk_addr_free(s->addr);
|
|
|
|
s->addr = NULL;
|
|
|
|
}
|
2001-09-07 22:39:01 +00:00
|
|
|
break;
|
2000-10-23 11:55:11 +00:00
|
|
|
case FD_READ:
|
2001-08-08 20:44:35 +00:00
|
|
|
/* In the case the socket is still frozen, we don't even bother */
|
2001-08-25 17:09:23 +00:00
|
|
|
if (s->frozen) {
|
|
|
|
s->frozen_readable = 1;
|
2001-08-08 20:44:35 +00:00
|
|
|
break;
|
2001-08-25 17:09:23 +00:00
|
|
|
}
|
2001-08-08 20:44:35 +00:00
|
|
|
|
2001-05-06 14:35:20 +00:00
|
|
|
/*
|
|
|
|
* We have received data on the socket. For an oobinline
|
|
|
|
* socket, this might be data _before_ an urgent pointer,
|
|
|
|
* in which case we send it to the back end with type==1
|
|
|
|
* (data prior to urgent).
|
|
|
|
*/
|
|
|
|
if (s->oobinline) {
|
|
|
|
atmark = 1;
|
2003-10-12 13:46:12 +00:00
|
|
|
p_ioctlsocket(s->s, SIOCATMARK, &atmark);
|
2001-05-06 14:35:20 +00:00
|
|
|
/*
|
|
|
|
* Avoid checking the return value from ioctlsocket(),
|
|
|
|
* on the grounds that some WinSock wrappers don't
|
|
|
|
* support it. If it does nothing, we get atmark==1,
|
|
|
|
* which is equivalent to `no OOB pending', so the
|
|
|
|
* effect will be to non-OOB-ify any OOB data.
|
|
|
|
*/
|
|
|
|
} else
|
|
|
|
atmark = 1;
|
2001-02-01 14:11:04 +00:00
|
|
|
|
2003-10-12 13:46:12 +00:00
|
|
|
ret = p_recv(s->s, buf, sizeof(buf), 0);
|
2001-05-06 14:35:20 +00:00
|
|
|
noise_ultralight(ret);
|
2000-10-23 11:55:11 +00:00
|
|
|
if (ret < 0) {
|
2003-10-12 13:46:12 +00:00
|
|
|
err = p_WSAGetLastError();
|
2000-10-23 11:55:11 +00:00
|
|
|
if (err == WSAEWOULDBLOCK) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (ret < 0) {
|
2001-05-06 14:35:20 +00:00
|
|
|
return plug_closing(s->plug, winsock_error_string(err), err,
|
|
|
|
0);
|
2001-03-13 10:22:45 +00:00
|
|
|
} else if (0 == ret) {
|
2001-05-06 14:35:20 +00:00
|
|
|
return plug_closing(s->plug, NULL, 0, 0);
|
2000-10-23 11:55:11 +00:00
|
|
|
} else {
|
2001-05-06 14:35:20 +00:00
|
|
|
return plug_receive(s->plug, atmark ? 0 : 1, buf, ret);
|
2000-10-23 11:55:11 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case FD_OOB:
|
2001-05-06 14:35:20 +00:00
|
|
|
/*
|
|
|
|
* This will only happen on a non-oobinline socket. It
|
|
|
|
* indicates that we can immediately perform an OOB read
|
|
|
|
* and get back OOB data, which we will send to the back
|
|
|
|
* end with type==2 (urgent data).
|
|
|
|
*/
|
2003-10-12 13:46:12 +00:00
|
|
|
ret = p_recv(s->s, buf, sizeof(buf), MSG_OOB);
|
2001-05-06 14:35:20 +00:00
|
|
|
noise_ultralight(ret);
|
|
|
|
if (ret <= 0) {
|
2002-03-23 18:04:27 +00:00
|
|
|
char *str = (ret == 0 ? "Internal networking trouble" :
|
2003-10-12 13:46:12 +00:00
|
|
|
winsock_error_string(p_WSAGetLastError()));
|
2002-10-26 12:58:13 +00:00
|
|
|
/* We're inside the Windows frontend here, so we know
|
|
|
|
* that the frontend handle is unnecessary. */
|
|
|
|
logevent(NULL, str);
|
2002-03-23 18:04:27 +00:00
|
|
|
fatalbox("%s", str);
|
2001-05-06 14:35:20 +00:00
|
|
|
} else {
|
|
|
|
return plug_receive(s->plug, 2, buf, ret);
|
|
|
|
}
|
|
|
|
break;
|
2000-10-23 11:55:11 +00:00
|
|
|
case FD_WRITE:
|
2001-08-25 17:09:23 +00:00
|
|
|
{
|
|
|
|
int bufsize_before, bufsize_after;
|
|
|
|
s->writable = 1;
|
|
|
|
bufsize_before = s->sending_oob + bufchain_size(&s->output_data);
|
|
|
|
try_send(s);
|
|
|
|
bufsize_after = s->sending_oob + bufchain_size(&s->output_data);
|
|
|
|
if (bufsize_after < bufsize_before)
|
|
|
|
plug_sent(s->plug, bufsize_after);
|
|
|
|
}
|
2000-10-23 11:55:11 +00:00
|
|
|
break;
|
|
|
|
case FD_CLOSE:
|
2001-01-29 15:10:56 +00:00
|
|
|
/* Signal a close on the socket. First read any outstanding data. */
|
2001-05-06 14:35:20 +00:00
|
|
|
open = 1;
|
|
|
|
do {
|
2003-10-12 13:46:12 +00:00
|
|
|
ret = p_recv(s->s, buf, sizeof(buf), 0);
|
2001-05-06 14:35:20 +00:00
|
|
|
if (ret < 0) {
|
2003-10-12 13:46:12 +00:00
|
|
|
err = p_WSAGetLastError();
|
2001-05-06 14:35:20 +00:00
|
|
|
if (err == WSAEWOULDBLOCK)
|
|
|
|
break;
|
|
|
|
return plug_closing(s->plug, winsock_error_string(err),
|
|
|
|
err, 0);
|
|
|
|
} else {
|
|
|
|
if (ret)
|
|
|
|
open &= plug_receive(s->plug, 0, buf, ret);
|
|
|
|
else
|
|
|
|
open &= plug_closing(s->plug, NULL, 0, 0);
|
2001-03-13 10:22:45 +00:00
|
|
|
}
|
2001-01-29 15:10:56 +00:00
|
|
|
} while (ret > 0);
|
2001-05-06 14:35:20 +00:00
|
|
|
return open;
|
2001-08-08 20:44:35 +00:00
|
|
|
case FD_ACCEPT:
|
|
|
|
{
|
2004-12-30 16:45:11 +00:00
|
|
|
#ifdef NO_IPV6
|
2001-10-12 19:32:13 +00:00
|
|
|
struct sockaddr_in isa;
|
2004-12-30 16:45:11 +00:00
|
|
|
#else
|
|
|
|
struct sockaddr_storage isa;
|
|
|
|
#endif
|
|
|
|
int addrlen = sizeof(isa);
|
2001-08-27 15:59:37 +00:00
|
|
|
SOCKET t; /* socket of connection */
|
2013-11-17 14:03:55 +00:00
|
|
|
accept_ctx_t actx;
|
2001-08-27 15:59:37 +00:00
|
|
|
|
2004-12-30 16:45:11 +00:00
|
|
|
memset(&isa, 0, sizeof(isa));
|
2001-08-27 15:59:37 +00:00
|
|
|
err = 0;
|
2003-10-12 13:46:12 +00:00
|
|
|
t = p_accept(s->s,(struct sockaddr *)&isa,&addrlen);
|
2001-08-27 15:59:37 +00:00
|
|
|
if (t == INVALID_SOCKET)
|
|
|
|
{
|
2003-10-12 13:46:12 +00:00
|
|
|
err = p_WSAGetLastError();
|
2001-08-27 15:59:37 +00:00
|
|
|
if (err == WSATRY_AGAIN)
|
|
|
|
break;
|
|
|
|
}
|
2013-11-17 14:03:55 +00:00
|
|
|
|
|
|
|
actx.p = (void *)t;
|
|
|
|
|
2004-12-30 16:45:11 +00:00
|
|
|
#ifndef NO_IPV6
|
|
|
|
if (isa.ss_family == AF_INET &&
|
|
|
|
s->localhost_only &&
|
2007-01-08 19:38:39 +00:00
|
|
|
!ipv4_is_local_addr(((struct sockaddr_in *)&isa)->sin_addr))
|
2004-12-30 16:45:11 +00:00
|
|
|
#else
|
2007-01-08 19:38:39 +00:00
|
|
|
if (s->localhost_only && !ipv4_is_local_addr(isa.sin_addr))
|
2004-12-30 16:45:11 +00:00
|
|
|
#endif
|
2007-01-08 19:38:39 +00:00
|
|
|
{
|
2003-10-12 13:46:12 +00:00
|
|
|
p_closesocket(t); /* dodgy WinSock let nonlocal through */
|
2013-11-17 14:03:55 +00:00
|
|
|
} else if (plug_accepting(s->plug, sk_tcp_accept, actx)) {
|
2003-10-12 13:46:12 +00:00
|
|
|
p_closesocket(t); /* denied or error */
|
2001-08-27 15:59:37 +00:00
|
|
|
}
|
2001-08-08 20:44:35 +00:00
|
|
|
}
|
2000-10-23 11:55:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Special error values are returned from sk_namelookup and sk_new
|
|
|
|
* if there's a problem. These functions extract an error message,
|
|
|
|
* or return NULL if there's no problem.
|
|
|
|
*/
|
2003-05-04 14:18:18 +00:00
|
|
|
const char *sk_addr_error(SockAddr addr)
|
2001-05-06 14:35:20 +00:00
|
|
|
{
|
2000-10-23 11:55:11 +00:00
|
|
|
return addr->error;
|
|
|
|
}
|
2003-05-04 14:18:18 +00:00
|
|
|
static const char *sk_tcp_socket_error(Socket sock)
|
2001-05-06 14:35:20 +00:00
|
|
|
{
|
2001-03-13 10:22:45 +00:00
|
|
|
Actual_Socket s = (Actual_Socket) sock;
|
2000-10-23 11:55:11 +00:00
|
|
|
return s->error;
|
|
|
|
}
|
|
|
|
|
2002-03-23 17:47:21 +00:00
|
|
|
static void sk_tcp_set_frozen(Socket sock, int is_frozen)
|
2001-08-08 20:44:35 +00:00
|
|
|
{
|
|
|
|
Actual_Socket s = (Actual_Socket) sock;
|
2001-08-25 17:09:23 +00:00
|
|
|
if (s->frozen == is_frozen)
|
|
|
|
return;
|
2001-08-08 20:44:35 +00:00
|
|
|
s->frozen = is_frozen;
|
2005-03-18 19:47:21 +00:00
|
|
|
if (!is_frozen) {
|
|
|
|
do_select(s->s, 1);
|
|
|
|
if (s->frozen_readable) {
|
|
|
|
char c;
|
|
|
|
p_recv(s->s, &c, 1, MSG_PEEK);
|
|
|
|
}
|
2001-08-08 20:44:35 +00:00
|
|
|
}
|
2001-08-25 17:09:23 +00:00
|
|
|
s->frozen_readable = 0;
|
2001-08-08 20:44:35 +00:00
|
|
|
}
|
|
|
|
|
2007-01-08 19:38:39 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-10-23 11:55:11 +00:00
|
|
|
/*
|
|
|
|
* For Plink: enumerate all sockets currently active.
|
|
|
|
*/
|
2001-05-06 14:35:20 +00:00
|
|
|
SOCKET first_socket(int *state)
|
|
|
|
{
|
2001-04-16 17:18:24 +00:00
|
|
|
Actual_Socket s;
|
|
|
|
*state = 0;
|
|
|
|
s = index234(sktree, (*state)++);
|
2000-10-23 11:55:11 +00:00
|
|
|
return s ? s->s : INVALID_SOCKET;
|
|
|
|
}
|
2001-05-06 14:35:20 +00:00
|
|
|
|
|
|
|
SOCKET next_socket(int *state)
|
|
|
|
{
|
2001-04-16 17:18:24 +00:00
|
|
|
Actual_Socket s = index234(sktree, (*state)++);
|
2000-10-23 11:55:11 +00:00
|
|
|
return s ? s->s : INVALID_SOCKET;
|
|
|
|
}
|
2002-10-30 17:57:31 +00:00
|
|
|
|
2004-11-27 13:20:21 +00:00
|
|
|
extern int socket_writable(SOCKET skt)
|
|
|
|
{
|
|
|
|
Actual_Socket s = find234(sktree, (void *)skt, cmpforsearch);
|
|
|
|
|
|
|
|
if (s)
|
|
|
|
return bufchain_size(&s->output_data) > 0;
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-10-30 17:57:31 +00:00
|
|
|
int net_service_lookup(char *service)
|
|
|
|
{
|
|
|
|
struct servent *se;
|
2003-10-12 13:46:12 +00:00
|
|
|
se = p_getservbyname(service, NULL);
|
2002-10-30 17:57:31 +00:00
|
|
|
if (se != NULL)
|
2003-10-12 13:46:12 +00:00
|
|
|
return p_ntohs(se->s_port);
|
2002-10-30 17:57:31 +00:00
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
2004-05-31 14:01:52 +00:00
|
|
|
|
Since r8305, Unix PuTTY has always "upgraded" an X11 display like "localhost:0"
to a Unix-domain socket. This typically works fine when PuTTY is run on the
same machine as the X server, but it's broken multi-hop X forwarding through
OpenSSH; when OpenSSH creates a proxy X server "localhost:10", it only listens
on TCP, not on a Unix-domain socket.
Instead, when deciding on the details of the display, we actively probe to see
if there's a Unix-domain socket we can use instead, and only use it if it's
there, falling back to the specified IP "localhost" if not.
Independently, when looking for local auth details in Xauthority for a
"localhost" TCP display, we prefer a matching Unix-domain entry, but will fall
back to an IP "localhost" entry (which would be unusual, but we don't trust a
Windows X server not to do it) -- this is a generalisation of the special case
added in r2538 (but removed in r8305, as the automatic upgrade masked the need
for it).
(This is now done in platform-independent code, so a side-effect is that
get_hostname() is now part of the networking abstraction on all platforms.)
[originally from svn r8462]
[r2538 == fda998324345ba50a913655754303ce8f0a4cfde]
[r8305 == ca6fc3a4daf51166a15693feffc967bee9e3f59a]
2009-02-24 01:01:23 +00:00
|
|
|
char *get_hostname(void)
|
|
|
|
{
|
|
|
|
int len = 128;
|
|
|
|
char *hostname = NULL;
|
|
|
|
do {
|
|
|
|
len *= 2;
|
|
|
|
hostname = sresize(hostname, len, char);
|
|
|
|
if (p_gethostname(hostname, len) < 0) {
|
|
|
|
sfree(hostname);
|
|
|
|
hostname = NULL;
|
|
|
|
break;
|
|
|
|
}
|
2011-07-12 18:13:33 +00:00
|
|
|
} while (strlen(hostname) >= (size_t)(len-1));
|
Since r8305, Unix PuTTY has always "upgraded" an X11 display like "localhost:0"
to a Unix-domain socket. This typically works fine when PuTTY is run on the
same machine as the X server, but it's broken multi-hop X forwarding through
OpenSSH; when OpenSSH creates a proxy X server "localhost:10", it only listens
on TCP, not on a Unix-domain socket.
Instead, when deciding on the details of the display, we actively probe to see
if there's a Unix-domain socket we can use instead, and only use it if it's
there, falling back to the specified IP "localhost" if not.
Independently, when looking for local auth details in Xauthority for a
"localhost" TCP display, we prefer a matching Unix-domain entry, but will fall
back to an IP "localhost" entry (which would be unusual, but we don't trust a
Windows X server not to do it) -- this is a generalisation of the special case
added in r2538 (but removed in r8305, as the automatic upgrade masked the need
for it).
(This is now done in platform-independent code, so a side-effect is that
get_hostname() is now part of the networking abstraction on all platforms.)
[originally from svn r8462]
[r2538 == fda998324345ba50a913655754303ce8f0a4cfde]
[r8305 == ca6fc3a4daf51166a15693feffc967bee9e3f59a]
2009-02-24 01:01:23 +00:00
|
|
|
return hostname;
|
|
|
|
}
|
|
|
|
|
2008-05-28 19:23:57 +00:00
|
|
|
SockAddr platform_get_x11_unix_address(const char *display, int displaynum,
|
|
|
|
char **canonicalname)
|
2004-05-31 14:01:52 +00:00
|
|
|
{
|
|
|
|
SockAddr ret = snew(struct SockAddr_tag);
|
|
|
|
memset(ret, 0, sizeof(struct SockAddr_tag));
|
|
|
|
ret->error = "unix sockets not supported on this platform";
|
2008-11-08 16:58:55 +00:00
|
|
|
ret->refcount = 1;
|
2004-05-31 14:01:52 +00:00
|
|
|
return ret;
|
|
|
|
}
|