disconnect() told the listener thread to stop and dialled it awake, then
returned while that thread was still unwinding, so the TcpListener was
often still open when the caller moved on. A client built straight after
a drop then found its configured port taken and fell back to an ephemeral
one. The TUI login screen does exactly that when it replaces an attempt.
The listener thread now raises a flag once it has dropped its socket, and
after the wake-up dial has landed, disconnect() waits for that flag,
bounded at two seconds, so the port can be bound again by the time
disconnect() or Drop returns. A listener that cannot be woken, or is held
past the bound by a full handshake queue, finishes on its own as before.
The flag is an Arc<AtomicBool>, like the stop flag beside it: keeping the
thread's JoinHandle instead would leave Client neither UnwindSafe nor
RefUnwindSafe, which is a breaking change for the library.
Nicotine+ and Soulseek.NET both close the listen socket as part of
disconnecting; this makes that hold by the time the call returns.