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
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);
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;
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) ?
#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);
urgentflag = 0;
bufchain_prefix(&s->output_data, &data, &len);
}
-
nsent = send(s->s, data, len, urgentflag);
noise_ultralight(nsent);
if (nsent <= 0) {
err = (nsent < 0 ? WSAGetLastError() : 0);
- if ((err == 0 && nsent < 0) || err == WSAEWOULDBLOCK) {
+ if ((err < WSABASEERR && nsent < 0) || err == WSAEWOULDBLOCK) {
/*
* Perfectly normal: we've sent all we can for the moment.
*
- * (Apparently some WinSocks can return <0 but
- * leave no error indication - WSAGetLastError() is
- * called but returns zero - so we check that case
- * and treat it just like WSAEWOULDBLOCK.)
+ * (Some WinSock send() implementations can return
+ * <0 but leave no sensible error indication -
+ * WSAGetLastError() is called but returns zero or
+ * a small number - so we check that case and treat
+ * it just like WSAEWOULDBLOCK.)
*/
s->writable = FALSE;
return;
} 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 "
+ "<putty@projects.tartarus.org>.",
+ winsock_error_string(err));
} else {
fatalbox(winsock_error_string(err));
}
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) {