def get(self): # overload get() from parent """Get the next response from the network. Arguments: None Returns: a received datagram, may be empty only with time and retry number. """ if self._count < 0: return while True: _o_datagram = super().get() if _o_datagram is None: self._count -= 1 _o_dummy_datagram = SSDPdatagram() if self._count > 0: super().request() self._retry += 1 _o_dummy_datagram.request = self._retry #return _rel_time + 's ' + str(self._retry) + '\r\n' else: self._count = -1 _o_dummy_datagram.request = 0 #return _rel_time + 's ' + '0' + '\r\n' return _o_dummy_datagram.fdevice( base_time=self._timestamp_first_request) else: _device = _o_datagram.ipaddr + ' ' +_o_datagram.uuid if _device not in self._devicelist: self._devicelist.append(_device) _o_datagram.request = self._retry return _o_datagram.fdevice( base_time=self._timestamp_first_request, verbose=self._verbose)
def test3_fdevice(self): """Test formating device from listen datagram without addr and data.""" o_datagram = SSDPdatagram() result = o_datagram.fdevice() self.assertEqual(result, '0000.0000s 0\r\n') result = o_datagram.fdevice(base_time=time() - 1.5) self.assertRegex(result, r'^0001\.\d\d\d\ds 0\r\n$')
def test8_fdevice(self): """Test format device verbose listen datagram without addr and data.""" o_datagram = SSDPdatagram() result = o_datagram.fdevice(verbose=True) self.assertEqual(result, '0000.0000s 0\r\n') result = o_datagram.fdevice(base_time=time() - 1.5, verbose=True) self.assertRegex(result, r'^0001\.\d\d\d\ds 0\r\n$')
def test9_fdevice(self): """Test formating device verbose from listen datagram without data.""" o_datagram = SSDPdatagram(addr=LADDR1) o_datagram.request = 2 result = o_datagram.fdevice(verbose=True) self.assertEqual(result, '0000.0000s 2 192.168.10.86:57535\r\n') result = o_datagram.fdevice(base_time=time() - 1.5, verbose=True) self.assertRegex(result, (r'^0001\.\d\d\d\ds 2 ' r'192\.168\.10\.86:57535\r\n$'))
def test10_fdevice(self): """Test formating device verbose from listen datagram without addr.""" o_datagram = SSDPdatagram(raw_data=LDATAGRAM1) o_datagram.request = 4 result = o_datagram.fdevice(verbose=True) self.assertEqual(result, '0000.0000s 4\r\n' + LDATAGRAM1.decode()) result = o_datagram.fdevice(base_time=time() - 1.5, verbose=True) self.assertRegex(result[:9], r'^0001\.\d\d\d\d$') self.assertEqual(result[9:], 's 4\r\n' + LDATAGRAM1.decode())
def _get_datagram(self): """Listen to the next SSDP datagram on the local network""" if self._timeout != 0: try: data, addr = self._sock.recvfrom(self.RECVBUF) if len(data) >= self.RECVBUF: raise SystemExit("ERROR: receive buffer overflow") self._o_datagram = SSDPdatagram(addr, data) except KeyboardInterrupt: self._timeout = 0
def test7_fdevice(self): """Test formating a device verbose output from a listen datagram.""" o_datagram = SSDPdatagram(addr=LADDR1, raw_data=LDATAGRAM1) o_datagram.request = 3 result = o_datagram.fdevice(verbose=True) self.assertEqual( result, '0000.0000s 3 192.168.10.86:57535\r\n' + LDATAGRAM1.decode()) result = o_datagram.fdevice(base_time=time() - 1.5, verbose=True) self.assertRegex(result[:9], r'^0001\.\d\d\d\d$') self.assertEqual(result[9:], 's 3 192.168.10.86:57535\r\n' + LDATAGRAM1.decode())
def test6_fdevice(self): """Test formating a device verbose output from a search datagram.""" o_datagram = SSDPdatagram(addr=SADDR1, raw_data=SDATAGRAM1) result = o_datagram.fdevice(verbose=True) self.assertEqual( result, '0000.0000s 0 192.168.10.119:47383\r\n' + SDATAGRAM1.decode()) result = o_datagram.fdevice(time() + 2, verbose=True) self.assertEqual( result, '0000.0000s 0 192.168.10.119:47383\r\n' + SDATAGRAM1.decode()) result = o_datagram.fdevice(base_time=time() - 1.5, verbose=True) self.assertRegex(result[:9], r'^0001\.\d\d\d\d$') self.assertEqual(result[9:], 's 0 192.168.10.119:47383\r\n' + SDATAGRAM1.decode())
def test5_fdevice(self): """Test formating device output from a listen datagram without addr.""" o_datagram = SSDPdatagram(raw_data=LDATAGRAM1) o_datagram.request = 4 result = o_datagram.fdevice() self.assertEqual( result, ('0000.0000s 4 NOTIFY uuid:f4f7681c-3056-11e8-86bd-87a6e4e2c42d ' 'Linux/4.14.71-v7+, UPnP/1.0, Portable SDK for UPnP ' 'devices/1.6.19+git20160116\r\n')) result = o_datagram.fdevice(base_time=time() - 1.5) self.assertRegex(result, ( r'^0001\.\d\d\d\ds 4 NOTIFY ' r'uuid:f4f7681c-3056-11e8-86bd-87a6e4e2c42d Linux/4\.14\.71-v7\+, ' r'UPnP/1\.0, Portable SDK for UPnP devices/1\.6\.19\+git20160116' r'\r\n$'))
def test5_ssdp_datagram(self): """Test structure of a SSDP datagram object from listen.""" o_datagram = SSDPdatagram(addr=LADDR1, raw_data=LDATAGRAM1) self.assertAlmostEqual(o_datagram.timestamp, time(), 2) self.assertEqual(o_datagram.ipaddr, '192.168.10.86') self.assertEqual(o_datagram.port, '57535') self.assertEqual(o_datagram.request, 0) self.assertEqual(o_datagram.method, 'NOTIFY') self.assertEqual(o_datagram.host, '239.255.255.250:1900') self.assertEqual(o_datagram.cache_control, 'max-age=100') self.assertEqual(o_datagram.location, 'http://192.168.10.86:49494/description.xml') self.assertEqual(o_datagram.opt, '"http://schemas.upnp.org/upnp/1/0/"; ns=01') self.assertEqual(o_datagram.x01_nls, '293e3a3c-760d-11e8-8719-a7d281e29bfc') self.assertEqual(o_datagram.nt, 'urn:schemas-upnp-org:device:MediaRenderer:1') self.assertEqual(o_datagram.nts, 'ssdp:alive') self.assertEqual(o_datagram.server, ('Linux/4.14.71-v7+, UPnP/1.0, Portable SDK for UPnP ' 'devices/1.6.19+git20160116')) self.assertEqual(o_datagram.x_user_agent, 'redsonic') self.assertEqual(o_datagram.usn, ('uuid:f4f7681c-3056-11e8-86bd-87a6e4e2c42d' '::urn:schemas-upnp-org:device:MediaRenderer:1')) self.assertEqual(o_datagram.uuid, 'f4f7681c-3056-11e8-86bd-87a6e4e2c42d') self.assertEqual(o_datagram.data, LDATAGRAM1.decode())
def get(self): """Get next SSDP datagram from multicast net within a timeout. This method returns a SSDPdatagram object that represents a received SSDP record from an upnp root device on the local netwwork. A call returns only when a datagram has received or when the timeout has expired. The timeout is the given response time for the devices (plus a small network delay). """ if self._response_time == 0: return else: try: # The timeout (in sec) for the socket is reduced after every # received data so the over all transfer has finished after the # given response time (plus a small network delay added). _tout = int(round( self._response_time \ - (time() - self._timestamp_request))) \ + 1 self._sock.settimeout(_tout) data, addr = self._sock.recvfrom(self.RECVBUF) if len(data) >= self.RECVBUF: raise SystemExit("ERROR: receive buffer overflow") return SSDPdatagram(addr, data) except socket.timeout: self._response_time = 0 return
def test2_fdevice(self): """Test formating a device output from a listen datagram.""" o_datagram = SSDPdatagram(addr=LADDR1, raw_data=LDATAGRAM1) o_datagram.request = 3 result = o_datagram.fdevice() self.assertEqual( result, ('0000.0000s 3 NOTIFY 192.168.10.86:57535 ' 'uuid:f4f7681c-3056-11e8-86bd-87a6e4e2c42d Linux/4.14.71-v7+, ' 'UPnP/1.0, Portable SDK for UPnP devices/1.6.19+git20160116\r\n')) result = o_datagram.fdevice(base_time=time() - 1.5) self.assertRegex(result, ( r'^0001\.\d\d\d\ds 3 NOTIFY 192\.168\.10\.86:57535 ' r'uuid:f4f7681c-3056-11e8-86bd-87a6e4e2c42d Linux/4\.14\.71-v7\+, ' r'UPnP/1\.0, Portable SDK for UPnP devices/1\.6\.19\+git20160116' r'\r\n$'))
def test1_ssdp_datagram(self): """Test structure of a SSDP datagram object from search response.""" o_datagram = SSDPdatagram(addr=SADDR1, raw_data=SDATAGRAM1) self.assertAlmostEqual(o_datagram.timestamp, time(), 2) self.assertEqual(len(o_datagram.__dict__), 17) self.assertEqual(o_datagram.method, '') self.assertEqual(o_datagram.bootid_upnp_org, '0') self.assertEqual(o_datagram.cache_control, 'max-age=1800') self.assertEqual(o_datagram.configid_upnp_org, '1') self.assertEqual(o_datagram.date, 'Sun, 23 Sep 2018 17:08:38 GMT') self.assertEqual(o_datagram.ext, '') self.assertEqual(o_datagram.ipaddr, '192.168.10.119') self.assertEqual(o_datagram.location, ('http://192.168.10.119:8008/ssdp/device-desc.xml')) self.assertEqual(o_datagram.opt, '"http://schemas.upnp.org/upnp/1/0/";' ' ns=01') self.assertEqual(o_datagram.port, '47383') self.assertEqual(o_datagram.request, 0) self.assertEqual( o_datagram.server, 'Linux/3.10.79, UPnP/1.0, ' 'Portable SDK for UPnP devices/1.6.18') self.assertEqual(o_datagram.st, 'upnp:rootdevice') self.assertEqual( o_datagram.usn, ('uuid:3b2867a3-b55f-8e77-5ad8-a6d0c6990277::upnp:rootdevice')) self.assertEqual(o_datagram.uuid, '3b2867a3-b55f-8e77-5ad8-a6d0c6990277') self.assertEqual(o_datagram.x01_nls, 'd2631d76-1dd1-11b2-9c2f-ee4373b37081') self.assertEqual(o_datagram.x_user_agent, 'redsonic') self.assertEqual(o_datagram.data, SDATAGRAM1.decode())
def test2_ssdp_datagram(self): """Test SSDP datagram from search response without addr and data.""" o_datagram = SSDPdatagram() self.assertAlmostEqual(o_datagram.timestamp, time(), 2) self.assertEqual(len(o_datagram.__dict__), 4) self.assertEqual(o_datagram.ipaddr, '') self.assertEqual(o_datagram.port, '') self.assertEqual(o_datagram.method, '') self.assertEqual(o_datagram.request, 0) self.assertIsNone(o_datagram.data)
def test4_ssdp_datagram(self): """Test SSDP datagram from search response without addr.""" o_datagram = SSDPdatagram(raw_data=SDATAGRAM1) self.assertAlmostEqual(o_datagram.timestamp, time(), 2) self.assertEqual(len(o_datagram.__dict__), 17) self.assertEqual(o_datagram.ipaddr, '') self.assertEqual(o_datagram.port, '') self.assertEqual(o_datagram.method, '') self.assertEqual(o_datagram.request, 0) self.assertEqual(o_datagram.data, SDATAGRAM1.decode())
def test3_ssdp_datagram(self): """Test SSDP datagram from search response without data.""" o_datagram = SSDPdatagram(addr=SADDR1) self.assertAlmostEqual(o_datagram.timestamp, time(), 2) self.assertEqual(len(o_datagram.__dict__), 4) self.assertEqual(o_datagram.ipaddr, '192.168.10.119') self.assertEqual(o_datagram.port, '47383') self.assertEqual(o_datagram.method, '') self.assertEqual(o_datagram.request, 0) self.assertIsNone(o_datagram.data)
def test1_fdevice(self): """Test formating a device output from a search datagram.""" o_datagram = SSDPdatagram(addr=SADDR1, raw_data=SDATAGRAM1) result = o_datagram.fdevice() self.assertEqual( result, ('0000.0000s 0 192.168.10.119:47383 ' 'uuid:3b2867a3-b55f-8e77-5ad8-a6d0c6990277 Linux/3.10.79, ' 'UPnP/1.0, Portable SDK for UPnP devices/1.6.18\r\n')) result = o_datagram.fdevice(time() + 2) self.assertEqual( result, ('0000.0000s 0 192.168.10.119:47383 ' 'uuid:3b2867a3-b55f-8e77-5ad8-a6d0c6990277 Linux/3.10.79, ' 'UPnP/1.0, Portable SDK for UPnP devices/1.6.18\r\n')) result = o_datagram.fdevice(base_time=time() - 1.5) self.assertRegex( result, (r'^0001\.\d\d\d\ds 0 192\.168\.10\.119:47383 ' r'uuid:3b2867a3-b55f-8e77-5ad8-a6d0c6990277 Linux/3\.10\.79, ' r'UPnP/1\.0, Portable SDK for UPnP devices/1\.6\.18\r\n$'))
class Listen(Mcast): """Passive listen for notifies from devices on the local network We are only listen to the upnp multicast group. """ _verbose = False _open_timestamp = 0 _timeout = 0 _sock = None _o_datagram = None def __init__(self, verbose=False): """Setup verbose output if requested.""" self._verbose = verbose def open(self): """Initialize and open a connection and join to the multicast group""" self._open_timestamp = time() self._timeout = -1 self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) self._sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # use MCAST_GRP instead of '' to listen only to MCAST_GRP, # not all groups on MCAST_PORT # self._sock.bind(('', self._MCAST_PORT)) self._sock.bind((self._MCAST_GRP, self._MCAST_PORT)) mreq = struct.pack("4sl", socket.inet_aton(self._MCAST_GRP), socket.INADDR_ANY) self._sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq) def _get_datagram(self): """Listen to the next SSDP datagram on the local network""" if self._timeout != 0: try: data, addr = self._sock.recvfrom(self.RECVBUF) if len(data) >= self.RECVBUF: raise SystemExit("ERROR: receive buffer overflow") self._o_datagram = SSDPdatagram(addr, data) except KeyboardInterrupt: self._timeout = 0 def get(self): """Listen for upnp datagrams on the local network.""" self._get_datagram() if self._timeout == 0: return return self._o_datagram.fdevice(base_time=self._open_timestamp, verbose=self._verbose)