Example #1
0
class StompDispatcherResource(resource.Resource):
    logger = logging.get_logger('orbited.system.test.stompdispatcher')

    def render(self, request):
        self.logger.info("request received")
        if config['[test]']['stompdispatcher.enabled'] == '1':
            destination = request.args['dest'][0]
            message = request.args['msg'][0]
            self.logger.info("sending %s to %s" % (message, destination))
            config['morbid_instance'].send(destination, message)
        else:
            self.logger.info(
                "stompdispatcher not enabled - message not dispatched")
            return "alert('stompdispatcher not enabled');"
Example #2
0
def setupSite(backend):
    from orbited import logging, config
    config.map['[access]'][('localhost',61613)] = ['*']
    logging.setup(config.map)
    import orbited.start

    orbited.start.logger = logging.get_logger('orbited.start')

    root = static.File(os.path.dirname(backhardding.__file__) + "/html")
    root.putChild('control', BackharddiNGControl(backend))
    static_files = static.File(os.path.dirname(orbited.__file__) + "/static")
    root.putChild('static', static_files)
    orbited.start._setup_protocols(root)
    site = server.Site(root,'/dev/null')
    return site
Example #3
0
class TCPResource(resource.Resource):

    logger = logging.get_logger('orbited.cometsession.TCPResource')

    def __init__(self, listeningPort):
        resource.Resource.__init__(self)
        self.listeningPort = listeningPort
        self.static_files = static.File(
            os.path.join(os.path.dirname(__file__), 'static'))
        self.connections = {}

    def render(self, request):
        key = None
        while key is None or key in self.connections:
            key = str(uuid.uuid4()).replace('-', '')
        # request.client and request.host should be address.IPv4Address classes
        hostHeader = request.received_headers.get('host', '')
        self.connections[key] = TCPConnectionResource(self, key,
                                                      request.client,
                                                      request.host, hostHeader)
        self.listeningPort.connectionMade(self.connections[key])
        self.logger.debug('created conn: ', repr(self.connections[key]))
        request.setHeader('cache-control', 'no-cache, must-revalidate')
        return key

    def getChild(self, path, request):
        if path == 'static':
            return self.static_files
        if path not in self.connections:
            if 'htmlfile' in request.path:
                return transports.htmlfile.CloseResource()
            return error.NoResource("<script>alert('whoops');</script>")


#        print 'returning self.connections[%s]' % (path,)
        return self.connections[path]

    def removeConn(self, conn):
        if conn.key in self.connections:
            del self.connections[conn.key]

    def connectionMade(self, conn):
        self.listeningPort.connectionMade(conn)
Example #4
0
class XHRStreamingTransport(CometTransport):

    logger = logging.get_logger('orbited.transports.xhrstream.XHRStreamingTransport')

    def opened(self):
        self.totalBytes = 0
        # Force reconnect ever 45 seconds
#        self.close_timer = reactor.callLater(45, self.triggerCloseTimeout)
        self.request.setHeader('content-type', 'application/x-orbited-event-stream')
        # Safari/Tiger may need 256 bytes
        self.request.write(' ' * 256)

    def triggerCloseTimeout(self):
        self.logger.debug('triggerCloseTimeout called')
        self.close()

    def write(self, packets):
        self.logger.debug('write %r' % packets)
        # TODO why join the packets here?  why not do N request.write?
        payload = self.encode(packets)
        self.logger.debug('WRITE ' + payload)
        self.request.write(payload)
        self.totalBytes += len(payload)
        if (self.totalBytes > MAXBYTES):
            self.logger.debug('over maxbytes limit')
            self.close()

    def encode(self, packets):
        output = []
        for packet in packets:
            for i, arg in enumerate(packet):
                if i == len(packet) -1:
                    output.append('0')
                else:
                    output.append('1')
                output.append(str(len(arg)))
                output.append(',')
                output.append(arg)
        return "".join(output)

    def writeHeartbeat(self):
        self.logger.debug('writeHeartbeat, ' + repr(self))
        self.request.write('x')
Example #5
0
class LongPollingTransport(CometTransport):

    logger = logging.get_logger(
        'orbited.transports.longpoll.LongPollingTransport')

    def opened(self):
        self.totalBytes = 0
        # Force reconnect ever 45 seconds
        self.close_timer = reactor.callLater(30, self.triggerCloseTimeout)
        #        self.request.setHeader('content-type', 'application/x-orbited-event-stream')
        self.request.setHeader('cache-control', 'no-cache, must-revalidate')

    def triggerCloseTimeout(self):
        self.close()

    def write(self, packets):
        # TODO: we can optimize this. In the case where packets contains a
        #       single packet, and its a ping, just don't send it. (instead,
        #       close the connection. the re-open will prompt the ack)

        self.logger.debug('write %r' % packets)
        payload = self.encode(packets)
        self.logger.debug('WRITE ' + payload)
        self.request.write(payload)
        self.close()

    def encode(self, packets):
        output = []
        for packet in packets:
            for i, arg in enumerate(packet):
                if i == len(packet) - 1:
                    output.append('0')
                else:
                    output.append('1')
                output.append(str(len(arg)))
                output.append(',')
                output.append(arg)
        return "".join(output)

    def writeHeartbeat(self):
        # NOTE: no heartbeats...
        pass
Example #6
0
class ProxyOutgoingProtocol(Protocol):
    """
    Handles the protocol between orbited and backend server.
    """

    logger = logging.get_logger('orbited.proxy.ProxyOutgoingProtocol')

    def __init__(self, incomingConn):
        # TODO rename this to incomingProtocol
        self.incomingConn = incomingConn

    def connectionMade(self):
        self.incomingConn.outgoingConnectionEstablished(self)
        config.map['globalVars']['connections'] += 1

    def dataReceived(self, data):
        self.logger.debug("dataReceived %r" % data)
        self.incomingConn.write(data)

    def connectionLost(self, reason):
        self.incomingConn.outgoingConnectionLost(self, reason)
        config.map['globalVars']['connections'] -= 1
Example #7
0
class PollingTransport(CometTransport):

    logger = logging.get_logger('orbited.transports.poll.PollingTransport')

    def opened(self):
        self.request.setHeader('cache-control', 'no-cache, must-revalidate')

    # NOTE: we override this so we can close as soon as we send out any waiting
    #       packets. We can't put the self.close call inside of self.write
    #       because sometimes there will be no packets to write.
    def flush(self):
        self.logger.debug('flush')
        CometTransport.flush(self)
        self.close()

    def write(self, packets):
        self.logger.debug('write %r' % packets)
        payload = self.encode(packets)
        self.logger.debug('WRITE ' + payload)
        self.request.write(payload)

    def encode(self, packets):
        output = []
        for packet in packets:
            for i, arg in enumerate(packet):
                if i == len(packet) - 1:
                    output.append('0')
                else:
                    output.append('1')
                output.append(str(len(arg)))
                output.append(',')
                output.append(arg)
        return "".join(output)

    def writeHeartbeat(self):
        # NOTE: no heartbeats...
        pass
Example #8
0
from orbited import logging
from twisted.web import server, resource
from twisted.internet import defer, reactor
logger = logging.get_logger('orbited.transports.base.CometTransport')
class CometTransport(resource.Resource):
    HEARTBEAT_INTERVAL = 5

    def __init__(self, conn):
        self.conn = conn
        self.open = False
        self.closed = False

    def render(self, request):
        self.open = True
        self.packets = []
        self.request = request
        self.opened()
#        self.request.notifiyFinish().addCallback(self.finished)
        self.resetHeartbeat()
        self.closeDeferred = defer.Deferred()
        self.conn.transportOpened(self)
        return server.NOT_DONE_YET

    def resetHeartbeat(self):
        self.heartbeatTimer = reactor.callLater(self.HEARTBEAT_INTERVAL, self.doHeartbeat)

    def doHeartbeat(self):
        if self.closed:
            logger.debug("don't send hearbeat -- we should be closed", )
            raise Exception("show tb...")
        else:
Example #9
0
from orbited import logging
from twisted.web import server, resource
from twisted.internet import defer, reactor
logger = logging.get_logger('orbited.transports.base.CometTransport')


class CometTransport(resource.Resource):
    HEARTBEAT_INTERVAL = 5

    def __init__(self, conn):
        self.conn = conn
        self.open = False
        self.closed = False

    def render(self, request):
        self.open = True
        self.packets = []
        self.request = request
        self.opened()
        #        self.request.notifiyFinish().addCallback(self.finished)
        self.resetHeartbeat()
        self.closeDeferred = defer.Deferred()
        self.conn.transportOpened(self)
        return server.NOT_DONE_YET

    def resetHeartbeat(self):
        self.heartbeatTimer = reactor.callLater(self.HEARTBEAT_INTERVAL,
                                                self.doHeartbeat)

    def doHeartbeat(self):
        if self.closed:
Example #10
0
def main():
    try:
        import twisted
    except ImportError:
        print "Orbited requires Twisted, which is not installed. See http://twistedmatrix.com/trac/ for installation instructions."
        sys.exit(1)
    import platform
    if platform.system() == "Windows":
        try:
            import win32api
        except ImportError:
            print "Orbited for Windows requires the Python for Windows Extensions, which are not installed. See http://python.net/crew/mhammond/win32/ for installation instructions."
            sys.exit(1)
    from optparse import OptionParser
    parser = OptionParser()
    parser.add_option("-c",
                      "--config",
                      dest="config",
                      default=None,
                      help="path to configuration file")
    parser.add_option("-v",
                      "--version",
                      dest="version",
                      action="store_true",
                      default=False,
                      help="print Orbited version")
    parser.add_option("-p",
                      "--profile",
                      dest="profile",
                      action="store_true",
                      default=False,
                      help="run Orbited with a profiler")
    parser.add_option(
        "-q",
        "--quickstart",
        dest="quickstart",
        action="store_true",
        default=False,
        help="run Orbited on port 8000 and MorbidQ on port 61613")

    (options, args) = parser.parse_args()

    if args:
        print 'the "orbited" command does not accept positional arguments. type "orbited -h" for options.'
        sys.exit(1)

    if options.version:
        print "Orbited version: %s" % (version, )
        sys.exit(0)

    if options.quickstart:
        config.map['[listen]'].append('http://:8000')
        config.map['[listen]'].append('stomp://:61613')
        config.map['[access]'][('localhost', 61613)] = ['*']
        print "Quickstarting Orbited"
    else:
        # load configuration from configuration
        # file and from command line arguments.
        config.setup(options=options)

    logging.setup(config.map)

    # we can now safely get loggers.
    global logger
    logger = logging.get_logger('orbited.start')

    # NB: we need to install the reactor before using twisted.
    reactor_name = config.map['[global]'].get('reactor')
    if reactor_name:
        install = _import('twisted.internet.%sreactor.install' % reactor_name)
        install()
        logger.info('using %s reactor' % reactor_name)

    ############
    # This crude garbage corrects a bug in twisted
    #   Orbited ticket: http://orbited.org/ticket/111
    #   Twisted ticket: http://twistedmatrix.com/trac/ticket/2447
    import twisted.web.http
    twisted.web.http.HTTPChannel.setTimeout = lambda self, arg: None
    twisted.web.http.HTTPChannel.resetTimeout = lambda self: None
    ############

    from twisted.internet import reactor
    from twisted.web import resource
    from twisted.web import server
    from twisted.web import static
    import orbited.system

    root = resource.Resource()
    static_files = static.File(
        os.path.join(os.path.dirname(__file__), 'static'))
    root.putChild('static', static_files)
    root.putChild('system', orbited.system.SystemResource())

    if config.map['[test]']['stompdispatcher.enabled'] == '1':
        logger.info('stompdispatcher enabled')

    #static_files.putChild('orbited.swf', static.File(os.path.join(os.path.dirname(__file__), 'flash', 'orbited.swf')))
    site = server.Site(root)

    _setup_protocols(root)
    _setup_static(root, config.map)
    start_listening(site, config.map, logger)

    # switch uid and gid to configured user and group.
    if os.name == 'posix' and os.getuid() == 0:
        user = config.map['[global]'].get('user')
        group = config.map['[global]'].get('group')
        if user:
            import pwd
            import grp
            try:
                pw = pwd.getpwnam(user)
                uid = pw.pw_uid
                if group:
                    gr = grp.getgrnam(group)
                    gid = gr.gr_gid
                else:
                    gid = pw.pw_gid
                    gr = grp.getgrgid(gid)
                    group = gr.gr_name
            except Exception, e:
                logger.error('Aborting; Unknown user or group: %s' % e)
                sys.exit(1)
            logger.info('switching to user %s (uid=%d) and group %s (gid=%d)' %
                        (user, uid, group, gid))
            os.setgid(gid)
            os.setuid(uid)
        else:
            logger.error(
                'Aborting; You must define a user (and optionally a group) in the configuration file.'
            )
            sys.exit(1)
Example #11
0
from orbited.util import format_block
from orbited import json
from twisted.internet import reactor
from orbited import logging
from orbited.transports.base import CometTransport
from twisted.web import resource

MAXBYTES = 1048576
# MAXBYTES = 64 # for testing

from orbited import logging

logger = logging.get_logger("orbited.transports.htmlfile.HTMLFileTransport")


class HTMLFileTransport(CometTransport):
    initialData = format_block(
        """
            <html>
             <head>
              <script src="../static/HTMLFileFrame.js"></script>
             </head>
             <body>
        """
    )
    initialData += " " * max(0, 256 - len(initialData)) + "\n"

    def opened(self):
        logger.debug("opened!")
        # Force reconnect ever 30 seconds
        self.totalBytes = 0
Example #12
0
from orbited.util import format_block
from orbited import json
from twisted.internet import reactor
from base import CometTransport

from orbited import logging
logger = logging.get_logger('orbited.transports.sse.SSETransport')


class SSETransport(CometTransport):
    HEARTBEAT_INTERVAL = 30

    def opened(self):
        self.request.setHeader('content-type',
                               'application/x-dom-event-stream')
        self.request.setHeader('cache-control', 'no-cache, must-revalidate')

    def write(self, packets):
        payload = json.encode(packets)
        data = ('Event: payload\n' +
                '\n'.join(['data: %s' % line
                           for line in payload.splitlines()]) + '\n\n')
        self.request.write(data)

    def writeHeartbeat(self):
        logger.debug('writeHeartbeat')
        self.request.write('Event: heartbeat\n\n')
Example #13
0
def main():
    try:
        import twisted
    except ImportError:
        print "Orbited requires Twisted, which is not installed. See http://twistedmatrix.com/trac/ for installation instructions."
        sys.exit(1)

    #################
    # This corrects a bug in Twisted 8.2.0 for certain Python 2.6 builds on Windows
    #   Twisted ticket: http://twistedmatrix.com/trac/ticket/3868
    #     -mario
    try:
        from twisted.python import lockfile
    except ImportError:
        from orbited import __path__ as orbited_path
        sys.path.append(os.path.join(orbited_path[0],"hotfixes","win32api"))
        from twisted.python import lockfile
        lockfile.kill = None
    #################

    from optparse import OptionParser
    parser = OptionParser()
    parser.add_option(
        "-c",
        "--config",
        dest="config",
        default=None,
        help="path to configuration file"
    )
    parser.add_option(
        "-v",
        "--version",
        dest="version",
        action="store_true",
        default=False,
        help="print Orbited version"
    )
    parser.add_option(
        "-p",
        "--profile",
        dest="profile",
        action="store_true",
        default=False,
        help="run Orbited with a profiler"
    )
    parser.add_option(
        "-q",
        "--quickstart",
        dest="quickstart",
        action="store_true",
        default=False,
        help="run Orbited on port 8000 and MorbidQ on port 61613"
    )

    (options, args) = parser.parse_args()

    if args:
        print 'the "orbited" command does not accept positional arguments. type "orbited -h" for options.'
        sys.exit(1)

    if options.version:
        print "Orbited version: %s" % (version,)
        sys.exit(0)

    if options.quickstart:
        config.map['[listen]'].append('http://:8000')
        config.map['[listen]'].append('stomp://:61613')
        config.map['[access]'][('localhost',61613)] = ['*']
        print "Quickstarting Orbited"
    else:
        # load configuration from configuration
        # file and from command line arguments.
        config.setup(options=options)

    logging.setup(config.map)

    # we can now safely get loggers.
    global logger; logger = logging.get_logger('orbited.start')


    # NB: we need to install the reactor before using twisted.
    reactor_name = config.map['[global]'].get('reactor')
    if reactor_name:
        install = _import('twisted.internet.%sreactor.install' % reactor_name)
        install()
        logger.info('using %s reactor' % reactor_name)

    ############
    # This crude garbage corrects a bug in twisted
    #   Orbited ticket: http://orbited.org/ticket/111
    #   Twisted ticket: http://twistedmatrix.com/trac/ticket/2447
    import twisted.web.http
    twisted.web.http.HTTPChannel.setTimeout = lambda self, arg: None
    twisted.web.http.HTTPChannel.resetTimeout = lambda self: None
    ############

    from twisted.internet import reactor
    from twisted.web import resource
    from twisted.web import server
    from twisted.web import static
    import orbited.system

    root = resource.Resource()
    static_files = static.File(os.path.join(os.path.dirname(__file__), 'static'))
    root.putChild('static', static_files)
    root.putChild('system', orbited.system.SystemResource())
    
    if config.map['[test]']['stompdispatcher.enabled'] == '1':
        logger.info('stompdispatcher enabled')
    
    #static_files.putChild('orbited.swf', static.File(os.path.join(os.path.dirname(__file__), 'flash', 'orbited.swf')))
    site = server.Site(root)

    _setup_protocols(root)
    _setup_static(root, config.map)
    start_listening(site, config.map, logger)

    # switch uid and gid to configured user and group.
    if os.name == 'posix' and os.getuid() == 0:
        user = config.map['[global]'].get('user')
        group = config.map['[global]'].get('group')
        if user:
            import pwd
            import grp
            try:
                pw = pwd.getpwnam(user)
                uid = pw.pw_uid
                if group:
                    gr = grp.getgrnam(group)
                    gid = gr.gr_gid
                else:
                    gid = pw.pw_gid
                    gr = grp.getgrgid(gid)
                    group = gr.gr_name
            except Exception, e:
                logger.error('Aborting; Unknown user or group: %s' % e)
                sys.exit(1)
            logger.info('switching to user %s (uid=%d) and group %s (gid=%d)' % (user, uid, group, gid))
            os.setgid(gid)
            os.setuid(uid)
        else:
            logger.error('Aborting; You must define a user (and optionally a group) in the configuration file.')
            sys.exit(1)
Example #14
0
class ProxyIncomingProtocol(Protocol):
    """
    Handles the protocol between the browser and orbited, and proxies
    the data to a backend server.
    """

    logger = logging.get_logger('orbited.proxy.ProxyIncomingProtocol')

    def connectionMade(self):
        # TODO: add handshake timer
        self.transport.pingTimeout = pingTimeout
        self.transport.pingInterval = pingInterval
        self.logger.debug("connectionMade")
        self.state = 'handshake'
        # TODO rename this to outgoingProtocol
        self.outgoingConn = None
        self.completedHandshake = False

    def dataReceived(self, data):
        # NB: this only receives whole frames;  so we will just decode
        #     data as-is.
        # NB: its cometsession.py:TCPConnectionResource that makes sure
        #     we receive whole frames here.
        self.logger.debug('dataReceived: data=%r' % data)
        self.logger.debug('self.outgoingConn is', self.outgoingConn)

        if self.outgoingConn:
            # NB: outgoingConn is-a ProxyOutgoingProtocol
            self.logger.debug("write (out): %r" % data)
            return self.outgoingConn.transport.write(data)
        if self.state == "handshake":
            try:
                data = data.strip()
                host, port = data.split(':')
                port = int(port)
                self.completedHandshake = True
            except:
                self.logger.error("failed to connect on handshake", tb=True)
                self.transport.write("0" + str(ERRORS['InvalidHandshake']))
                self.transport.loseConnection()
                return
            peer = self.transport.getPeer()
            self.fromHost = peer.host
            self.fromPort = peer.port
            self.toHost = host
            self.toPort = port
            allowed = False
            for source in config.map['[access]'].get((host, port), []):
                if source == self.transport.hostHeader or source == '*':
                    allowed = True
                    break
            if not allowed:
                self.logger.warn(
                    'Unauthorized connect from %r:%d to %r:%d' %
                    (self.fromHost, self.fromPort, self.toHost, self.toPort))
                self.transport.write("0" + str(ERRORS['Unauthorized']))
                self.transport.loseConnection()
                return
            self.logger.access(
                'new connection from %s:%s to %s:%d' %
                (self.fromHost, self.fromPort, self.toHost, self.toPort))
            self.state = 'connecting'
            client = ClientCreator(reactor, ProxyOutgoingProtocol, self)
            client.connectTCP(host, port).addErrback(self.errorConnection)
            # TODO: connect timeout or onConnectFailed handling...
        else:
            self.transport.write("0" + str(ERRORS['InvalidHandshake']))
            self.state = 'closed'
            self.transport.loseConnection()

    def errorConnection(self, err):
        self.logger.warn("Connection Error %s" % (err, ))
        self.transport.write("0" + str(ERRORS['RemoteConnectionFailed']))
        self.transport.loseConnection()

    def connectionLost(self, reason):
        self.logger.debug("connectionLost %s" % reason)
        if self.outgoingConn:
            self.outgoingConn.transport.loseConnection()
        if self.completedHandshake:
            self.logger.access(
                'connection closed from %s:%s to %s:%s' %
                (self.fromHost, self.fromPort, self.toHost, self.toPort))

    def outgoingConnectionEstablished(self, outgoingConn):
        if self.state == 'closed':
            return outgoingConn.transport.loseConnection()
        self.outgoingConn = outgoingConn
        self.transport.write('1')
        self.state = 'proxy'  # Not really necessary...

    def outgoingConnectionLost(self, outgoingConn, reason):
        self.logger.debug("remoteConnectionLost %s" % reason)
        self.transport.loseConnection()

    def write(self, data):
        #        data = base64.b64encode(data)
        self.logger.debug("write %r" % data)
        self.transport.write(data)
Example #15
0
class TCPConnectionResource(resource.Resource):
    pingTimeout = 30
    pingInterval = 30
    logger = logging.get_logger('orbited.cometsession.TCPConnectionResource')

    def __init__(self, root, key, peer, host, hostHeader, **options):
        resource.Resource.__init__(self)
        self.root = root
        self.key = key
        self.peer = peer
        self.host = host
        self.hostHeader = hostHeader
        self.transport = None
        self.cometTransport = None
        self.parentTransport = None
        self.options = {}
        self.msgQueue = []
        self.unackQueue = []
        self.lastAckId = 0
        self.packetId = 0
        self.pingTimer = None
        self.timeoutTimer = None
        self.closeTimer = None
        self.lostTriggered = False
        self.resetPingTimer()
        self.open = False
        self.closed = False
        self.closing = False

    def getPeer(self):
        return self.peer

    def getHost(self):
        return self.host

    def write(self, data):
        self.send(data)

    # this is never used, right?
    def writeSequence(self, data):
        for datum in data:
            self.write(datum)

    def loseConnection(self):
        # TODO: self.close() ?
        self.close('loseConnection', True)
        return None

    def connectionLost(self):
        self.logger.debug('connectionLost... already triggered?',
                          self.lostTriggered)
        if not self.lostTriggered:
            self.logger.debug('do trigger')
            self.lostTriggered = True
            self.parentTransport.connectionLost()

    def getChild(self, path, request):
        if path in transports.map:
            return transports.create(path, self)
        return error.NoResource("No such child resource.")

    def render(self, request):
        self.logger.debug('render: request=%r' % request)
        stream = request.content.read()
        self.logger.debug('render: request.content=%r' % stream)
        ack = request.args.get('ack', [None])[0]
        if ack:
            try:
                ack = int(ack)
                self.ack(ack)
            except ValueError:
                pass
        encoding = request.received_headers.get('tcp-encoding', None)
        # TODO instead of .write/.finish just return OK?
        request.write('OK')
        request.finish()
        self.resetPingTimer()
        # TODO why not call parseData here?
        reactor.callLater(0, self.parseData, stream)
        return server.NOT_DONE_YET

    def parseData(self, data):
        # TODO: this method is filled with areas that really should be put
        #       inside try/except blocks. We don't want errors caused by
        #       malicious IO.
        self.logger.debug('RECV: ' + data)
        frames = []
        curFrame = []
        while data:
            self.logger.debug([data, frames, curFrame])
            isLast = data[0] == '0'
            l, data = data[1:].split(',', 1)
            l = int(l)
            arg = data[:l]
            data = data[l:]
            curFrame.append(arg)
            if isLast:
                frames.append(curFrame)
                curFrame = []

        # TODO: do we really need the id? maybe we should take it out
        #       of the protocol...
        #       -mcarter 7-29-08
        #       I think its a safenet for unintentinal bugs;  we should
        #       compare it with the last one we received, and error or
        #       ignore if its not what we expect.
        #       -- rgl
        for args in frames:
            self.logger.debug('parseData: frame=%r' % args)
            id = args[0]
            name = args[1]
            if name == 'close':
                if len(args) != 2:
                    # TODO kill the connection with error.
                    pass
                self.loseConnection()
            elif name == 'data':
                # TODO: should there be a try/except around this block?
                #       we don't want app-level code to break and cause
                #       only some packets to be delivered.
                if len(args) != 3:
                    # TODO kill the connection with error.
                    pass
                data = base64.b64decode(args[2])
                # NB: parentTransport is-a FakeTCPTransport.
                self.parentTransport.dataReceived(data)
            elif name == 'ping':
                if len(args) != 2:
                    # TODO kill the connection with error.
                    pass
                # TODO: do we have to do anything? I don't think so...
                #       -mcarter 7-30-08
                self.logger.debug('parseData: PING? PONG!')

    # Called by the callback attached to the CometTransport
    def transportClosed(self, transport):
        if transport is self.cometTransport:
            self.cometTransport = None

    # Called by transports.CometTransport.render
    def transportOpened(self, transport):
        self.resetPingTimer()
        if self.cometTransport:
            self.cometTransport.close()
            self.cometTransport = None
        self.logger.debug("new transport: " + repr(transport))
        self.cometTransport = transport
        transport.CONNECTION = self
        transport.onClose().addCallback(self.transportClosed)
        ack = transport.request.args.get('ack', [None])[0]
        if ack:
            try:
                ack = int(ack)
                self.ack(ack)
            except ValueError:
                pass
        self.resendUnackQueue()
        self.sendMsgQueue()
        if not self.open:
            self.open = True
            self.cometTransport.sendPacket("open", self.packetId)
        self.cometTransport.flush()

    def resetPingTimer(self):
        self.cancelTimers()
        self.pingTimer = reactor.callLater(self.pingInterval, self.sendPing)

    def sendPing(self):
        self.pingTimer = None
        self.send(TCPPing())
        self.timeoutTimer = reactor.callLater(self.pingTimeout, self.timeout)

    def timeout(self):
        self.timeoutTimer = None
        self.close("timeout", True)

    def cancelTimers(self):
        if self.timeoutTimer:
            self.timeoutTimer.cancel()
            self.timeoutTimer = None
        if self.pingTimer:
            self.pingTimer.cancel()
            self.pingTimer = None

    def hardClose(self):
        self.closed = True
        self.cancelTimers()
        if self.closeTimer:
            self.closeTimer.cancel()
            self.closeTimer = None
        if self.cometTransport:
            self.cometTransport.close()
            self.cometTransport = None
        self.connectionLost()
        self.root.removeConn(self)

    def close(self, reason="", now=False):
        if self.closed:
            self.logger.debug('close called - already closed')
            return
        self.closing = True
        self.logger.debug('close reason=%s %s' % (reason, repr(self)))
        self.send(TCPClose(reason))
        if now:
            self.hardClose()
        elif not self.closing:
            self.cancelTimers()
            self.closeTimer = reactor.callLater(self.pingInterval,
                                                self.hardClose)

    def ack(self, ackId):
        self.logger.debug('ack ackId=%s' % (ackId, ))
        ackId = min(ackId, self.packetId)
        if ackId <= self.lastAckId:
            return
        for i in range(ackId - self.lastAckId):
            (data, packetId) = self.unackQueue.pop(0)
            if isinstance(data, TCPClose):
                # Really close
                self.close("close acked", True)
        self.lastAckId = ackId

    def sendMsgQueue(self):
        while self.msgQueue and self.cometTransport:
            self.send(self.msgQueue.pop(0), flush=False)

    def send(self, data, flush=True):
        if not self.cometTransport:
            self.msgQueue.append(data)
        else:
            self.packetId += 1
            self._send(data, self.packetId)
            self.unackQueue.append((data, self.packetId))
            if flush:
                self.cometTransport.flush()

    def _send(self, data, packetId=""):
        self.logger.debug('_send data=%r packetId=%s' % (data, packetId))
        if isinstance(data, TCPPing):
            self.cometTransport.sendPacket('ping', str(packetId))
        elif isinstance(data, TCPClose):
            self.cometTransport.sendPacket('close', str(packetId), data.reason)
        elif isinstance(data, TCPOption):
            self.cometTransport.sendPacket('opt', str(packetId), data.payload)
        else:
            self.cometTransport.sendPacket('data', str(packetId),
                                           base64.b64encode(data))

    def resendUnackQueue(self):
        if not self.unackQueue:
            return
        for (data, packetId) in self.unackQueue:
            self._send(data, packetId)
        ackId = self.lastAckId + len(self.unackQueue)
Example #16
0
from orbited.util import format_block
from orbited import json
from twisted.internet import reactor
from orbited import logging
from orbited.transports.base import CometTransport
from twisted.web import resource
MAXBYTES = 1048576
#MAXBYTES = 64 # for testing

from orbited import logging
logger = logging.get_logger('orbited.transports.htmlfile.HTMLFileTransport')


class HTMLFileTransport(CometTransport):
    initialData = format_block('''
            <html>
             <head>
              <script src="../static/HTMLFileFrame.js"></script>
             </head>
             <body>
        ''')
    initialData += ' ' * max(0, 256 - len(initialData)) + '\n'

    def opened(self):
        logger.debug('opened!')
        # Force reconnect ever 30 seconds
        self.totalBytes = 0
        #        self.closeTimer = reactor.callLater(5, self.triggerCloseTimeout)
        # See "How to prevent caching in Internet Explorer"
        #     at http://support.microsoft.com/kb/234067
        self.request.setHeader('cache-control', 'no-cache, must-revalidate')
Example #17
0
class Port(object):
    """ A cometsession.Port object can be used in two different ways.
    # Method 1
    reactor.listenWith(cometsession.Port, 9999, SomeFactory())
    
    # Method 2
    root = twisted.web.resource.Resource()
    site = twisted.web.server.Site(root)
    reactor.listenTcp(site, 9999)
    reactor.listenWith(cometsession.Port, factory=SomeFactory(), resource=root, childName='tcp')
    
    Either of these methods should acheive the same effect, but Method2 allows you
    To listen with multiple protocols on the same port by using different urls.
    """
    implements(interfaces.IListeningPort)

    logger = logging.get_logger('orbited.cometsession.Port')

    def __init__(self,
                 port=None,
                 factory=None,
                 backlog=50,
                 interface='',
                 reactor=None,
                 resource=None,
                 childName=None):
        self.port = port
        self.factory = factory
        self.backlog = backlog
        self.interface = interface
        self.resource = resource
        self.childName = childName
        self.wrapped_port = None
        self.listening = False

    def startListening(self):
        self.logger.debug('startingListening')
        if not self.listening:
            self.listening = True
            if self.port:
                self.logger.debug('creating new site and resource')
                self.wrapped_factory = setup_site(self)
                self.wrapped_port = reactor.listenTCP(self.port,
                                                      self.wrapped_factory,
                                                      self.backlog,
                                                      self.interface)
            elif self.resource and self.childName:
                self.logger.debug('adding into existing resource as %s' %
                                  self.childName)
                self.resource.putChild(self.childName, TCPResource(self))
        else:
            raise CannotListenError("Already listening...")

    def stopListening():
        self.logger.debug('stopListening')
        if self.wrapped_port:
            self.listening = False
            self.wrapped_port.stopListening()
        elif self.resource:
            pass
            # TODO: self.resource.removeChild(self.childName) ?

    def connectionMade(self, transportProtocol):
        """
            proto is the tcp-emulation protocol
            
            protocol is the real protocol on top of the transport that depends
            on proto
            
        """
        self.logger.debug('connectionMade')
        protocol = self.factory.buildProtocol(transportProtocol.getPeer())
        if protocol is None:
            transportProtocol.loseConnection()
            return

        transport = FakeTCPTransport(transportProtocol, protocol)
        transportProtocol.parentTransport = transport
        protocol.makeConnection(transport)

    def getHost():
        if self.wrapped_port:
            return self.wrapped_port.getHost()
        elif self.resource:
            pass
Example #18
0
def main():
    try:
        import twisted
    except ImportError:
        print "Orbited requires Twisted, which is not installed. See http://twistedmatrix.com/trac/ for installation instructions."
        sys.exit(1)
    import platform

    if platform.system() == "Windows":
        try:
            import win32api
        except ImportError:
            print "Orbited for Windows requires the Python for Windows Extensions, which are not installed. See http://python.net/crew/mhammond/win32/ for installation instructions."
            sys.exit(1)
    from optparse import OptionParser

    parser = OptionParser()
    parser.add_option("-c", "--config", dest="config", default=None, help="path to configuration file")
    parser.add_option(
        "-v", "--version", dest="version", action="store_true", default=False, help="print Orbited version"
    )
    parser.add_option(
        "-p", "--profile", dest="profile", action="store_true", default=False, help="run Orbited with a profiler"
    )
    parser.add_option(
        "-q",
        "--quickstart",
        dest="quickstart",
        action="store_true",
        default=False,
        help="run Orbited on port 8000 and MorbidQ on port 61613",
    )

    (options, args) = parser.parse_args()

    if args:
        print 'the "orbited" command does not accept positional arguments. type "orbited -h" for options.'
        sys.exit(1)

    if options.version:
        print "Orbited version: %s" % (version,)
        sys.exit(0)

    if options.quickstart:
        config.map["[listen]"].append("http://:8000")
        config.map["[listen]"].append("stomp://:61613")
        config.map["[access]"][("localhost", 61613)] = ["*"]
        print "Quickstarting Orbited"
    else:
        # load configuration from configuration
        # file and from command line arguments.
        config.setup(options=options)

    logging.setup(config.map)

    # we can now safely get loggers.
    global logger
    logger = logging.get_logger("orbited.start")

    # NB: we need to install the reactor before using twisted.
    reactor_name = config.map["[global]"].get("reactor")
    if reactor_name:
        install = _import("twisted.internet.%sreactor.install" % reactor_name)
        install()
        logger.info("using %s reactor" % reactor_name)

    ############
    # This crude garbage corrects a bug in twisted
    #   Orbited ticket: http://orbited.org/ticket/111
    #   Twisted ticket: http://twistedmatrix.com/trac/ticket/2447
    import twisted.web.http

    twisted.web.http.HTTPChannel.setTimeout = lambda self, arg: None
    twisted.web.http.HTTPChannel.resetTimeout = lambda self: None
    ############

    from twisted.internet import reactor
    from twisted.web import resource
    from twisted.web import server
    from twisted.web import static
    import orbited.system

    root = resource.Resource()
    static_files = static.File(os.path.join(os.path.dirname(__file__), "static"))
    root.putChild("static", static_files)
    root.putChild("system", orbited.system.SystemResource())

    if config.map["[test]"]["stompdispatcher.enabled"] == "1":
        logger.info("stompdispatcher enabled")

    # static_files.putChild('orbited.swf', static.File(os.path.join(os.path.dirname(__file__), 'flash', 'orbited.swf')))
    site = server.Site(root)

    _setup_protocols(root)
    _setup_static(root, config.map)
    start_listening(site, config.map, logger)

    # switch uid and gid to configured user and group.
    if os.name == "posix" and os.getuid() == 0:
        user = config.map["[global]"].get("user")
        group = config.map["[global]"].get("group")
        if user:
            import pwd
            import grp

            try:
                pw = pwd.getpwnam(user)
                uid = pw.pw_uid
                if group:
                    gr = grp.getgrnam(group)
                    gid = gr.gr_gid
                else:
                    gid = pw.pw_gid
                    gr = grp.getgrgid(gid)
                    group = gr.gr_name
            except Exception, e:
                logger.error("Aborting; Unknown user or group: %s" % e)
                sys.exit(1)
            logger.info("switching to user %s (uid=%d) and group %s (gid=%d)" % (user, uid, group, gid))
            os.setgid(gid)
            os.setuid(uid)
        else:
            logger.error("Aborting; You must define a user (and optionally a group) in the configuration file.")
            sys.exit(1)
Example #19
0
from orbited.util import format_block
from orbited import json
from twisted.internet import reactor
from base import CometTransport

from orbited import logging
logger = logging.get_logger('orbited.transports.sse.SSETransport')

class SSETransport(CometTransport):
    HEARTBEAT_INTERVAL = 30
    def opened(self):
        self.request.setHeader('content-type', 'application/x-dom-event-stream')
        self.request.setHeader('cache-control', 'no-cache, must-revalidate')   
            
    def write(self, packets):
        payload = json.encode(packets)
        data = (
            'Event: payload\n' +
            '\n'.join(['data: %s' % line for line in payload.splitlines()]) +
            '\n\n'
        )
        self.request.write(data)
        
    def writeHeartbeat(self):
        logger.debug('writeHeartbeat');
        self.request.write('Event: heartbeat\n\n')