Exemplo n.º 1
0
 def _dispatchSoapRequest(self, request):
     try:
         try:
             envelope = XML(request.soap_data)
             body = envelope.find("{http://schemas.xmlsoap.org/soap/envelope/}Body")
             # determine UPnP action
             action = body.find("{%s}%s" % (request.soap_ns, request.soap_action))
             # look up the action in the service
             upnp_action = self.service._actions[request.soap_action]
             # build a list of the action arguments
             in_args = {}
             for arg in action:
                 in_args[arg.tag] = arg.text
             # execute the UPnP action
             logger.log_debug("executing %s#%s" % (self.service.serviceID, request.soap_action))
             out_args = upnp_action(request, self.service, in_args)
             # return the action response
             env = Element("s:Envelope")
             env.attrib['xmlns:s'] = "http://schemas.xmlsoap.org/soap/envelope/"
             env.attrib['s:encodingStyle'] = "http://schemas.xmlsoap.org/soap/encoding/"
             env.attrib['xmlns:i'] = "http://www.w3.org/1999/XMLSchema-instance"
             body = SubElement(env, "s:Body")
             resp = SubElement(body, "u:%sResponse" % request.soap_action)
             resp.attrib['xmlns:u'] = request.soap_ns
             for (name,type,value) in out_args:
                 arg = SubElement(resp, name)
                 arg.attrib["i:type"] = type
                 arg.text = value
             output = xmlprint(env)
             return HttpResponse(200, headers={'EXT': ''}, stream=output)
         except UPNPError, e:
             raise e
         except Exception, e:
             logger.log_error("caught unhandled exception: %s" % e)
             raise UPNPError(500, "Internal server error")
Exemplo n.º 2
0
 def _notify(self, statevars):
     # create the request body
     propset = Element("e:propertyset")
     propset.attrib['xmlns:e'] = "urn:schemas-upnp-org:event-1-0"
     prop = SubElement(propset, "e:property")
     # add each evented statevar to the property set
     for statevar in statevars:
         if statevar.sendEvents:
             SubElement(prop, statevar.name).text = statevar.text_value
         else:
             raise Exception("StateVar '%s' is not evented" % statevar.name)
     postData = xmlprint(propset)
     logger.log_debug("NOTIFY property set:\n" + postData)
     # send the NOTIFY request to each callback
     for url,urlparts in self.callbacks:
         # set the NOTIFY headers
         headers = {
             'Host': urlparts.netloc,
             'Content-Type': MimeType('text', 'xml'),
             'NT': 'upnp:event',
             'NTS': 'upnp:propchange',
             'SID': self.id,
             'SEQ': self.seqid
             }
         #
         creator = protocol.ClientCreator(reactor, HTTPClientProtocol)
         request = ClientRequest("NOTIFY", urlparts.path, headers, postData)
         d = creator.connectTCP(urlparts.hostname, urlparts.port)
         d.addCallback(self._sendNotifyRequest, request)
         logger.log_debug("sending NOTIFY to %s" % url)
     self.seqid = self.seqid + 1
Exemplo n.º 3
0
 def _renew(self, sid, timeout):
     try:
         s = self._subscribers[sid]
         s.handle.reset(timeout)
         logger.log_debug("service %s renewed subscription %s for %i seconds" % (self.serviceID, sid, timeout))
     except Exception, e:
         logger.log_debug("service %s failed to renew %s: %s" % (self.serviceID, sid, str(e)))
Exemplo n.º 4
0
 def _subscribe(self, callbacks, timeout=1800):
     s = Subscription(callbacks, timeout)
     self._subscribers[s.id] = s
     logger.log_debug("service %s created new subscription %s" % (self.serviceID,s.id))
     s.handle = reactor.callLater(timeout, self._unsubscribe, s.id)
     s._notify([sv for sv in self._stateVars.values() if sv.sendEvents])
     return s
Exemplo n.º 5
0
 def _unsubscribe(self, sid):
     try:
         s = self._subscribers[sid]
         s.handle.cancel()
         del self._subscribers[sid]
         logger.log_debug("service %s unsubscribed %s" % (self.serviceID, sid))
     except Exception, e:
         logger.log_debug("service %s failed to unsubscribe %s: %s" % (self.serviceID, sid, str(e)))
Exemplo n.º 6
0
 def _sendResponses(self, host, port, responses, delayMax):
     self.transport.write(responses.pop(0) + '\r\n', (host,port))
     logger.log_debug("wrote ssdp response to %s:%i" % (host,port))
     if len(responses) > 0:
         reactor.callLater(random.randint(0, delayMax),
                           self._sendResponses,
                           host,
                           port,
                           responses,
                           delayMax)
Exemplo n.º 7
0
 def _sendByebye(self, usn, nt):
     resp = [
         'NOTIFY * HTTP/1.1',
         'HOST: 239.255.255.250:1900',
         'NTS: ssdp:byebye',
         'NT: %s' % nt,
         'USN: %s' % usn
         ]
     self.transport.write('\r\n'.join(resp) + '\r\n\r\n', (SSDP_MULTICAST_GROUP, 1900))
     logger.log_debug("sent ssdp:byebye for %s on %s" % (usn, self.interface.address))
Exemplo n.º 8
0
 def start(self):
     self.servers = []
     for addr,iface in self.interfaces.items():
         protocol = SSDPFactory(iface)
         #listener = reactor.listenMulticast(1900, protocol, addr, listenMultiple=True)
         listener = reactor.listenMulticast(1900, protocol, listenMultiple=True)
         listener.joinGroup('239.255.255.250', addr)
         listener.setOutgoingInterface(addr)
         listener.setTTL(1)
         listener.setLoopbackMode(0)
         self.servers.append((addr,protocol,listener))
         logger.log_debug("SSDP Server listening on %s:1900" % addr)
Exemplo n.º 9
0
 def unregisterDevice(self, device):
     if not device.UDN in self.devices:
         raise Exception("%s is not a registered device" % device)
     # advertise the device
     self._stopAdvertising("uuid:%s::upnp:rootdevice" % device.UDN)
     self._stopAdvertising("uuid:%s" % device.UDN)
     self._stopAdvertising("uuid:%s::%s" % (device.UDN, device.deviceType))
     # advertise each service on the device
     for svc in device._services.values():
         self._stopAdvertising("uuid:%s::%s" % (device.UDN, svc.serviceType))
     logger.log_debug("unregistered device %s" % device.UDN)
     del self.devices[device.UDN]
Exemplo n.º 10
0
def _parseTimeout(header):
    """Returns the event timeout"""
    try:
        unused,timeout = header.split('-')
        if timeout.lower() == 'infinite':
            return -1
        timeout = int(timeout)
        if timeout < 1800:
            timeout = 1800
        return timeout
    except Exception, e:
        logger.log_debug("failed to parse SUBSCRIBE timeout: %s" % str(e))
        return 1800
Exemplo n.º 11
0
 def __call__(self, request, service, arguments):
     # arguments is a dict.  key is the argument name, value is
     # the argument value as a string.
     a = self.in_args[:]
     parsed_args = []
     while not a == []:
         arg = a.pop(0)
         try:
             arg_value = arguments[arg.name]
             parsed_value = arg.parse(arg_value)
             logger.log_debug("parsed %s => '%s'" % (arg.name, arg_value))
             parsed_args.append(parsed_value)
         except KeyError:
             raise Exception("missing required InArgument %s" % arg.name)
         except Exception, e:
             raise e
Exemplo n.º 12
0
 def _sendAlive(self, usn, nt, udn):
     if not usn in self.advertisements:
         logger.log_warning("no registered advertisement for %s" % usn)
         return
     adv = self.advertisements[usn]
     resp = [
         'NOTIFY * HTTP/1.1',
         'HOST: 239.255.255.250:1900',
         'NTS: ssdp:alive',
         'NT: %s' % nt,
         'USN: %s' % usn,
         'LOCATION: http://%s:%d/%s' % (self.interface.address, 1900, udn.replace(':','_')),
         'CACHE-CONTROL: max-age=%d' % self.expires,
         'SERVER: Twisted, UPnP/1.0, Higgins'
         ]
     self.transport.write('\r\n'.join(resp) + '\r\n\r\n', (SSDP_MULTICAST_GROUP, 1900))
     logger.log_debug("sent ssdp:alive for %s on %s" % (usn, self.interface.address))
     adv.delayed = reactor.callLater(self.expires, self._sendAlive, usn, nt, udn)
Exemplo n.º 13
0
 def registerDevice(self, device):
     if device.UDN in self.devices:
         raise Exception("%s is already a registered device" % device)
     # advertise the device
     self._startAdvertising("uuid:%s::upnp:rootdevice" % device.UDN,
                            "upnp:rootdevice",
                            device.UDN)
     self._startAdvertising("uuid:%s" % device.UDN,
                            "uuid:%s" % device.UDN,
                            device.UDN)
     self._startAdvertising("uuid:%s::%s" % (device.UDN, device.deviceType),
                            device.deviceType,
                            device.UDN)
     # advertise each service on the device
     for svc in device._services.values():
         self._startAdvertising("uuid:%s::%s" % (device.UDN, svc.serviceType),
                                svc.serviceType,
                                device.UDN)
     self.devices[device.UDN] = device
     logger.log_debug("registered device %s" % device.UDN)
Exemplo n.º 14
0
 def locateChild(self, request, segments):
     segments = [part for part in segments if part != '']
     logger.log_debug("%s" % '/' + '/'.join(segments))
     # we need the Host header
     if request.host == None:
         logger.log_warning("can't determine host from request, ignoring")
         return None, []
     # this is a fix for coherence (seen on v0.6.2), which doesn't send the
     # port number as part of the Host header.
     urlparts = urlparse('http://' + request.host)
     host = '%s:1901' % urlparts.netloc
     # / returns 404
     if segments == []:
         return None, []
     # the first segment is the device UDN with ':' escaped as '_'
     device_id = segments[0].replace('_',':')
     try:
         device = self.server.devices[device_id]
     except:
         logger.log_warning("device '%s' doesn't exist" % device_id)
         return None, []
     # if the next segment is 'root-device.xml', return the device description
     segments = segments[1:]
     if segments == []:
         return StaticResource(device.getDescription(host, True), 'text/xml'), []
     # otherwise the next segment is the service ID
     service_id = segments[0].replace('_',':')
     try:
         service = device._services[service_id]
     except:
         logger.log_warning("service '%s' doesn't exist" % service_id)
         return None, []
     segments = segments[1:]
     if segments == []:
         return StaticResource(service.getDescription(), 'text/xml'), []
     if segments[0] == 'control':
         return ControlResource(service), []
     if segments[0] == 'event':
         return EventResource(service), []
     return None, []
Exemplo n.º 15
0
 def __new__(cls, name, bases, attrs):
     # TODO: verify required service attributes
     # create UDN if needed
     udn_conf_key = "UPNP_" + name + "_UDN"
     udn = conf.get(udn_conf_key)
     if udn == None:
         udn = "".join(map(lambda x: random.choice(string.letters), xrange(20)))
         conf[udn_conf_key] = udn
     attrs["UDN"] = udn
     logger.log_debug("UDN for %s is %s" % (name, udn))
     # load services
     services = {}
     for key, svc in attrs.items():
         if isinstance(svc, UPNPDeviceService):
             # add the service back-reference for each StateVar and Action
             for statevar in svc._stateVars.values():
                 statevar.service = svc
             for action in svc._actions.values():
                 action.service = svc
             services[svc.serviceID] = svc
     attrs["_services"] = services
     return super(DeviceDeclarativeParser, cls).__new__(cls, name, bases, attrs)
Exemplo n.º 16
0
 def start(self):
     from higgins.http.server import Site
     from higgins.http.channel import HTTPFactory
     self.site = Site(RootResource(self))
     self.listener = reactor.listenTCP(1901, HTTPFactory(self.site))
     logger.log_debug("UPnP Server listening on port 1901")
Exemplo n.º 17
0
 def stop(self):
     for addr,protocol,listener in self.servers:
         protocol.sendAllByebyes()
         listener.stopListening()
         logger.log_debug("SSDP server stopped listening on %s:1900" % addr)
Exemplo n.º 18
0
                parsed_value = arg.parse(arg_value)
                logger.log_debug("parsed %s => '%s'" % (arg.name, arg_value))
                parsed_args.append(parsed_value)
            except KeyError:
                raise Exception("missing required InArgument %s" % arg.name)
            except Exception, e:
                raise e
        try:
            out_args = self.action(service, request, *parsed_args)
        except UPNPError, e:
            raise e
        except Exception, e:
            logger.log_error("caught exception executing %s: %s" % (arg.name, e))
            raise UPNPError(500, "Internal server error")
        a = self.out_args[:]
        parsed_args = []
        while not a == []:
            arg = a.pop(0)
            try:
                arg_value = out_args[arg.name]
                parsed_value = arg.write(arg_value)
                logger.log_debug("wrote %s => %s" % (arg.name,parsed_value))
                parsed_args.append((arg.name, arg.type, parsed_value))
            except KeyError:
                raise Exception("missing required OutArgument %s" % arg.name)
            except Exception, e:
                raise e
        return parsed_args

__all__ = ['Action', 'InArgument', 'OutArgument']
Exemplo n.º 19
0
 def _startAdvertising(self, usn, nt, udn):
     adv = Advertisement(usn, nt, udn)
     self.advertisements[usn] = adv
     reactor.callLater(1, self._sendByebye, usn, nt)
     adv.delayed = reactor.callLater(2, self._sendAlive, usn, nt, udn)
     logger.log_debug("registered advertisement for %s" % usn)
Exemplo n.º 20
0
                body = SubElement(env, "s:Body")
                resp = SubElement(body, "u:%sResponse" % request.soap_action)
                resp.attrib['xmlns:u'] = request.soap_ns
                for (name,type,value) in out_args:
                    arg = SubElement(resp, name)
                    arg.attrib["i:type"] = type
                    arg.text = value
                output = xmlprint(env)
                return HttpResponse(200, headers={'EXT': ''}, stream=output)
            except UPNPError, e:
                raise e
            except Exception, e:
                logger.log_error("caught unhandled exception: %s" % e)
                raise UPNPError(500, "Internal server error")
        except UPNPError, e:
            logger.log_debug("failed to execute %s#%s: %s" % (self.service.serviceID, request.soap_action, e))
            return HttpResponse(500,
                headers={'EXT': ''},
                stream="""<?xml version="1.0"?>
<u:Envelope
  xmlns:u="http://schemas.xmlsoap.org/soap/envelope"
  u:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
    <u:Body>
        <u:Fault>
            <faultcode>u:Client</faultcode>
            <faultstring>UPnPError</faultstring>
            <detail>
                <UPnPError xmlns="urn:schemas-upnp-org:control-1-0">
                    <errorCode>%i</errorCode>
                    <errorDescription>%s</errorDescription>
                </UPnPError>
Exemplo n.º 21
0
 def unregisterDevice(self, device):
     del self.devices[device.UDN]
     logger.log_debug("unregistered device %s with UPnP server" % device.UDN)
Exemplo n.º 22
0
 def discoveryRequest(self, headers, (host, port)):
     def makeResponse(st, usn, location):
         resp = [
             'HTTP/1.1 200 OK',
             'DATE: %s' % strftime('%a, %d %B 20%y %H:%M:%S GMT', gmtime()),
             'EXT: ',
             'LOCATION: %s' % location,
             'SERVER: Twisted, UPnP/1.0, Higgins',
             'ST: %s' % st,
             'USN: %s' % usn,
             'CACHE-CONTROL: max-age=%d' % self.expires
             ]
         return '\r\n'.join(resp) + '\r\n'
     # if the MAN header is present, make sure its ssdp:discover
     if not headers.get('MAN', '') == '"ssdp:discover"':
         logger.log_debug("MAN header for discovery request is not 'ssdp:discover', ignoring")
         logger.log_debug2("SSDP data:\n%s" % '\n'.join(headers))
         return
     logger.log_debug('received discovery request from %s:%d for %s' % (host, port, headers['ST']))
     # Generate a response
     iface = self.interface.address
     responses = []
     # return all devices and services
     if headers['ST'] == 'ssdp:all':
         for udn,device in self.devices.items():
             # advertise the device
             responses.append(makeResponse("upnp:rootdevice",
                              "uuid:%s::upnp:rootdevice" % udn,
                              "http://%s:1901/%s" % (iface,udn.replace(':','_'))))
             responses.append(makeResponse("uuid:%s" % udn,
                              "uuid:%s" % udn,
Exemplo n.º 23
0
 def _notifySuccess(self, response):
     readAndDiscard(response.stream)
     logger.log_debug("NOTIFY succeeded")
Exemplo n.º 24
0
 def registerDevice(self, device):
     self.devices[device.UDN] = device
     logger.log_debug("registered device %s with UPnP server" % device.UDN)