Esempio n. 1
0
class AppletConnection( object ) :
    DEFAULT = 0
    CONNECTING = 1
    WAITING_BRIDGE = 2
    LISTENER = 3
    CLOSED = 4
    def __init__( self, sock, reactor, appletServer ) :
        self.reactor = reactor
        self.stream = TCPLineStream( sock, reactor )
        self.appletServer = appletServer
        self.appletServer.appletConnections[self] = 1
        self.session = appletServer.session
        self.incoming = appletServer.incoming
        self.state = self.DEFAULT
        self._writeData = self.stream.writeData
        rt = {}
        self.requestTable = rt
        rt['echo'] = self._doEcho
        rt['getcontacts'] = self._doGetContacts
        rt['getpubkey'] = self._doGetPubKey
        rt['getcontactpubkeys'] = self._doGetContactPubKeys
        rt['connect'] = self._doConnect
        rt['connectpubkey'] = self._doConnectPubKey
        rt['accept'] = self._doAccept
        rt['getincomingpubkey'] = self._doGetIncomingPubKey
        rt['registerlistener'] = self._doRegisterListener
        rt['sendlistener'] = self._doSendListener
        self.stream.setInputCallback( self._onInput )
        self.stream.setCloseCallback( self._onClose )
        self.stream.setErrorCallback( self._onError )
        self.stream.enableRead( True )

    def _setClosed( self ) :
        del self.appletServer.appletConnections[self]
        self.state = self.CLOSED

    def shutdown( self, deferred=False ) :
        if self.state == self.CONNECTING :
            self.connectOp.cancel()
        elif self.state == self.LISTENER :
            self.appletServer.unregisterListener( self.listenerName )
        elif self.state == self.WAITING_BRIDGE :
            sslAbort( self.peerSSLConn )
        self.stream.close( deferred )
        self._setClosed()

    def _onClose( self ) :
        self.shutdown()

    def _onError( self, err, errMsg ) :
        self.shutdown()

    def _writeLine( self, line ) :
        self._writeData( line + '\r\n' )

    def _writeWords( self, words ) :
        words = [wordEncode(w) for w in words]
        self._writeData( ' '.join(words) + '\r\n' )

    def _writeError( self, msg ) :
        self._writeLine( 'ERROR %s' % msg )

    def _writeResult( self, words ) :
        self._writeWords( ['OK'] + words )

    def dispatchMessage( self, msg ) :
        assert self.state == self.LISTENER
        self._writeWords( ['MSG'] + msg )

    def _doEcho( self, words ) :
        self._writeResult( words )

    def _doGetContacts( self, words ) :
        if len(words) != 0 :
            self._writeError( 'Malformed request' )
            return
        if not self.session.isOnline() :
            self._writeError( 'Not online' )
            return
        names = self.session.getProfile().getContactNames()
        self._writeResult( names )

    def _doGetPubKey( self, words ) :
        if len(words) > 1 :
            self._writeError( 'Malformed request' )
            return
        if not self.session.isOnline() :
            self._writeError( 'Not online' )
            return
        if len(words) == 0 :
            keyData = self.session.getProfile().rsaKey.toDER_PublicKey()
            self._writeResult( [hexEncode(keyData)] )
            return
        contact = self.session.getProfile().getContactByName( words[0] )
        if contact is None :
            self._writeError( 'Unknown contact' )
            return
        self._writeResult( [hexEncode(contact.publicKeyData)] )

    def _doGetContactPubKeys( self, words ) :
        if len(words) != 0 :
            self._writeError( 'Malformed request' )
            return
        if not self.session.isOnline() :
            self._writeError( 'Not online' )
            return
        out = []
        profile = self.session.getProfile()
        for name in profile.getContactNames() :
            c = profile.getContactByName( name )
            out.extend( [c.name,hexEncode(c.publicKeyData)] )
        self._writeResult( out )

    def _connectInternal( self, publicKey, service ) :
        def onWriteComplete() :
            self.stream.shutdown()
            sock = self.stream.getSock()
            self.appletServer.bridgeThread.threadQueue.postMessage(
                    ('bridge',sock,self.peerSSLConn) )
            self._setClosed()
        def onConnect( err, sslConn ) :
            if err < 0 :
                self._writeError( 'Connect failed' )
                self.state = self.DEFAULT
                return
            self._writeResult( ['Connected'] )
            self.peerSSLConn = sslConn
            self.state = self.WAITING_BRIDGE
            self.stream.enableRead( False )
            self.stream.setWriteCompleteCallback( onWriteComplete )
        self.connectOp = self.session.connectTo( publicKey, service,
                onConnect )
        self.state = self.CONNECTING

    def _doConnect( self, words ) :
        if len(words) != 2 :
            self._writeError( 'Malformed request' )
            return
        contactName, service = words
        if not self.session.isOnline() :
            self._writeError( 'Not online' )
            return
        contact = self.session.getProfile().getContactByName( contactName )
        if not contact :
            self._writeError( 'Unknown contact' )
            return
        self._connectInternal( contact.publicKey, service )

    def _doConnectPubKey( self, words ) :
        if len(words) != 2 :
            self._writeError( 'Malformed request' )
            return
        hexPubKey, service = words
        if not self.session.isOnline() :
            self._writeError( 'Not online' )
            return
        try :
            pubKeyData = hexDecode( hexPubKey )
            pubKey = RSAKey()
            pubKey.fromDER_PublicKey( pubKeyData )
        except (HexDecodeError,RSAError) :
            self._writeError( 'Malformed publickey' )
            return
        self._connectInternal( pubKey, service )

    def _doAccept( self, words ) :
        if len(words) != 1 :
            self._writeError( 'Malformed request' )
            return
        connectionId = words[0]
        sslConn = self.incoming.acceptIncoming( connectionId )
        if not sslConn :
            self._writeError( 'Invalid connection' )
            return
        self._writeResult( ['Connected'] )
        self.peerSSLConn = sslConn
        self.state = self.WAITING_BRIDGE
        self.stream.enableRead( False )
        def onWriteComplete() :
            self.stream.shutdown()
            sock = self.stream.getSock()
            self.appletServer.bridgeThread.threadQueue.postMessage(
                    ('bridge',sock,self.peerSSLConn) )
            self._setClosed()
        self.stream.setWriteCompleteCallback( onWriteComplete )

    def _doGetIncomingPubKey( self, words ) :
        if len(words) != 1 :
            self._writeError( 'Malformed request' )
            return
        connectionId = words[0]
        peerKey = self.incoming.getPeerKey( connectionId )
        if not peerKey :
            self._writeError( 'Invalid connection' )
            return
        self._writeResult( [hexEncode(peerKey.toDER_PublicKey())] )

    def _doRegisterListener( self, words ) :
        if len(words) != 1 :
            self._writeError( 'Malformed request' )
            return
        listenerName = words[0]
        result = self.appletServer.registerListener( listenerName, self )
        if not result :
            self._writeError( 'Listener already registered' )
            return
        self.listenerName = listenerName
        self.state = self.LISTENER
        self._writeResult( ['Registered'] )

    def _doSendListener( self, words ) :
        if len(words) <= 1 :
            self._writeError( 'Malformed request' )
            return
        listenerName = words[0]
        listener = self.appletServer.getListener( listenerName )
        if listener is None :
            self._writeError( 'No such listener' )
            return
        listener.dispatchMessage( words[1:] )
        self._writeResult( ['Sent'] )

    def _onInput( self, line ) :
        assert self.state in (self.DEFAULT,self.CONNECTING,self.LISTENER)
        if self.state in (self.CONNECTING,self.LISTENER) :
            self._writeError( 'Junk received' )
            self.shutdown( deferred=True )
            return
        words = line.strip().split()
        if len(words) == 0 : return
        try :
            words = [wordDecode(w) for w in words]
        except WordDecodeError :
            self._writeError( 'Malformed request' )
            return
        cmd = words[0].lower()
        handler = self.requestTable.get( cmd, None )
        if not handler :
            self._writeError( 'Unknown request' )
            return
        handler( words[1:] )