def render_SUBSCRIBE(self, request): Logr.debug("(%s) SUBSCRIBE", self.service.serviceType) if request.requestHeaders.hasHeader('sid'): # Renew sid = getHeader(request, 'sid') if sid in self.service.subscriptions: self.service.subscriptions[sid].last_subscribe = time.time() self.service.subscriptions[sid].expired = False Logr.debug("(%s) Successfully renewed subscription", self.service.serviceType) else: Logr.debug("(%s) Received invalid subscription renewal", self.service.serviceType) else: # New Subscription nt = self._parse_nt(getHeader(request, 'nt')) callback = self._parse_callback(getHeader(request, 'callback')) timeout = self._parse_timeout(getHeader(request, 'timeout', False)) Logr.debug("(%s) %s %s", self.service.serviceType, callback, timeout) responseHeaders = self.service.subscribe(callback, timeout) if responseHeaders is not None and type(responseHeaders) is dict: for name, value in responseHeaders.items(): request.setHeader(name, value) return '' else: Logr.debug("(%s) SUBSCRIBE FAILED", self.service.serviceType)
def render_POST(self, request): data = request.content.getvalue() (r, header, body, attrs) = parseSOAPRPC(data, header=1, body=1, attrs=1) name = r._name kwargs = r._asdict() Logr.debug("(%s) %s", self.service.serviceType, name) if name not in self.service.actions or name not in self.service.actionFunctions: raise NotImplementedError() action = self.service.actions[name] func = self.service.actionFunctions[name] for argument in action: if argument.direction == 'in': if argument.name in kwargs: value = kwargs[argument.name] del kwargs[argument.name] kwargs[argument.parameterName] = value else: raise TypeError() result = func(**kwargs) return buildSOAP(kw={ '%sResponse' % name: result })
def stop(self): if not self.running: return Logr.debug("stop()") self.site_port.stopListening() self.running = False
def stop(self): Logr.debug("stop()") if not self.running: return self.notifySequenceLoop.stop() self.listen_port.stopListening()
def stop(self): Logr.debug("stop()") if not self.running: return self.listen_port.stopListening()
def listen(self): if self.running: raise Exception() Logr.debug("listen()") self.listen_port = reactor.listenMulticast(SSDP_PORT, self, listenMultiple=True) self.running = True
def send_NOTIFY(self, nt, uuid=None, nts='ssdp:alive'): if self.ssdp.device.bootID is None: self.ssdp.device.bootID = int(time.time()) location = self.ssdp.device.getLocation(get_default_v4_address()) if uuid is None: uuid = self.ssdp.device.uuid usn, nt = build_notification_type(uuid, nt) Logr.debug("send_NOTIFY %s:%s", nts, usn) headers = { # max-age is notifySequenceInterval + 10 minutes 'CACHE-CONTROL': 'max-age = %d' % (self.notifySequenceInterval + (10 * 60)), 'LOCATION': location, 'SERVER': self.ssdp.device.server, 'NT': nt, 'NTS': nts, 'USN': usn, 'BOOTID.UPNP.ORG': self.ssdp.device.bootID, 'CONFIGID.UPNP.ORG': self.ssdp.device.configID } self.send('NOTIFY', headers, (SSDP_ADDR_V4, SSDP_PORT))
def render(self, request): try: return Resource.render(self, request) except UnsupportedMethod, e: Logr.debug("(%s) unhandled method %s", self.service.serviceType, request.method) raise e
def dump(self): Logr.debug("xml tree dumped") scpd = et.Element('scpd', attrib={ 'xmlns': 'urn:schemas-upnp-org:service-1-0', }) # specVersion specVersion = et.Element('specVersion') specVersion.append(make_element('major', str(self.version[0]))) specVersion.append(make_element('minor', str(self.version[1]))) scpd.append(specVersion) # actionList actionList = et.Element('actionList') for action_name, action_args in self.actions.items(): action = et.Element('action') action.append(make_element('name', action_name)) argumentList = et.Element('argumentList') for arg in action_args: argumentList.append(arg.dump()) action.append(argumentList) actionList.append(action) scpd.append(actionList) # serviceStateTable serviceStateTable = et.Element('serviceStateTable') for stateVariable in self.stateVariables.values(): serviceStateTable.append(stateVariable.dump()) scpd.append(serviceStateTable) return scpd
def startProtocol(self): self.transport.setTTL(2) for interface in self.interfaces: self.transport.joinGroup(SSDP_ADDR_V4, interface) if interface == '': Logr.debug("joined on ANY") else: Logr.debug("joined on %s", interface)
def getChild(self, path, request): if path == 'event': return ServiceEventResource(self.service) if path == 'control': return ServiceControlResource(self.service) Logr.debug("(%s) unhandled request %s", self.service.serviceType, path) return Resource()
def listen(self): if self.running: raise Exception() Logr.debug("listen()") self.listen_port = reactor.listenUDP(0, self, self.interface) self.running = True Logr.debug("listening on %s", self.listen_port.socket.getsockname()) reactor.callLater(0, self._notifySequenceCall, True) self.notifySequenceLoop.start(self.notifySequenceInterval)
def getChild(self, path, request): # Hack to fix twisted not accepting absolute URIs path, request = twisted_absolute_path(path, request) if path == '': return ServeResource(self.device.dumps(), 'application/xml') for service in self.device.services: if path == service.serviceId: return ServiceResource(service) Logr.debug("unhandled request %s", path) return Resource()
def listen(self, interface=''): if self.running: raise Exception() Logr.debug("listen()") self.site = Site(self) self.site_port = reactor.listenTCP(0, self.site, interface=interface) self.listen_address = self.site_port.socket.getsockname()[0] self.listen_port = self.site_port.socket.getsockname()[1] self.running = True self.device.location = "http://%s:" + str(self.listen_port) Logr.debug("listening on %s:%s", self.listen_address, self.listen_port)
def _notifySequenceCall(self, initial=False): Logr.debug("_notifySequenceCall initial=%s", initial) # 3 + 2d + k # - 3 rootdevice # - 2d embedded devices # - k distinct services # TODO: Embedded device calls call_count = 3 + len(self.ssdp.device.services) call_delay = self.notifySequenceInterval / call_count if initial: call_delay = 1 Logr.debug("sending %d calls with delay of %ds per call, total duration of %ds", call_count, call_delay, call_count * call_delay) self.sendall_NOTIFY(call_delay)
def notify(self, props): """ :type props: EventProperty or list of EventProperty """ if type(props) is not list: props = [props] if self.expired: return if self.check_expiration(): Logr.info("(%s) subscription expired", self.sid) return # noinspection PyTypeChecker Logr.debug("(%s) notify(), %d props: %s", self.sid, len(props), str(props)) headers = { 'NT': 'upnp:event', 'NTS': 'upnp:propchange', 'SID': self.sid, 'SEQ': self.next_notify_key } _propertyset = et.Element('e:propertyset', attrib={ 'xmlns:e': 'urn:schemas-upnp-org:event-1-0' }) for prop in props: _property = et.Element('e:property') _property.append(make_element(prop.name, str(prop.value))) _propertyset.append(_property) data = '<?xml version="1.0"?>' + et.tostring(_propertyset) try: requests.request('NOTIFY', self.callback, headers=headers, data=data) except requests.exceptions.ConnectionError: pass self._increment_notify_key()
def dump(self): Logr.debug("xml tree dumped") root = et.Element('root', attrib={ 'configId': str(self.configID) }) for prefix, namespace in self.namespaces.items(): if prefix == '': prefix = 'xmlns' else: prefix = 'xmlns:' + prefix root.attrib[prefix] = namespace # specVersion specVersion = et.Element('specVersion') specVersion.append(make_element('major', str(self.version[0]))) specVersion.append(make_element('minor', str(self.version[1]))) root.append(specVersion) root.append(self.dump_device()) return root
def render_UNSUBSCRIBE(self, request): Logr.debug("(%s) UNSUBSCRIBE", self.service.serviceType) if request.requestHeaders.hasHeader('sid'): # Cancel sid = getHeader(request, 'sid') if sid in self.service.subscriptions: self.service.subscriptions[sid].expired = True Logr.debug("(%s) Successfully unsubscribed", self.service.serviceType) else: Logr.debug("(%s) Received invalid UNSUBSCRIBE request", self.service.serviceType) else: Logr.debug("(%s) Received invalid UNSUBSCRIBE request", self.service.serviceType)
def stop(self): Logr.debug("stop()") self.clients.stop() self.listener.stop()
def render(self, request): try: return Resource.render(self, request) except UnsupportedMethod, e: Logr.debug("(%s) %s", self.service.serviceType, request.method) raise e
self.notifySequenceLoop.stop() self.listen_port.stopListening() def respond(self, headers, (address, port)): Logr.debug("respond() %s %d", address, port) msg = 'HTTP/1.1 200 OK\r\n' msg += headers_join(headers) msg += '\r\n\r\n' try: self.transport.write(msg, (address, port)) except socket.error, e: Logr.warning("socket.error: %s", e) def send(self, method, headers, (address, port)): Logr.debug("send() %s:%s", address, port) msg = '%s * HTTP/1.1\r\n' % method msg += headers_join(headers) msg += '\r\n\r\n' try: self.transport.write(msg, (address, port)) except socket.error, e: Logr.warning("socket.error: %s", e) def send_NOTIFY(self, nt, uuid=None, nts='ssdp:alive'): if self.ssdp.device.bootID is None: self.ssdp.device.bootID = int(time.time()) location = self.ssdp.device.getLocation(get_default_v4_address())
def listen(self): Logr.debug("listen()") self.clients.listen() self.listener.listen()
def stop(self): Logr.debug("stop()") for client in self.clients: client.stop()
def listen(self): Logr.debug("listen()") for client in self.clients: client.listen()