⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 winnet.c

📁 putty
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 * Windows networking abstraction.
 *
 * For the IPv6 code in here I am indebted to Jeroen Massar and
 * unfix.org.
 */

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#define DEFINE_PLUG_METHOD_MACROS
#include "putty.h"
#include "network.h"
#include "tree234.h"

#include <ws2tcpip.h>

#ifndef NO_IPV6
const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
#endif

#define ipv4_is_loopback(addr) \
	((p_ntohl(addr.s_addr) & 0xFF000000L) == 0x7F000000L)

/*
 * 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;

struct Socket_tag {
    const struct socket_function_table *fn;
    /* the above variable absolutely *must* be the first in this structure */
    char *error;
    SOCKET s;
    Plug plug;
    void *private_ptr;
    bufchain output_data;
    int connected;
    int writable;
    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 */
    int localhost_only;		       /* for listening sockets */
    char oobdata[1];
    int sending_oob;
    int oobinline, nodelay, keepalive, privport;
    SockAddr addr;
    int port;
    int pending_error;		       /* in case send() returns error */
    /*
     * 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;
};

struct SockAddr_tag {
    char *error;
    /* 
     * 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.
     * The hostname field is also used when the hostname has both
     * an IPv6 and IPv4 address and the IPv6 connection attempt
     * fails. We then try the IPv4 address.
     * This 'family' should become an option in the GUI and
     * on the commandline for selecting a default protocol.
     */
    int family;
#ifndef NO_IPV6
    struct addrinfo *ais;	       /* Addresses IPv6 style. */
    struct addrinfo *ai;	       /* steps along the linked list */
#endif
    unsigned long *addresses;	       /* Addresses IPv4 style. */
    int naddresses, curraddr;
    char hostname[512];		       /* Store an unresolved host name. */
};

static tree234 *sktree;

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;
    return 0;
}

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;
    return 0;
}

#define NOTHING
#define DECL_WINSOCK_FUNCTION(linkage, rettype, name, params) \
    typedef rettype (WINAPI *t_##name) params; \
    linkage t_##name p_##name
#define GET_WINSOCK_FUNCTION(module, name) \
    p_##name = module ? (t_##name) GetProcAddress(module, #name) : NULL

DECL_WINSOCK_FUNCTION(NOTHING, int, WSAAsyncSelect,
		      (SOCKET, HWND, u_int, long));
DECL_WINSOCK_FUNCTION(NOTHING, int, WSAEventSelect, (SOCKET, WSAEVENT, long));
DECL_WINSOCK_FUNCTION(NOTHING, int, select,
		      (int, fd_set FAR *, fd_set FAR *,
		       fd_set FAR *, const struct timeval FAR *));
DECL_WINSOCK_FUNCTION(NOTHING, int, WSAGetLastError, (void));
DECL_WINSOCK_FUNCTION(NOTHING, int, WSAEnumNetworkEvents,
		      (SOCKET, WSAEVENT, LPWSANETWORKEVENTS));
DECL_WINSOCK_FUNCTION(static, int, WSAStartup, (WORD, LPWSADATA));
DECL_WINSOCK_FUNCTION(static, int, WSACleanup, (void));
DECL_WINSOCK_FUNCTION(static, int, closesocket, (SOCKET));
DECL_WINSOCK_FUNCTION(static, u_long, ntohl, (u_long));
DECL_WINSOCK_FUNCTION(static, u_long, htonl, (u_long));
DECL_WINSOCK_FUNCTION(static, u_short, htons, (u_short));
DECL_WINSOCK_FUNCTION(static, u_short, ntohs, (u_short));
DECL_WINSOCK_FUNCTION(static, struct hostent FAR *, gethostbyname,
		      (const char FAR *));
DECL_WINSOCK_FUNCTION(static, struct servent FAR *, getservbyname,
		      (const char FAR *, const char FAR *));
DECL_WINSOCK_FUNCTION(static, unsigned long, inet_addr, (const char FAR *));
DECL_WINSOCK_FUNCTION(static, char FAR *, inet_ntoa, (struct in_addr));
DECL_WINSOCK_FUNCTION(static, int, connect,
		      (SOCKET, const struct sockaddr FAR *, int));
DECL_WINSOCK_FUNCTION(static, int, bind,
		      (SOCKET, const struct sockaddr FAR *, int));
DECL_WINSOCK_FUNCTION(static, int, setsockopt,
		      (SOCKET, int, int, const char FAR *, int));
DECL_WINSOCK_FUNCTION(static, SOCKET, socket, (int, int, int));
DECL_WINSOCK_FUNCTION(static, int, listen, (SOCKET, int));
DECL_WINSOCK_FUNCTION(static, int, send, (SOCKET, const char FAR *, int, int));
DECL_WINSOCK_FUNCTION(static, int, ioctlsocket,
		      (SOCKET, long, u_long FAR *));
DECL_WINSOCK_FUNCTION(static, SOCKET, accept,
		      (SOCKET, struct sockaddr FAR *, int FAR *));
DECL_WINSOCK_FUNCTION(static, int, recv, (SOCKET, char FAR *, int, int));
DECL_WINSOCK_FUNCTION(static, int, WSAIoctl,
		      (SOCKET, DWORD, LPVOID, DWORD, LPVOID, DWORD,
		       LPDWORD, LPWSAOVERLAPPED,
		       LPWSAOVERLAPPED_COMPLETION_ROUTINE));
#ifndef NO_IPV6
DECL_WINSOCK_FUNCTION(static, int, getaddrinfo,
		      (const char *nodename, const char *servname,
		       const struct addrinfo *hints, struct addrinfo **res));
DECL_WINSOCK_FUNCTION(static, void, freeaddrinfo, (struct addrinfo *res));
DECL_WINSOCK_FUNCTION(static, int, getnameinfo,
		      (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 = NULL;
static WSADATA wsadata;
#ifndef NO_IPV6
static HMODULE winsock2_module = NULL;
static HMODULE wship6_module = NULL;
#endif

int sk_startup(int hi, int lo)
{
    WORD winsock_ver;

    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");
    }
    if (!winsock_module)
	fatalbox("Unable to load any WinSock library");

#ifndef NO_IPV6
    /* 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, WSAEventSelect);
    GET_WINSOCK_FUNCTION(winsock_module, select);
    GET_WINSOCK_FUNCTION(winsock_module, WSAGetLastError);
    GET_WINSOCK_FUNCTION(winsock_module, WSAEnumNetworkEvents);
    GET_WINSOCK_FUNCTION(winsock_module, WSAStartup);
    GET_WINSOCK_FUNCTION(winsock_module, WSACleanup);
    GET_WINSOCK_FUNCTION(winsock_module, closesocket);
    GET_WINSOCK_FUNCTION(winsock_module, ntohl);
    GET_WINSOCK_FUNCTION(winsock_module, htonl);
    GET_WINSOCK_FUNCTION(winsock_module, htons);
    GET_WINSOCK_FUNCTION(winsock_module, ntohs);
    GET_WINSOCK_FUNCTION(winsock_module, gethostbyname);
    GET_WINSOCK_FUNCTION(winsock_module, getservbyname);
    GET_WINSOCK_FUNCTION(winsock_module, inet_addr);
    GET_WINSOCK_FUNCTION(winsock_module, inet_ntoa);
    GET_WINSOCK_FUNCTION(winsock_module, connect);
    GET_WINSOCK_FUNCTION(winsock_module, bind);
    GET_WINSOCK_FUNCTION(winsock_module, setsockopt);
    GET_WINSOCK_FUNCTION(winsock_module, socket);
    GET_WINSOCK_FUNCTION(winsock_module, listen);
    GET_WINSOCK_FUNCTION(winsock_module, send);
    GET_WINSOCK_FUNCTION(winsock_module, ioctlsocket);
    GET_WINSOCK_FUNCTION(winsock_module, accept);
    GET_WINSOCK_FUNCTION(winsock_module, recv);
    GET_WINSOCK_FUNCTION(winsock_module, WSAIoctl);

    /* 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");
    }

    sktree = newtree234(cmpfortree);
}

void sk_cleanup(void)
{
    Actual_Socket s;
    int i;

    if (sktree) {
	for (i = 0; (s = index234(sktree, i)) != NULL; i++) {
	    p_closesocket(s->s);
	}
	freetree234(sktree);
	sktree = NULL;
    }

    p_WSACleanup();
    if (winsock_module)
	FreeLibrary(winsock_module);
#ifndef NO_IPV6
    if (wship6_module)
	FreeLibrary(wship6_module);
#endif
}

char *winsock_error_string(int error)
{
    switch (error) {
      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";
      default:
	return "Unknown network error";
    }
}

SockAddr sk_namelookup(const char *host, char **canonicalname,
		       int address_family)
{
    SockAddr ret = snew(struct SockAddr_tag);
    unsigned long a;
    struct hostent *h = NULL;
    char realhost[8192];
    int ret_family;
    int err;

    /* Clear the structure and default to IPv4. */
    memset(ret, 0, sizeof(struct SockAddr_tag));
    ret->family = (address_family == ADDRTYPE_IPV4 ? AF_INET :
#ifndef NO_IPV6
		   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 ((a = p_inet_addr(host)) == (unsigned long) INADDR_NONE) {
#ifndef NO_IPV6
	/*
	 * Use getaddrinfo when it's available
	 */
	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!)
	     */
	    if ( (h = p_gethostbyname(host)) )
		ret_family = AF_INET;
	    else
		err = p_WSAGetLastError();
	}

	if (ret_family == AF_UNSPEC) {
	    ret->error = (err == WSAENETDOWN ? "Network is down" :
			  err == WSAHOST_NOT_FOUND ? "Host does not exist" :
			  err == WSATRY_AGAIN ? "Host not found" :
#ifndef NO_IPV6
			  p_getaddrinfo&&p_gai_strerror ? p_gai_strerror(err) :
#endif
			  "gethostbyname: unknown error");
	} else {
	    ret->error = NULL;
	    ret->family = ret_family;

#ifndef NO_IPV6
	    /* If we got an address info use that... */
	    if (ret->ai) {
		/* Are we in IPv4 fallback mode? */
		/* We put the IPv4 address into the a variable so we can further-on use the IPv4 code... */
		if (ret->family == AF_INET)
		    memcpy(&a,
			   (char *) &((SOCKADDR_IN *) ret->ai->
				      ai_addr)->sin_addr, sizeof(a));

		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
#endif
	    {
		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);
		}
		ret->curraddr = 0;
		memcpy(&a, h->h_addr, sizeof(a));
		/* This way we are always sure the h->h_name is valid :) */
		strncpy(realhost, h->h_name, sizeof(realhost));
	    }
	}
    } else {
	/*
	 * This must be a numeric IPv4 address because it caused a
	 * success return from inet_addr.
	 */
	ret->addresses = snewn(1, unsigned long);
	ret->naddresses = 1;
	ret->curraddr = 0;
	ret->addresses[0] = p_ntohl(a);
	ret->family = AF_INET;
	strncpy(realhost, host, sizeof(realhost));
    }
    realhost[lenof(realhost)-1] = '\0';
    *canonicalname = snewn(1+strlen(realhost), char);
    strcpy(*canonicalname, realhost);
    return ret;
}

SockAddr sk_nonamelookup(const char *host)
{
    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;
}

int sk_nextaddr(SockAddr addr)
{
#ifndef NO_IPV6
    if (addr->ai) {
	if (addr->ai->ai_next) {
	    addr->ai = addr->ai->ai_next;
	    addr->family = addr->ai->ai_family;
	    return TRUE;
	} else
	    return FALSE;
    }
#endif
    if (addr->curraddr+1 < addr->naddresses) {
	addr->curraddr++;
	return TRUE;
    } else {
	return FALSE;
    }
}

void sk_getaddr(SockAddr addr, char *buf, int buflen)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -