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

📄 uxnet.c

📁 putty
💻 C
📖 第 1 页 / 共 3 页
字号:
    }

    ret->oobinline = 0;

    uxsel_tell(ret);
    add234(sktree, ret);

    return (Socket) ret;
}

static int try_connect(Actual_Socket sock)
{
    int s;
#ifndef NO_IPV6
    struct sockaddr_in6 a6;
#endif
    struct sockaddr_in a;
    struct sockaddr_un au;
    const struct sockaddr *sa;
    int err = 0;
    short localport;
    int fl, salen;

    if (sock->s >= 0)
        close(sock->s);

    plug_log(sock->plug, 0, sock->addr, sock->port, NULL, 0);

    /*
     * Open socket.
     */
    assert(sock->addr->family != AF_UNSPEC);
    s = socket(sock->addr->family, SOCK_STREAM, 0);
    sock->s = s;

    if (s < 0) {
	err = errno;
	goto ret;
    }

    cloexec(s);

    if (sock->oobinline) {
	int b = TRUE;
	setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (void *) &b, sizeof(b));
    }

    if (sock->nodelay) {
	int b = TRUE;
	setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (void *) &b, sizeof(b));
    }

    if (sock->keepalive) {
	int b = TRUE;
	setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (void *) &b, sizeof(b));
    }

    /*
     * Bind to local address.
     */
    if (sock->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));
#ifndef NO_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(sock->addr->family != AF_UNIX) {
	/* Loop round trying to bind */
	while (1) {
	    int retcode;

#ifndef NO_IPV6
	    if (sock->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(sock->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)
	    goto ret;
    }

    /*
     * Connect to remote address.
     */
    switch(sock->addr->family) {
#ifndef NO_IPV6
      case AF_INET:
	/* XXX would be better to have got getaddrinfo() to fill in the port. */
	((struct sockaddr_in *)sock->addr->ai->ai_addr)->sin_port =
	    htons(sock->port);
	sa = (const struct sockaddr *)sock->addr->ai->ai_addr;
	salen = sock->addr->ai->ai_addrlen;
	break;
      case AF_INET6:
	((struct sockaddr_in *)sock->addr->ai->ai_addr)->sin_port =
	    htons(sock->port);
	sa = (const struct sockaddr *)sock->addr->ai->ai_addr;
	salen = sock->addr->ai->ai_addrlen;
	break;
#else
      case AF_INET:
	a.sin_family = AF_INET;
	a.sin_addr.s_addr = htonl(sock->addr->addresses[sock->addr->curraddr]);
	a.sin_port = htons((short) sock->port);
	sa = (const struct sockaddr *)&a;
	salen = sizeof a;
	break;
#endif
      case AF_UNIX:
	assert(sock->port == 0);       /* to catch confused people */
	assert(strlen(sock->addr->hostname) < sizeof au.sun_path);
	memset(&au, 0, sizeof au);
	au.sun_family = AF_UNIX;
	strcpy(au.sun_path, sock->addr->hostname);
	sa = (const struct sockaddr *)&au;
	salen = sizeof au;
	break;

      default:
	assert(0 && "unknown address family");
	exit(1); /* XXX: GCC doesn't understand assert() on some systems. */
    }

    fl = fcntl(s, F_GETFL);
    if (fl != -1)
	fcntl(s, F_SETFL, fl | O_NONBLOCK);

    if ((connect(s, sa, salen)) < 0) {
	if ( errno != EINPROGRESS ) {
	    err = errno;
	    goto ret;
	}
    } else {
	/*
	 * If we _don't_ get EWOULDBLOCK, the connect has completed
	 * and we should set the socket as connected and writable.
	 */
	sock->connected = 1;
	sock->writable = 1;
    }

    uxsel_tell(sock);
    add234(sktree, sock);

    ret:
    if (err)
	plug_log(sock->plug, 1, sock->addr, sock->port, strerror(err), err);
    return err;
}

Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
	      int nodelay, int keepalive, Plug plug)
{
    Actual_Socket ret;
    int err;

    /*
     * 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;
    ret->addr = addr;
    ret->s = -1;
    ret->oobinline = oobinline;
    ret->nodelay = nodelay;
    ret->keepalive = keepalive;
    ret->privport = privport;
    ret->port = port;

    err = 0;
    do {
        err = try_connect(ret);
    } while (err && sk_nextaddr(ret->addr));

    if (err)
        ret->error = strerror(err);

    return (Socket) ret;
}

Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only, int address_family)
{
    int s;
#ifndef NO_IPV6
    struct addrinfo hints, *ai;
    char portstr[6];
    struct sockaddr_in6 a6;
#endif
    struct sockaddr *addr;
    int addrlen;
    struct sockaddr_in a;
    Actual_Socket ret;
    int retcode;
    int on = 1;

    /*
     * 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 = 0;		       /* to start with */
    ret->sending_oob = 0;
    ret->frozen = 0;
    ret->frozen_readable = 0;
    ret->localhost_only = local_host_only;
    ret->pending_error = 0;
    ret->oobpending = FALSE;
    ret->listener = 1;
    ret->addr = NULL;

    /*
     * Translate address_family from platform-independent constants
     * into local reality.
     */
    address_family = (address_family == ADDRTYPE_IPV4 ? AF_INET :
#ifndef NO_IPV6
		      address_family == ADDRTYPE_IPV6 ? AF_INET6 :
#endif
		      AF_UNSPEC);

#ifndef NO_IPV6
    /* Let's default to IPv6.
     * If the stack doesn't support IPv6, we will fall back to IPv4. */
    if (address_family == AF_UNSPEC) address_family = AF_INET6;
#else
    /* No other choice, default to IPv4 */
    if (address_family == AF_UNSPEC)  address_family = AF_INET;
#endif

    /*
     * Open socket.
     */
    s = socket(address_family, SOCK_STREAM, 0);

#ifndef NO_IPV6
    /* If the host doesn't support IPv6 try fallback to IPv4. */
    if (s < 0 && address_family == AF_INET6) {
    	address_family = AF_INET;
    	s = socket(address_family, SOCK_STREAM, 0);
    }
#endif

    if (s < 0) {
	ret->error = strerror(errno);
	return (Socket) ret;
    }

    cloexec(s);

    ret->oobinline = 0;

    setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on));

    retcode = -1;
    addr = NULL; addrlen = -1;         /* placate optimiser */

    if (srcaddr != NULL) {
#ifndef NO_IPV6
        hints.ai_flags = AI_NUMERICHOST;
        hints.ai_family = address_family;
        hints.ai_socktype = SOCK_STREAM;
        hints.ai_protocol = 0;
        hints.ai_addrlen = 0;
        hints.ai_addr = NULL;
        hints.ai_canonname = NULL;
        hints.ai_next = NULL;
	assert(port >= 0 && port <= 99999);
        sprintf(portstr, "%d", port);
        retcode = getaddrinfo(srcaddr, portstr, &hints, &ai);
	if (retcode == 0) {
	    addr = ai->ai_addr;
	    addrlen = ai->ai_addrlen;
	}
#else
        memset(&a,'\0',sizeof(struct sockaddr_in));
        a.sin_family = AF_INET;
        a.sin_port = htons(port);
        a.sin_addr.s_addr = inet_addr(srcaddr);
        if (a.sin_addr.s_addr != (in_addr_t)(-1)) {
            /* Override localhost_only with specified listen addr. */
            ret->localhost_only = ipv4_is_loopback(a.sin_addr);
        }
        addr = (struct sockaddr *)&a;
        addrlen = sizeof(a);
        retcode = 0;
#endif
    }

    if (retcode != 0) {
#ifndef NO_IPV6
        if (address_family == AF_INET6) {
            memset(&a6,'\0',sizeof(struct sockaddr_in6));
            a6.sin6_family = AF_INET6;
            a6.sin6_port = htons(port);
            if (local_host_only)
                a6.sin6_addr = in6addr_loopback;
            else
                a6.sin6_addr = in6addr_any;
            addr = (struct sockaddr *)&a6;
            addrlen = sizeof(a6);
        } else
#endif
        {
            memset(&a,'\0',sizeof(struct sockaddr_in));
            a.sin_family = AF_INET;
            a.sin_port = htons(port);
	    if (local_host_only)
		a.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
	    else
		a.sin_addr.s_addr = htonl(INADDR_ANY);
            addr = (struct sockaddr *)&a;
            addrlen = sizeof(a);
        }
    }

    retcode = bind(s, addr, addrlen);
    if (retcode < 0) {
        close(s);
	ret->error = strerror(errno);
	return (Socket) ret;
    }

    if (listen(s, SOMAXCONN) < 0) {
        close(s);
	ret->error = strerror(errno);
	return (Socket) ret;
    }

    ret->s = s;

    uxsel_tell(ret);
    add234(sktree, ret);

    return (Socket) ret;
}

static void sk_tcp_close(Socket sock)
{
    Actual_Socket s = (Actual_Socket) sock;

    uxsel_del(s->s);
    del234(sktree, s);
    close(s->s);
    if (s->addr)
        sk_addr_free(s->addr);
    sfree(s);
}

void *sk_getxdmdata(void *sock, int *lenp)
{
    Actual_Socket s = (Actual_Socket) sock;
#ifdef NO_IPV6
    struct sockaddr_in addr;
#else
    struct sockaddr_storage addr;
    struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addr;
#endif
    struct sockaddr *sa = (struct sockaddr *)&addr;
    struct sockaddr_in *sin = (struct sockaddr_in *)&addr;
    socklen_t addrlen;
    char *buf;
    static unsigned int unix_addr = 0xFFFFFFFF;

    /*
     * We must check that this socket really _is_ an Actual_Socket.
     */
    if (s->fn != &tcp_fn_table)
	return NULL;		       /* failure */

    addrlen = sizeof(addr);
    if (getsockname(s->s, sa, &addrlen) < 0)
	return NULL;
    switch(sa->sa_family) {
      case AF_INET:
	*lenp = 6;
	buf = snewn(*lenp, char);
	PUT_32BIT_MSB_FIRST(buf, ntohl(sin->sin_addr.s_addr));
	PUT_16BIT_MSB_FIRST(buf+4, ntohs(sin->sin_port));
	break;
#ifndef NO_IPV6
    case AF_INET6:
	*lenp = 6;
	buf = snewn(*lenp, char);
	if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {

⌨️ 快捷键说明

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