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

📄 winnet.c

📁 远程登陆工具软件源码 用于远程登陆unix
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 * Windows networking abstraction.
 *
 * Due to this clean abstraction it was possible
 * to easily implement IPv6 support :)
 *
 * IPv6 patch 1 (27 October 2000) Jeroen Massar <jeroen@unfix.org>
 *  - Preliminary hacked IPv6 support.
 *    - Connecting to IPv6 address (eg fec0:4242:4242:100:2d0:b7ff:fe8f:5d42) works.
 *    - Connecting to IPv6 hostname (eg heaven.ipv6.unfix.org) works.
 *  - Compiles as either IPv4 or IPv6.
 *
 * IPv6 patch 2 (29 October 2000) Jeroen Massar <jeroen@unfix.org>
 *  - When compiled as IPv6 it also allows connecting to IPv4 hosts.
 *  - Added some more documentation.
 *
 * IPv6 patch 3 (18 November 2000) Jeroen Massar <jeroen@unfix.org>
 *  - It now supports dynamically loading the IPv6 resolver dll's.
 *    This way we should be able to distribute one (1) binary
 *    which supports both IPv4 and IPv6.
 *  - getaddrinfo() and getnameinfo() are loaded dynamicaly if possible.
 *  - in6addr_any is defined in this file so we don't need to link to wship6.lib
 *  - The patch is now more unified so that we can still
 *    remove all IPv6 support by undef'ing IPV6.
 *    But where it fallsback to IPv4 it uses the IPv4 code which is already in place...
 *  - Canonical name resolving works.
 *
 * IPv6 patch 4 (07 January 2001) Jeroen Massar <jeroen@unfix.org>
 *  - patch against CVS of today, will be submitted to the bugs list
 *    as a 'cvs diff -u' on Simon's request...
 *
 */

/*
 * Define IPV6 to have IPv6 on-the-fly-loading support.
 * This means that one doesn't have to have an IPv6 stack to use it.
 * But if an IPv6 stack is found it is used with a fallback to IPv4.
 */
/* #define IPV6 1 */

#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>
#ifdef IPV6
#include <tpipv6.h>
#endif

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

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;
    int pending_error;		       /* in case send() returns error */
};

/*
 * 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 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.
     */
    int family;
    unsigned long address;	       /* Address IPv4 style. */
#ifdef IPV6
    struct addrinfo *ai;	       /* Address IPv6 style. */
#endif
    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(name) \
    p_##name = (t_##name) GetProcAddress(winsock_module, #name)

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));

static HMODULE winsock_module;

void sk_init(void)
{
    WORD winsock_ver;
    WSADATA wsadata;

    winsock_ver = MAKEWORD(2, 0);
    winsock_module = LoadLibrary("WS2_32.DLL");
    if (!winsock_module) {
	winsock_module = LoadLibrary("WSOCK32.DLL");
	winsock_ver = MAKEWORD(1, 1);
    }
    if (!winsock_module)
	fatalbox("Unable to load any WinSock library");

    GET_WINSOCK_FUNCTION(WSAAsyncSelect);
    GET_WINSOCK_FUNCTION(WSAEventSelect);
    GET_WINSOCK_FUNCTION(select);
    GET_WINSOCK_FUNCTION(WSAGetLastError);
    GET_WINSOCK_FUNCTION(WSAEnumNetworkEvents);
    GET_WINSOCK_FUNCTION(WSAStartup);
    GET_WINSOCK_FUNCTION(WSACleanup);
    GET_WINSOCK_FUNCTION(closesocket);
    GET_WINSOCK_FUNCTION(ntohl);
    GET_WINSOCK_FUNCTION(htonl);
    GET_WINSOCK_FUNCTION(htons);
    GET_WINSOCK_FUNCTION(ntohs);
    GET_WINSOCK_FUNCTION(gethostbyname);
    GET_WINSOCK_FUNCTION(getservbyname);
    GET_WINSOCK_FUNCTION(inet_addr);
    GET_WINSOCK_FUNCTION(inet_ntoa);
    GET_WINSOCK_FUNCTION(connect);
    GET_WINSOCK_FUNCTION(bind);
    GET_WINSOCK_FUNCTION(setsockopt);
    GET_WINSOCK_FUNCTION(socket);
    GET_WINSOCK_FUNCTION(listen);
    GET_WINSOCK_FUNCTION(send);
    GET_WINSOCK_FUNCTION(ioctlsocket);
    GET_WINSOCK_FUNCTION(accept);
    GET_WINSOCK_FUNCTION(recv);
    GET_WINSOCK_FUNCTION(WSAIoctl);

    if (p_WSAStartup(winsock_ver, &wsadata)) {
	fatalbox("Unable to initialise WinSock");
    }
    if (LOBYTE(wsadata.wVersion) != LOBYTE(winsock_ver)) {
        p_WSACleanup();
	fatalbox("WinSock version is incompatible with %d.%d",
		 LOBYTE(winsock_ver), HIBYTE(winsock_ver));
    }

    sktree = newtree234(cmpfortree);
}

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);
}

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)
{
    SockAddr ret = snew(struct SockAddr_tag);
    unsigned long a;
    struct hostent *h = NULL;
    char realhost[8192];

    /* Clear the structure and default to IPv4. */
    memset(ret, 0, sizeof(struct SockAddr_tag));
    ret->family = 0;		       /* We set this one when we have resolved the host. */
    *realhost = '\0';

    if ((a = p_inet_addr(host)) == (unsigned long) INADDR_NONE) {
#ifdef IPV6

	/* Try to get the getaddrinfo() function from wship6.dll */
	/* This way one doesn't need to have IPv6 dll's to use PuTTY and
	 * it will fallback to IPv4. */
	typedef int (CALLBACK * FGETADDRINFO) (const char *nodename,
					       const char *servname,
					       const struct addrinfo *
					       hints,
					       struct addrinfo ** res);
	FGETADDRINFO fGetAddrInfo = NULL;

	HINSTANCE dllWSHIP6 = LoadLibrary("wship6.dll");
	if (dllWSHIP6)
	    fGetAddrInfo = (FGETADDRINFO) GetProcAddress(dllWSHIP6,
							 "getaddrinfo");

	/*
	 * Use fGetAddrInfo when it's available (which usually also
	 * means IPv6 is installed...)
	 */
	if (fGetAddrInfo) {
	    /*debug(("Resolving \"%s\" with getaddrinfo()  (IPv4+IPv6 capable)...\n", host)); */
	    if (fGetAddrInfo(host, NULL, NULL, &ret->ai) == 0)
		ret->family = ret->ai->ai_family;
	} else
#endif
	{
	    /*
	     * Otherwise use the IPv4-only gethostbyname...
	     * (NOTE: we don't use gethostbyname as a
	     * fallback!)
	     */
	    if (ret->family == 0) {
		/*debug(("Resolving \"%s\" with gethostbyname() (IPv4 only)...\n", host)); */
		if ( (h = p_gethostbyname(host)) )
		    ret->family = AF_INET;
	    }
	}
	/*debug(("Done resolving...(family is %d) AF_INET = %d, AF_INET6 = %d\n", ret->family, AF_INET, AF_INET6)); */

	if (ret->family == 0) {
	    DWORD err = p_WSAGetLastError();
	    ret->error = (err == WSAENETDOWN ? "Network is down" :
			  err ==
			  WSAHOST_NOT_FOUND ? "Host does not exist" : err
			  == WSATRY_AGAIN ? "Host not found" :
#ifdef IPV6
			  fGetAddrInfo ? "getaddrinfo: unknown error" :
#endif
			  "gethostbyname: unknown error");
#ifdef DEBUG
	    {
		LPVOID lpMsgBuf;
		FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
			      FORMAT_MESSAGE_FROM_SYSTEM |
			      FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err,
			      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
			      (LPTSTR) & lpMsgBuf, 0, NULL);
		/*debug(("Error %ld: %s (h=%lx)\n", err, lpMsgBuf, h)); */
		/* Free the buffer. */
		LocalFree(lpMsgBuf);
	    }
#endif
	} else {
	    ret->error = NULL;

#ifdef IPV6
	    /* If we got an address info use that... */
	    if (ret->ai) {
		typedef int (CALLBACK * FGETNAMEINFO)
		 (const struct sockaddr FAR * sa, socklen_t salen,
		  char FAR * host, size_t hostlen, char FAR * serv,
		  size_t servlen, int flags);
		FGETNAMEINFO fGetNameInfo = NULL;

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

		/* Now let's find that canonicalname... */
		if ((dllWSHIP6)
		    && (fGetNameInfo =
			(FGETNAMEINFO) GetProcAddress(dllWSHIP6,
						      "getnameinfo"))) {
		    if (fGetNameInfo
			((struct sockaddr *) ret->ai->ai_addr,
			 ret->family ==
			 AF_INET ? sizeof(SOCKADDR_IN) :
			 sizeof(SOCKADDR_IN6), realhost,
			 sizeof(realhost), NULL, 0, 0) != 0) {
			strncpy(realhost, host, sizeof(realhost));
		    }
		}
	    }
	    /* We used the IPv4-only gethostbyname()... */
	    else
#endif
	    {
		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));
	    }
	}
#ifdef IPV6
	FreeLibrary(dllWSHIP6);
#endif
    } else {
	/*
	 * This must be a numeric IPv4 address because it caused a
	 * success return from inet_addr.
	 */
	ret->family = AF_INET;
	strncpy(realhost, host, sizeof(realhost));
    }

⌨️ 快捷键说明

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