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

📄 uxnet.c

📁 大名鼎鼎的远程登录软件putty的Symbian版源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Unix networking abstraction. */#include <stdio.h>#include <stdlib.h>#include <assert.h>#include <errno.h>#include <fcntl.h>#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/ioctl.h>#include <arpa/inet.h>#include <netinet/in.h>#include <netinet/tcp.h>#include <netdb.h>#include <sys/un.h>#define DEFINE_PLUG_METHOD_MACROS#include "putty.h"#include "network.h"#include "tree234.h"#ifndef X11_UNIX_PATH# define X11_UNIX_PATH "/tmp/.X11-unix/X"#endif#define ipv4_is_loopback(addr) (inet_netof(addr) == IN_LOOPBACKNET)struct Socket_tag {    struct socket_function_table *fn;    /* the above variable absolutely *must* be the first in this structure */    const char *error;    int 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 oobpending;		       /* is there OOB data available to read? */    int oobinline;    int pending_error;		       /* in case send() returns error */    int listener;};/* * 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 {    const 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;#ifdef IPV6    struct addrinfo *ai;	       /* Address IPv6 style. */#else    unsigned long address;	       /* Address IPv4 style. */#endif    char hostname[512];		       /* Store an unresolved host name. */};static tree234 *sktree;static void uxsel_tell(Actual_Socket s);static int cmpfortree(void *av, void *bv){    Actual_Socket a = (Actual_Socket) av, b = (Actual_Socket) bv;    int as = a->s, bs = 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;    int as = *(int *)av, bs = b->s;    if (as < bs)	return -1;    if (as > bs)	return +1;    return 0;}void sk_init(void){    sktree = newtree234(cmpfortree);}void sk_cleanup(void){    Actual_Socket s;    int i;    if (sktree) {	for (i = 0; (s = index234(sktree, i)) != NULL; i++) {	    close(s->s);	}    }}const char *error_string(int error){    return strerror(error);}SockAddr sk_namelookup(const char *host, char **canonicalname){    SockAddr ret = snew(struct SockAddr_tag);#ifdef IPV6    struct addrinfo hints;    int err;#else    unsigned long a;    struct hostent *h = NULL;#endif    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';    ret->error = NULL;#ifdef IPV6    hints.ai_flags = AI_CANONNAME;    hints.ai_family = AF_UNSPEC;    hints.ai_socktype = 0;    hints.ai_protocol = 0;    hints.ai_addrlen = 0;    hints.ai_addr = NULL;    hints.ai_canonname = NULL;    hints.ai_next = NULL;    err = getaddrinfo(host, NULL, NULL, &ret->ai);    if (err != 0) {	ret->error = gai_strerror(err);	return ret;    }    ret->family = ret->ai->ai_family;    *realhost = '\0';    if (ret->ai->ai_canonname != NULL)	strncat(realhost, ret->ai->ai_canonname, sizeof(realhost) - 1);    else	strncat(realhost, host, sizeof(realhost) - 1);#else    if ((a = inet_addr(host)) == (unsigned long) INADDR_NONE) {	/*	 * 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 = gethostbyname(host)) )			ret->family = AF_INET;	}	if (ret->family == 0) {		ret->error = (h_errno == HOST_NOT_FOUND ||		    h_errno == NO_DATA ||		    h_errno == NO_ADDRESS ? "Host does not exist" :		    h_errno == TRY_AGAIN ?		    "Temporary name service failure" :		    "gethostbyname: unknown error");		return ret;	}	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->family = AF_INET;	strncpy(realhost, host, sizeof(realhost));    }    ret->address = ntohl(a);#endif    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;    strncpy(ret->hostname, host, lenof(ret->hostname));    ret->hostname[lenof(ret->hostname)-1] = '\0';    return ret;}void sk_getaddr(SockAddr addr, char *buf, int buflen){    if (addr->family == AF_UNSPEC) {	strncpy(buf, addr->hostname, buflen);	buf[buflen-1] = '\0';    } else {#ifdef IPV6	if (getnameinfo(addr->ai->ai_addr, addr->ai->ai_addrlen, buf, buflen,			NULL, 0, NI_NUMERICHOST) != 0) {	    buf[0] = '\0';	    strncat(buf, "<unknown>", buflen - 1);	}#else	struct in_addr a;	assert(addr->family == AF_INET);	a.s_addr = htonl(addr->address);	strncpy(buf, inet_ntoa(a), buflen);	buf[buflen-1] = '\0';#endif    }}int sk_hostname_is_local(char *name){    return !strcmp(name, "localhost");}int sk_address_is_local(SockAddr addr){    if (addr->family == AF_UNSPEC)	return 0;                      /* we don't know; assume not */    else {#ifdef IPV6	if (addr->family == AF_INET)	    return ipv4_is_loopback(		((struct sockaddr_in *)addr->ai->ai_addr)->sin_addr);	else if (addr->family == AF_INET6)	    return IN6_IS_ADDR_LOOPBACK(		&((struct sockaddr_in6 *)addr->ai->ai_addr)->sin6_addr);	else	    return 0;#else	struct in_addr a;	assert(addr->family == AF_INET);	a.s_addr = htonl(addr->address);	return ipv4_is_loopback(a);#endif    }}int sk_addrtype(SockAddr addr){    return (addr->family == AF_INET ? ADDRTYPE_IPV4 :#ifdef IPV6	    addr->family == AF_INET6 ? ADDRTYPE_IPV6 :#endif	    ADDRTYPE_NAME);}void sk_addrcopy(SockAddr addr, char *buf){#ifdef IPV6    if (addr->family == AF_INET)	memcpy(buf, &((struct sockaddr_in *)addr->ai->ai_addr)->sin_addr,	       sizeof(struct in_addr));    else if (addr->family == AF_INET6)	memcpy(buf, &((struct sockaddr_in6 *)addr->ai->ai_addr)->sin6_addr,	       sizeof(struct in6_addr));    else	assert(FALSE);#else    struct in_addr a;    assert(addr->family == AF_INET);    a.s_addr = htonl(addr->address);    memcpy(buf, (char*) &a.s_addr, 4);#endif}void sk_addr_free(SockAddr addr){#ifdef IPV6    if (addr->ai != NULL)	freeaddrinfo(addr->ai);#endif    sfree(addr);}static Plug sk_tcp_plug(Socket sock, Plug p){    Actual_Socket s = (Actual_Socket) sock;    Plug ret = s->plug;    if (p)	s->plug = p;    return ret;}static void sk_tcp_flush(Socket s){    /*     * We send data to the socket as soon as we can anyway,     * so we don't need to do anything here.  :-)     */}static void sk_tcp_close(Socket s);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);static void sk_tcp_set_private_ptr(Socket s, void *ptr);static void *sk_tcp_get_private_ptr(Socket s);static void sk_tcp_set_frozen(Socket s, int is_frozen);static const char *sk_tcp_socket_error(Socket s);static struct socket_function_table tcp_fn_table = {    sk_tcp_plug,    sk_tcp_close,    sk_tcp_write,    sk_tcp_write_oob,    sk_tcp_flush,    sk_tcp_set_private_ptr,    sk_tcp_get_private_ptr,    sk_tcp_set_frozen,    sk_tcp_socket_error};Socket sk_register(OSSocket sockfd, Plug plug){    Actual_Socket ret;    /*     * Create Socket structure.     */    ret = snew(struct Socket_tag);    ret->fn = &tcp_fn_table;    ret->error = NULL;    ret->plug = plug;    bufchain_init(&ret->output_data);    ret->writable = 1;		       /* to start with */    ret->sending_oob = 0;    ret->frozen = 1;    ret->frozen_readable = 0;    ret->localhost_only = 0;	       /* unused, but best init anyway */    ret->pending_error = 0;    ret->oobpending = FALSE;    ret->listener = 0;    ret->s = sockfd;    if (ret->s < 0) {	ret->error = error_string(errno);	return (Socket) ret;    }    ret->oobinline = 0;    uxsel_tell(ret);    add234(sktree, ret);    return (Socket) ret;}Socket sk_new(SockAddr addr, int port, int privport, int oobinline,	      int nodelay, int keepalive, Plug plug){    int s;#ifdef IPV6    struct sockaddr_in6 a6;#endif    struct sockaddr_in a;    struct sockaddr_un au;    const struct sockaddr *sa;    int err;    Actual_Socket ret;    short localport;    int fl, salen;    /*     * Create Socket structure.     */    ret = snew(struct Socket_tag);    ret->fn = &tcp_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;    ret->frozen = 0;    ret->frozen_readable = 0;    ret->localhost_only = 0;	       /* unused, but best init anyway */    ret->pending_error = 0;    ret->oobpending = FALSE;    ret->listener = 0;    /*     * Open socket.     */    assert(addr->family != AF_UNSPEC);    s = socket(addr->family, SOCK_STREAM, 0);    ret->s = s;    if (s < 0) {	ret->error = error_string(errno);	return (Socket) ret;    }    ret->oobinline = oobinline;    if (oobinline) {	int b = TRUE;	setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (void *) &b, sizeof(b));    }    if (nodelay) {	int b = TRUE;	setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (void *) &b, sizeof(b));    }    if (keepalive) {	int b = TRUE;	setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (void *) &b, sizeof(b));    }    /*     * Bind to local address.     */    if (privport)	localport = 1023;	       /* count from 1023 downwards */    else	localport = 0;		       /* just use port 0 (ie kernel picks) */    /* BSD IP stacks need sockaddr_in zeroed before filling in */    memset(&a,'\0',sizeof(struct sockaddr_in));#ifdef IPV6    memset(&a6,'\0',sizeof(struct sockaddr_in6));#endif    /* We don't try to bind to a local address for UNIX domain sockets.  (Why     * do we bother doing the bind when localport == 0 anyway?) */    if(addr->family != AF_UNIX) {	/* Loop round trying to bind */	while (1) {	    int retcode;#ifdef IPV6	    if (addr->family == AF_INET6) {		/* XXX use getaddrinfo to get a local address? */		a6.sin6_family = AF_INET6;		a6.sin6_addr = in6addr_any;		a6.sin6_port = htons(localport);		retcode = bind(s, (struct sockaddr *) &a6, sizeof(a6));	    } else#endif	    {		assert(addr->family == AF_INET);		a.sin_family = AF_INET;		a.sin_addr.s_addr = htonl(INADDR_ANY);		a.sin_port = htons(localport);		retcode = bind(s, (struct sockaddr *) &a, sizeof(a));	    }	    if (retcode >= 0) {		err = 0;		break;		       /* done */	    } else {		err = errno;		if (err != EADDRINUSE) /* 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 */	}		if (err) {	    ret->error = error_string(err);	    return (Socket) ret;	}    }    /*     * Connect to remote address.     */    switch(addr->family) {#ifdef IPV6      case AF_INET:	/* XXX would be better to have got getaddrinfo() to fill in the port. */	((struct sockaddr_in *)addr->ai->ai_addr)->sin_port =	    htons(port);	sa = (const struct sockaddr *)addr->ai->ai_addr;	salen = addr->ai->ai_addrlen;	break;      case AF_INET6:	((struct sockaddr_in *)addr->ai->ai_addr)->sin_port =	    htons(port);	sa = (const struct sockaddr *)addr->ai->ai_addr;	salen = addr->ai->ai_addrlen;	break;#else      case AF_INET:	a.sin_family = AF_INET;	a.sin_addr.s_addr = htonl(addr->address);	a.sin_port = htons((short) port);	sa = (const struct sockaddr *)&a;	salen = sizeof a;	break;#endif      case AF_UNIX:	assert(port == 0);	/* to catch confused people */	assert(strlen(addr->hostname) < sizeof au.sun_path);	memset(&au, 0, sizeof au);	au.sun_family = AF_UNIX;	strcpy(au.sun_path, addr->hostname);	sa = (const struct sockaddr *)&au;	salen = sizeof au;	break;      default:	assert(0 && "unknown address family");    }    fl = fcntl(s, F_GETFL);    if (fl != -1)	fcntl(s, F_SETFL, fl | O_NONBLOCK);    if ((connect(s, sa, salen)) < 0) {	if ( errno != EINPROGRESS ) {	    ret->error = error_string(errno);	    return (Socket) ret;	}    } else {	/*	 * If we _don't_ get EWOULDBLOCK, the connect has completed	 * and we should set the socket as connected and writable.	 */	ret->connected = 1;	ret->writable = 1;    }    uxsel_tell(ret);    add234(sktree, ret);    sk_addr_free(addr);

⌨️ 快捷键说明

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