zeromq/libzmq — pull request #320 by shripchenko (2012-04-21 15:53:34+00:00)
Title: ZMQ BUG FOUND + fixes for zmq_unbind() / zmq_disconnect() usage corner cases

1. when we call zmq_bind()/zmq_connect() to create endpoint
we send ourself(through launch_child()) command to process_own(endpoint)
(and add it to own_t::owned)
in the application thread we could call zmq_unbind() / zmq_disconnect() _BEFORE_
we run process_own() in ZMQ thread and in this situation we will be unable to find it in
own_t::owned. in other words own_t::owned.find(endpoint) will not be deleted but it will be deleted from
socket_base_t::endpoints.

2. when you zmq_unbind(), the lisnening TCP/IPC socket was terminated only in destructor...
so the whole ZMQ_LINGER time listening TCP/IPC socket was able to accept() new connections
but unable to handle them.

this all geting even worse since unfortunately zmq HAS A BUG and '*_listener_t' object not terminated
untill the socket's zmq_close().
AT LEAST FOR PUSH SOCKETS.
Everything is ok for SUB sockets.

Easy to reproduce without my fix:

zmq_socket(PUSH)
zmq_bind(tcp);
// connect to it from PULL socket
zmq_unbind(tcp);

sleep(forever)

// netstat -anp | grep 'tcp listening socket'

To reproduce it with my fix you could see that after zmq_unbind(tcp);sleep(forever); all previously connected tcp sessions
will not be finished until the zmq_close(socket) regardless of ZMQ_LINGER value.

(*_listener_t terminates all owned session_base_t(connect=false) and they call pipe_t::terminate()
which in turn should call session_base_t::terminated() but this never happens)