X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/putty/blobdiff_plain/e5eb3a1ca14cf38028d076b06701792af954c90b..8e3a513c3a264390dce084ef9cd0e3e9cb0bd5d2:/winnet.c diff --git a/winnet.c b/winnet.c index 1a80a80c..b6710472 100644 --- a/winnet.c +++ b/winnet.c @@ -63,6 +63,7 @@ struct Socket_tag { 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 @@ -338,6 +339,21 @@ SockAddr sk_namelookup(char *host, char **canonicalname) return ret; } +void sk_getaddr(SockAddr addr, char *buf, int buflen) +{ +#ifdef IPV6 + if (addr->family == AF_INET) { +#endif + struct in_addr a; + a.s_addr = htonl(addr->address); + strncpy(buf, inet_ntoa(a), buflen); +#ifdef IPV6 + } else { + FIXME; /* I don't know how to get a text form of an IPv6 address. */ + } +#endif +} + void sk_addr_free(SockAddr addr) { sfree(addr); @@ -448,7 +464,8 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline, ret->error = NULL; ret->plug = plug; bufchain_init(&ret->output_data); - ret->writable = 1; /* to start with */ + ret->connected = 0; /* to start with */ + ret->writable = 0; /* to start with */ ret->sending_oob = 0; ret->frozen = 0; ret->frozen_readable = 0; @@ -543,6 +560,15 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline, a.sin_addr.s_addr = htonl(addr->address); a.sin_port = htons((short) port); } + + /* 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) { + ret->error = errstr; + return (Socket) ret; + } + if (( #ifdef IPV6 connect(s, ((addr->family == AF_INET6) ? @@ -553,16 +579,22 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline, #endif ) == SOCKET_ERROR) { err = WSAGetLastError(); - ret->error = winsock_error_string(err); - 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) { - ret->error = errstr; - return (Socket) ret; + /* + * 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 ) { + ret->error = winsock_error_string(err); + return (Socket) ret; + } + } else { + /* + * If we _don't_ get EWOULDBLOCK, the connect has completed + * and we should set the socket as writable. + */ + ret->writable = 1; } add234(sktree, ret); @@ -713,7 +745,6 @@ void try_send(Actual_Socket s) urgentflag = 0; bufchain_prefix(&s->output_data, &data, &len); } - nsent = send(s->s, data, len, urgentflag); noise_ultralight(nsent); if (nsent <= 0) { @@ -733,17 +764,30 @@ void try_send(Actual_Socket s) } else if (nsent == 0 || err == WSAECONNABORTED || err == WSAECONNRESET) { /* - * FIXME. This will have to be done better when we - * start managing multiple sockets (e.g. SSH port - * forwarding), because if we get CONNRESET while - * trying to write a particular forwarded socket - * then it isn't necessarily the end of the world. - * Ideally I'd like to pass the error code back to - * somewhere the next select_result() will see it, - * but that might be hard. Perhaps I should pass it - * back to be queued in the Windows front end bit. + * ASSUMPTION: + * + * I'm assuming here that if a TCP connection is + * reset or aborted once established, we will be + * notified by a select event rather than a + * CONNABORTED or CONNRESET from send(). In other + * words, I'm assuming CONNABORTED and CONNRESET + * don't come back from a _nonblocking_ send(), + * because the local side doesn't know they've + * happened until it waits for a response to its + * TCP segment - so the error will arrive + * asynchronously. + * + * If I'm wrong, this will be a really nasty case, + * because we can't necessarily call plug_closing() + * without having to make half the SSH code + * reentrant; so instead we'll have to schedule a + * call to plug_closing() for some suitable future + * time. */ - fatalbox(winsock_error_string(err)); + fatalbox("SERIOUS NETWORK INTERNAL ERROR: %s\n" + "Please report this immediately to " + ".", + winsock_error_string(err)); } else { fatalbox(winsock_error_string(err)); } @@ -825,6 +869,9 @@ int select_result(WPARAM wParam, LPARAM lParam) noise_ultralight(lParam); switch (WSAGETSELECTEVENT(lParam)) { + case FD_CONNECT: + s->connected = s->writable = 1; + break; case FD_READ: /* In the case the socket is still frozen, we don't even bother */ if (s->frozen) {