python-2.7twistedassertionreactorssdp

Send m-search packets on all network interfaces


I am implementing a code through which i have to get devices connected to all network interfaces on my machine.

For this, i am first getting the ip of all network interfaces and then sending m-search command on them.

After 2.5 seconds port is stopped to listen.

But it is giving me some assertion error.

Code:

class Base(DatagramProtocol):
    """ Class to send M-SEARCH message to devices in network and receive datagram
        packets from them
    """
    SSDP_ADDR = "239.255.255.250"
    SSDP_PORT = 1900
    MS = "M-SEARCH * HTTP/1.1\r\nHOST: {}:{}\r\nMAN: 'ssdp:discover'\r\nMX: 2\r\nST: ssdp:all\r\n\r\n".format(SSDP_ADDR, SSDP_PORT)

def sendMsearch(self):
    """ Sending M-SEARCH message
    """
    ports = []
    for address in self.addresses:
        ports.append(reactor.listenUDP(0, self, interface=address))

    for port in ports:
        for num in range(4):
            port.write(Base.MS, (Base.SSDP_ADDR,Base.SSDP_PORT))
        reactor.callLater(2.5, self.stopMsearch, port) # MX + a wait margin


def stopMsearch(self, port):
    """ Stop listening on port
    """
    port.stopListening()

Error:

Traceback (most recent call last):
  File "work\find_devices.py", line 56, in sendMsearch
    ports.append(reactor.listenUDP(0, self, interface=address))
  File "C:\Python27\lib\site-packages\twisted\internet\posixbase.py", line 374, in listenUDP
    p.startListening()
  File "C:\Python27\lib\site-packages\twisted\internet\udp.py", line 172, in startListening
    self._connectToProtocol()
  File "C:\Python27\lib\site-packages\twisted\internet\udp.py", line 210, in _connectToProtocol
    self.protocol.makeConnection(self)
  File "C:\Python27\lib\site-packages\twisted\internet\protocol.py", line 709, in makeConnection
    assert self.transport == None
AssertionError

Please tell what's wrong in this code and how to correct this.

Also on linux machines, if no device is found on network then it doesn't go to stopMsearch() why ?


Solution

  • A protocol can only have one transport. The loop:

    for address in self.addresses:
        ports.append(reactor.listenUDP(0, self, interface=address))
    

    tries to create multiple UDP transports and associate them all with self - a single protocol instance.

    This is what the assertion error is telling you. The protocol's transport must be None (ie, it must not have a transport). But on the second iteration through the loop, it already has a transport.

    Try using multiple protocol instances instead.