TCP: vastly improve the connection state handling

Change disconnect_locked() to conn_set_closing_locked() to better
reflect what it does. It transitions the state to CLOSING, queues the
conn on the closing queue, and calls ignore_fd_locked() (ignores the
conn's fd which removes it from the poll array, etc., and closes the
fd). The caller _must_ hold the ep->lock and the tep->is_polling token to
prevent the poll array from changing in the middle of poll_events().

Modify poll_events() to handle POLLHUP cases first. Since all POLLHUP
cases invoke conn_set_closing_locked() which modifies the poll array, we
have to exit the loop and poll again later.

Make sure disconnect() has the tep->is_polling token before calling
conn_set_closing_locked().

In return_event(), the connect event may be a tx if the peer's endpoint
is not yet open and it may be a rx if we get a successful reply. Use
the events's ctx to determine which.

Catch a couple of leaked descriptors.

Add locks around tcp_progress_conn_sends() in progress_queued().

Improve connection reply handling on the active side.