[Twisted-Python] Transfering a transport between DatagramProtocols

I am implementing a protocol where a DatagramProtocol "handshaking" subclass get an arbitrary port (by calling "self.udpPort = reactor.listenUDP(0, self)") and communicate it to a remote host. Once this is done, I would like to "switch" to another DatagramProtocol which would use the same port. To avoid a race condition, I would like to "transfert" self.transport from the first DatagramProtocol to the second without calling self.udpPort.stopListening(). Is this the "twisted" way to analyse this? Or should I use some kind of "proxy" DatagramProtocol which would relay datagramReceived calls to the proper DatagramProtocol, depending on the current protocol state (handshaking or data exchange)? Regards.

On Nov 24, 2009, at 4:26 PM, Olivier Parisy wrote:
Is this the "twisted" way to analyse this? Or should I use some kind of "proxy" DatagramProtocol which would relay datagramReceived calls to the proper DatagramProtocol, depending on the current protocol state (handshaking or data exchange)?
Currently, the right way to do this is to do as you suggest, and have two DatagramProtocol instances, and a third which switches between them. Now, it just so happens that there is an accidental feature of udp.Port, whereby you can do self.udpPort.protocol = someOtherProtocol, and it will work. However, this feature is not supported and may break in a future version of Twisted. In the future, however, it would be reasonable and useful to have an explicit "switch protocol" method, which would tear down one protocol/transport relationship and set up another. If you would like to open a ticket and contribute a patch to do this, that would be great :).

Glyph Lefkowitz a écrit :
On Nov 24, 2009, at 4:26 PM, Olivier Parisy wrote:
Currently, the right way to do this is to do as you suggest, and have two DatagramProtocol instances, and a third which switches between them.
OK, that seems like a reasonable pattern. Thanks for the confirmation.
In the future, however, it would be reasonable and useful to have an explicit "switch protocol" method, which would tear down one protocol/transport relationship and set up another. If you would like to open a ticket and contribute a patch to do this, that would be great :) .
I am not sure I would know where to start :-) But I'll give a look to DatagramProtocol source code. Regards, Olivier.

Glyph Lefkowitz a écrit :
On Nov 24, 2009, at 4:26 PM, Olivier Parisy wrote:
Is this the "twisted" way to analyse this? Or should I use some kind of "proxy" DatagramProtocol which would relay datagramReceived calls to the proper DatagramProtocol, depending on the current protocol state (handshaking or data exchange)?
Currently, the right way to do this is to do as you suggest, and have two DatagramProtocol instances, and a third which switches between them.
I tried to implement such a "switching" class so that I could freely change the DatagramProtocol handling a given port without releasing it. It is typically used in the following way : self.protocol = DelegatingDatagramProtocol(MyFirstDatagramProtocol()) self.udpPort = reactor.listenUDP(0, self.protocol) Then, later in the code : self.protocol.switchProtocol(MySecondDatagramProtocol()) Here is my current implementation : # Breaks when inheriting from DatagramProtocol? class DelegatingDatagramProtocol: def __init__(self, protocol): self._protocol = protocol def switchProtocol(self, protocol): self._protocol = protocol protocol.transport = self.transport def makeConnection(self, transport): self._protocol.makeConnection(transport) # Needed by switchProtocol self.transport = transport # Avoid an AssertionError (protocol.py:527 assert self.numPorts > 0) def doStop(self): pass # See http://www.python.org/workshops/1997-10/proceedings/savikko.html (Proxy pattern) def __getattr__(self, name): print 'Delegating to protocol: %s' % name return getattr(self._protocol, name) It mostly works, but I have two issues with it : - When doStop() is called by the reactor, an AssertionError is raised. I suppose this is due to my "sharing" of the transport in switchProtocol (which ensures that "transport.write" calls are directed to the proper transport), but how can I fix it? - If my class extends DatagramProtocol, it stops working (transport.write calls seems honored, then nothing works... I suppose datagramReceived is never called). Why is it so? Regards, Olivier.
participants (2)
-
Glyph Lefkowitz
-
Olivier Parisy