Commit 4f9c9341 authored by Michael Weinrich's avatar Michael Weinrich
Browse files

modules renamed, classes divided in parts for client and server devices

parent fea684ce
......@@ -8,27 +8,32 @@ import louie
from twisted.internet import reactor, defer
from coherence.base import Coherence
#from coherence.upnp.core.devices.control_point import ControlPoint
from coherence import log
#from coherence.extern.logger import Logger
#log = Logger('UPnT')
from upntest.testhost import TestHost
from upntest.host import Host
"""The main class of the whole test suite"""
class UPnT(log.Loggable):
logCategory = 'UPnT'
known_hosts = {}
runningDeferreds = []
shutdown_signal = None
def __init__(self, config={}):
log.init()
self.known_hosts = {}
self.runningDeferreds = []
self.shutdown_signal = None
self._hosts_to_remove = []
self._config = config
self._coherence = Coherence(self._config);
#if config.get('test_control_point', False):
#self._control_point = ControlPoint(self._coherence)
self.info('connecting signals...')
louie.connect(self.datagramReceived, 'UPnT.ssdp_datagram_received', louie.Any, weak=False)
louie.connect(self.datagramReceived, 'UPnT.msearch_datagram_received', louie.Any, weak=False)
......@@ -42,24 +47,30 @@ class UPnT(log.Loggable):
reactor.addSystemEventTrigger('before', 'shutdown', self.waitForShutdown)
def datagramReceived(self, data, ip, port):
"""debug output for received datagrams"""
#print '\nDatagram received from %s:%s' % (ip, port)
#print 'Datagram data:\n%s' % data
"""
Check if host exists in host list. If not create it and call the
validation method.
"""
if not self.known_hosts.has_key(ip):
self.known_hosts[ip] = TestHost(ip, self._config)
self.known_hosts[ip] = Host(ip, self._config)
self.info('Host added', ip)
self.debug('Calling dispatchDiscoveryPacketData')
try:
#try:
self.known_hosts[ip].dispatchDiscoveryPacketData(data)
except Exception:
pass
#except Exception, error:
# self.warning(error)
# GUI update signal
louie.send('UPnT.host_discovery_end', None, ip)
def hostRemoved(self, ip):
"""Remove host from the known hosts list"""
self.known_hosts.pop(ip)
"""
Remove host from the known hosts list
"""
self.debug('hostRemoved(%r)' % ip)
self._hosts_to_remove.append(ip)
def removeHosts(self):
self.known_hosts = None
......
This diff is collapsed.
......@@ -12,18 +12,16 @@ from twisted.internet import reactor, defer
import louie
from upntest.testdevice import TestDevice
from upntest.testservice import TestService
from upntest.serverdevice import ServerDevice
from upntest.service import Service
from coherence.upnp.core import utils
from coherence import log
#from coherence.extern.logger import Logger
#log = Logger('UPnT.TestHost')
class TestHost(log.Loggable):
class Host(log.Loggable):
"""helper class to keep track of hosts and their behaviour"""
logCategory = 'UPnT_TestHost'
logCategory = 'UPnT_Host'
def __init__(self, ip, config):
......@@ -34,56 +32,39 @@ class TestHost(log.Loggable):
self._services = {}
self._create_dev_tree_func = None
#overall behaviour indicators
self._discovery_packets_valid = True
self._last_announcement = 0
#hints for compliance to recommended behaviour
self._ssdp_max_age_to_low = False
self._mx_value_to_high = False
self._date_header_not_sent = False
def getIp(self):
return self._ip
ip = property(getIp)
def dispatchDiscoveryPacketData(self, data):
self.debug('dispatchDiscoveryPacketData')
[header, payload] = data.split('\r\n\r\n', 1)
if data.lower().startswith('m-search'):
self.info('Packet is of type M_SEARCH')
self.debug('Packet is of type M_SEARCH')
d = self.checkDiscoveryPacket(header, payload)
if d is not None:
#d.addCallback(self.updateDeviceTree, header, d)
#d.addErrback(self.showPacketData, header, payload, '', d)
louie.send('UPnT.ending_deferred', None, d)
else:
self._discovery_packets_valid = False
self.showPacketData(None, header, payload, '', None)
elif data.lower().startswith('notify'):
self.info('Packet is of type NOTIFY')
self.debug('Packet is of type NOTIFY')
d = self.checkNotificationPacket(header, payload)
if d is not None:
d.addCallback(self.updateDeviceTree, header, d)
d.addErrback(self.showPacketData, header, payload, 'location', d)
else:
self._discovery_packets_valid = False
self.showPacketData(None, header, payload, '', None)
elif data.lower().startswith('http'):
self.info('Packet is of type HTTP')
self.debug('Packet is of type HTTP (M-SEARCH response)')
d = self.checkDiscoveryAnswerPacket(header, payload)
if d is not None:
d.addCallback(self.updateDeviceTree, header, d)
d.addErrback(self.showPacketData, header, payload, 'location', d)
else:
self._discovery_packets_valid = False
self.showPacketData(None, header, payload, '', None)
def ssdpDatagramsReceived(self):
return (self._ssdp_datagram_num > 0)
def msearchDatagramsReceived(self):
return (self._msearch_datagram_num > 0)
def formatHeader(self, header):
"""parses the header and returns a dictionary containing the command
and the header lines also as dictionary"""
......@@ -144,6 +125,7 @@ class TestHost(log.Loggable):
if headers.has_key('nts'):
action = headers['nts']
else:
# packet was an M-SEARCH response therefore it has no NTS header
action = 'ssdp:alive'
if action == 'ssdp:alive':
......@@ -153,13 +135,13 @@ class TestHost(log.Loggable):
if self._services.has_key(headers['usn']):
self._services[headers['usn']].update(headers)
else:
self._services[headers['usn']] = TestService(headers, self._config)
self._services[headers['usn']] = Service(headers, self._config)
else:
if self._devices.has_key(uuid):
self._devices[uuid].update(headers)
else:
self._devices[uuid] = TestDevice(headers, self._config)
self._devices[uuid] = ServerDevice(headers, self._config)
self._devices[uuid].host = self
if self._create_dev_tree_func is None:
......@@ -169,11 +151,14 @@ class TestHost(log.Loggable):
elif action == 'ssdp:byebye':
if self._devices.has_key(uuid):
if upnp_type == 'device':
self._devices[uuid].removeDevice(headers)
if self._devices.has_key(uuid):
del self._devices[uuid]
else:
if self._devices.has_key(uuid):
self._devices[uuid].removeService(headers)
if self._services.has_key(headers['usn']):
del self._services[headers['usn']]
else:
louie.send('UPnT.infoMessage', None, 'Wrong action. Something went really wrong here.')
......@@ -264,10 +249,12 @@ class TestHost(log.Loggable):
#check if 2nd part of USN header is equal to NT header if NT header is not the UUID
if headers['nt'].startswith('uuid:'):
if headers['nt'] != headers['usn']:
self.debug('NT header doesn\'t match USN header')
return None
else:
usn_split = headers['usn'].split('::')
if headers['nt'] != usn_split[1]:
self.debug('NT header doesn\'t correspond USN header')
return None
#SSDP only needs the header data
......@@ -279,7 +266,12 @@ class TestHost(log.Loggable):
#NTS has to be ssdp:alive or ssdp:byebye
if headers['nts'] == 'ssdp:alive':
return self.checkAlivePacket(headers)
elif not headers['nts'] == 'ssdp:byebye':
elif headers['nts'] == 'ssdp:byebye':
self.debug('ssdp:byebye received')
d = defer.succeed(None)
louie.send('UPnT.running_deferred', None, d)
return d
else:
louie.send('UPnT.hostValidationError', None, 'Wrong NTS header', self.ip)
self.debug('Wrong NTS header')
return None
......@@ -335,8 +327,10 @@ class TestHost(log.Loggable):
return d
def checkDiscoveryPacket(self, header, payload):
"""checks content of a discovery packet for errors and returns
True if everything looks ok"""
"""
Check content of a discovery packet for errors and return True if
everything looks ok.
"""
self.info('Processing M-SEARCH request from %s' % self.ip)
......
......@@ -10,17 +10,16 @@ from StringIO import StringIO
import louie
from testservice import *
from coherence.upnp.core import utils
from coherence import log
#from coherence.extern.logger import Logger
#log = Logger('UPnT.TestDevice')
class TestDevice(log.Loggable):
"""Class for storing data about active devices"""
class ServerDevice(log.Loggable):
"""
Class for storing data about server devices like MediaServers or
MediaRenderers.
"""
logCategory = 'UPnT_TestDevice'
logCategory = 'UPnT_ServerDevice'
def __init__(self, headers, config):
......@@ -150,18 +149,18 @@ class TestDevice(log.Loggable):
self.warning(error)
louie.send('UPnT.infoMessage', None, 'Device-Description not valid! (UUID %s)' % self._uuid)
self.info('Description:\n%s' % description)
return None
raise InvalidDescriptionException(self._uuid)
return doc
def validateDescriptionFailed(self, failure, url):
"""Error while receiving description"""
self.warning("error requesting", url)
self.warning("validateDescriptionFailed %r" % url)
return failure
def checkDeviceAnnouncement(self, doc, device_list, xpath_exp='/upnp:root/upnp:device'):
"""Take the description, extract devices and look for a TestDevice object
"""Take the description, extract devices and look for a ServerDevice object
in the existing devices list. If found, add it to the tree. If not, the
device wasn't announced."""
self.debug('checkDeviceAnnouncement')
......@@ -193,17 +192,12 @@ class TestDevice(log.Loggable):
return failure
def checkServiceAnnouncement(self, doc, device_list, service_list, xpath_exp='/upnp:root/upnp:device', d=None):
"""Take the description, extract services and look for a TestService
"""Take the description, extract services and look for a Service
object in the existing services list. If found, add it to the tree. If
not, the service wasn't announced."""
self.debug('checkServiceAnnouncement')
# some error happened in previous callbacks
if doc == None:
return None
ns = {'upnp': 'urn:schemas-upnp-org:device-1-0'}
self.debug(etree.tostring(xpath_exp, pretty_print=True))
devices = doc.xpath(xpath_exp, ns)
for device in devices:
......@@ -285,3 +279,19 @@ class TestDevice(log.Loggable):
self._expiration_notification_func = None
louie.send('UPnT.infoMessage', None, 'Device announcement of %s:%s has expired!' % (self._device_type, self._device_version))
def removeService(self, headers):
if self._services.has_key(headers['usn']):
self.debug('Sending UPnT.serviceByeBye...')
louie.send('UPnT.serviceByeBye', None, self._services[headers['usn']])
self._services[headers['usn']].eventchecker.removeEventSeq()
del self._services[headers['usn']]
class InvalidDescriptionException(StandardError):
"""Error representing an invalid device description"""
def __init__(self, uuid):
self.uuid = uuid
def __str__(self):
return 'Device-Description not valid! (UUID %s)' % (self.uuid)
\ No newline at end of file
......@@ -19,13 +19,13 @@ from StringIO import StringIO
from coherence.upnp.core import utils
from coherence import log
#from coherence.extern.logger import Logger
#log = Logger('UPnT.TestService')
class TestService(log.Loggable):
from upntest.eventing import ServerEventMessageChecks
class Service(log.Loggable):
"""Class for storing data about active devices"""
logCategory = 'UPnT_TestService'
logCategory = 'UPnT_Service'
def __init__(self, headers, config):
......@@ -47,6 +47,8 @@ class TestService(log.Loggable):
self.update(headers, True)
self.eventchecker = ServerEventMessageChecks(self)
def __str__(self):
return self.parentDevice.UUID + '::' + self.serviceType
......@@ -60,14 +62,23 @@ class TestService(log.Loggable):
self._parentDevice = parentDevice
parentDevice = property(getParentDevice, setParentDevice)
def getEventSubUrl(self):
return self._parentDevice
def setEventSubUrl(self, eventSubURL):
self._eventSubURL = eventSubURL
eventSubUrl = property(getEventSubUrl, setEventSubUrl)
def setScpdUrl(self, scpdUrl):
self._SCPDURL = scpdUrl
def getScpdUrl(self):
return self._SCPDURL
scpdUrl = property(getScpdUrl, setScpdUrl)
def getControlUrl(self):
return self._controlURL
def setControlUrl(self, controlUrl):
self._controlURL = controlUrl
def setEventSubUrl(self, eventSubURL):
self._eventSubURL = eventSubURL
controlUrl = property(getControlUrl, setControlUrl)
def checkDescriptions(self):
"""Check if description of service is valid"""
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment