Revision 020f4a9e

b/vncauthproxy/proxy.py
34 34
import sys
35 35
import logging
36 36
import gevent
37
import gevent.event
37 38
import daemon
38 39
import random
39 40
import daemon.runner
......
116 117
        VncAuthProxy.id += 1
117 118
        self.log = logger
118 119
        self.listeners = listeners
120
        # A list of worker/forwarder greenlets, one for each direction
121
        self.workers = []
119 122
        # All listening sockets are assumed to be on the same port
120 123
        self.sport = listeners[0].getsockname()[1]
121 124
        self.pool = pool
......
127 130
        self.timeout = connect_timeout
128 131

  
129 132
    def _cleanup(self):
130
        """Close all active sockets and exit gracefully"""
133
        """Cleanup everything: workers, sockets, ports
134

  
135
        Kill all remaining forwarder greenlets, close all active sockets,
136
        return the source port to the pool if applicable, then exit
137
        gracefully.
138

  
139
        """
140
        # Make sure all greenlets are dead, then clean them up
141
        self.debug("Cleaning up %d workers", len(self.workers))
142
        for g in self.workers:
143
            g.kill()
144
        gevent.joinall(self.workers)
145
        del self.workers
146

  
131 147
        # Reintroduce the port number of the client socket in
132 148
        # the port pool, if applicable.
133 149
        if not self.pool is None:
......
135 151
            self.debug("Returned port %d to port pool, contains %d ports",
136 152
                       self.sport, len(self.pool))
137 153

  
154
        self.debug("Cleaning up sockets")
138 155
        while self.listeners:
139 156
            self.listeners.pop().close()
140 157
        if self.server:
......
142 159
        if self.client:
143 160
            self.client.close()
144 161

  
162
        self.info("Cleaned up connection, all done")
145 163
        raise gevent.GreenletExit
146 164

  
147 165
    def __str__(self):
......
258 276
            self._client_handshake()
259 277

  
260 278
            # Bridge both connections through two "forwarder" greenlets.
261
            self.workers = [gevent.spawn(self._forward,
262
                                         self.client, self.server),
263
                            gevent.spawn(self._forward,
264
                                         self.server, self.client)]
265

  
266
            # If one greenlet goes, the other has to go too.
267
            self.workers[0].link(self.workers[1])
268
            self.workers[1].link(self.workers[0])
269
            gevent.joinall(self.workers)
270
            del self.workers
279
            # This greenlet will wait until any of the workers dies.
280
            # Final cleanup will take place in _cleanup().
281
            dead = gevent.event.Event()
282
            dead.clear()
283

  
284
            # This callback will get called if any of the two workers dies.
285
            def callback(g):
286
                self.debug("Worker %d/%d died", self.workers.index(g),
287
                           len(self.workers))
288
                dead.set()
289

  
290
            self.workers.append(gevent.spawn(self._forward,
291
                                             self.client, self.server))
292
            self.workers.append(gevent.spawn(self._forward,
293
                                             self.server, self.client))
294
            for g in self.workers:
295
                g.link(callback)
296

  
297
            # Wait until any of the workers dies
298
            self.debug("Waiting for any of %d workers to die",
299
                       len(self.workers))
300
            dead.wait()
301

  
302
            # We can go now, _cleanup() will take care of
303
            # all worker, socket and port cleanup
304
            self.debug("A forwarder died, our work here is done")
271 305
            raise gevent.GreenletExit
272 306
        except Exception, e:
273 307
            # Any unhandled exception in the previous block

Also available in: Unified diff