示例#1
0
    def connectFeeder(self, feederName, fullFeedId):
        """
        Tell the component to feed the given feed to the receiving component
        accessible through the FeedServer on the given host and port.

        Called on by the manager-side ComponentAvatar.
        """
        def gotFeed((fullFeedId, fd)):
            self._eaterPendingConnections.pop(feederName, None)
            self.comp.feedToFD(feederName, fd, os.close, fullFeedId)

        if fullFeedId not in self._eaterFeedServer:
            self.debug("feedTo() hasn't been called yet for feeder %s",
                       feederName)
            # unclear if this function should have a return value at
            # all...
            return defer.succeed(None)

        host, port = self._eaterFeedServer[fullFeedId]

        # probably should key on feederName as well
        cancel = self._eaterPendingConnections.pop(fullFeedId, None)
        if cancel:
            self.debug('cancelling previous connection attempt on %s',
                       feederName)
            cancel()

        client = feed.FeedMedium(logName=self.comp.name)

        d = client.sendFeed(host, port,
                            self._getAuthenticatorForFeed(feederName),
                            fullFeedId)
        self._eaterPendingConnections[feederName] = client.stopConnecting
        d.addCallback(gotFeed)
        return d
    def testConnectAndFeed(self):
        client = feed.FeedMedium(logName='test')

        def login():
            port = self.feedServer.getPortNum()
            self.assertAdditionalFDsOpen(1, 'connect (socket)')
            d = client.startConnecting('localhost', port,
                                       fpb.Authenticator(username='******',
                                                         password='******',
                                                         avatarId='test:src'))
            self.assertAdditionalFDsOpen(2, 'connect (socket, client)')
            return d

        def receiveFeed(remote):
            client.setRemoteReference(remote)
            self.assertAdditionalFDsOpen(3, 'feed (socket, client, server)')
            return remote.callRemote('receiveFeed', '/foo/bar:baz')

        def feedReceived(thisValueIsNone):
            return self.feedServer.waitForAvatarExit()

        def serverFdPassed(res):
            self.assertAdditionalFDsOpen(2, 'feedSent (socket, client)')

            t = client.remote.broker.transport
            self.info('stop reading from transport')
            t.stopReading()

            self.info('flushing PB write queue')
            t.doWrite()
            self.info('stop writing to transport')
            t.stopWriting()

            t.keepSocketAlive = True

            # avoid refcount cycles
            client.setRemoteReference(None)

            # Since we need to be able to know when the file descriptor
            # closes, and we currently could be within a doReadOrWrite
            # callstack, close the fd from within a callLater instead to
            # avoid corrupting the reactor's internal state.
            d = defer.Deferred()

            def loseConnection():
                t.connectionLost(failure.Failure(main.CONNECTION_DONE))
                d.callback(None)

            reactor.callLater(0, loseConnection)
            return d

        def checkfds(_):
            self.assertAdditionalFDsOpen(1, 'feedReadyOnServer (socket)')

        d = login()
        d.addCallback(receiveFeed)
        d.addCallback(feedReceived)
        d.addCallback(serverFdPassed)
        d.addCallback(checkfds)
        return d
    def testConnectAndFeed(self):
        client = feed.FeedMedium(logName='test')

        def login():
            port = self.feedServer.getPortNum()
            self.assertAdditionalFDsOpen(1, 'connect (socket)')
            d = client.startConnecting('localhost', port,
                                       fpb.Authenticator(username='******',
                                                         password='******'))
            self.assertAdditionalFDsOpen(2, 'connect (socket, client)')
            return d

        def sendFeed(remote):
            # apparently one has to do magic to get the feed to work
            client.setRemoteReference(remote)
            self.assertAdditionalFDsOpen(3, 'feed (socket, client, server)')
            return remote.callRemote('sendFeed', '/foo/bar:baz')

        def feedSent(thisValueIsNone):
            # either just before or just after this, we received a
            # sendFeedReply call from the feedserver. so now we're
            # waiting on the component to get its fd
            self.assertAdditionalFDsOpen(
                3, 'feedSent (socket, client, server)')

            # This is poking the feedmedium's internals, but in the end,
            # this test is of the feed medium's internals, so that's ok.
            return client._feedToDeferred

        def feedReady((feedId, fd)):
            # this fd is ours, it's our responsibility to close it.
            self.assertEquals(feedId, 'bar:baz')

            # The feed medium should have dropped its reference already
            self.failIf(client.hasRemoteReference())

            self.assertAdditionalFDsOpen(3, 'cleanup (socket, client, server)')
            os.close(fd)
            self.assertAdditionalFDsOpen(2, 'cleanup (socket, server)')

            return self.feedServer.waitForAvatarExit()

        def checkfds(_):
            self.assertAdditionalFDsOpen(1, 'feedReadyOnServer (socket)')

        d = login()
        d.addCallback(sendFeed)
        d.addCallback(feedSent)
        d.addCallback(feedReady)
        d.addCallback(checkfds)
        return d
    def testRequestFeed(self):
        client = feed.FeedMedium(logName='frobby')

        self.failIf(client.hasRemoteReference())

        def requestFeed():
            port = self.feedServer.getPortNum()
            self.assertAdditionalFDsOpen(1, 'connect (socket)')
            d = client.requestFeed('localhost', port,
                                   fpb.Authenticator(username='******',
                                                     password='******'),
                                   '/foo/bar:baz')
            self.failIf(client.hasRemoteReference())
            self.assertAdditionalFDsOpen(2, 'connect (socket, client)')
            return d

        def gotFeed((feedId, fd)):
            # the feed medium should have dropped its reference to the
            # remotereference by now, otherwise we get cycles, and
            # remote references can't exist in cycles because they have
            # a __del__ method
            self.failIf(client.hasRemoteReference())

            self.assertEquals(feedId, 'bar:baz')
            self.assertAdditionalFDsOpen(3, 'cleanup (socket, client, server)')
            # our responsibility to close fd
            os.close(fd)
            self.assertAdditionalFDsOpen(2, 'cleanup (socket, client, server)')
            return self.brain.waitForFD()

        def feedReadyOnServer((componentId, feedName, fd, eaterId)):
            # this likely fires directly, not having dropped into the
            # reactor.

            # this fd is not ours, we should dup it if we want to hold
            # onto it
            return self.feedServer.waitForAvatarExit()

        def checkfds(_):
            self.assertAdditionalFDsOpen(1, 'feedReadyOnServer (socket)')

        d = requestFeed()
        d.addCallback(gotFeed)
        d.addCallback(feedReadyOnServer)
        d.addCallback(checkfds)
        return d
    def testRequestFeed(self):
        client = feed.FeedMedium(logName='frobby')

        self.failIf(client.hasRemoteReference())

        def requestFeed():
            port = self.feedServer.getPortNum()
            self.assertAdditionalFDsOpen(1, 'connect (socket)')
            d = client.sendFeed('localhost', port,
                                fpb.Authenticator(username='******',
                                                  password='******',
                                                  avatarId='test:src'),
                                '/foo/bar:baz')
            self.failIf(client.hasRemoteReference())
            self.assertAdditionalFDsOpen(2, 'connect (socket, client)')
            return d

        def gotFeed((fullFeedId, fd)):
            # the feed medium should have dropped its reference to the
            # remotereference by now, otherwise we get cycles, and
            # remote references can't exist in cycles because they have
            # a __del__ method
            self.assertEquals(fullFeedId, '/foo/bar:baz')
            self.failIf(client.hasRemoteReference())
            # since both the server and the client close their
            # transports via calllaters, we don't know how many extra
            # sockets should be open now

            # this fd is ours to close
            os.close(fd)

            return self.feedServer.waitForAvatarExit()

        def checkfds(_):
            self.assertAdditionalFDsOpen(1, 'feedReadyOnServer (socket)')

        d = requestFeed()
        d.addCallback(gotFeed)
        d.addCallback(checkfds)
        return d
    def testBadPass(self):
        client = feed.FeedMedium(logName='test')
        factory = feed.FeedClientFactory(client)

        def login():
            port = self.feedServer.getPortNum()
            self.assertAdditionalFDsOpen(1, 'connect (socket)')
            reactor.connectTCP('localhost', port, factory)
            self.assertAdditionalFDsOpen(2, 'connect (socket, client)')
            return factory.login(fpb.Authenticator(username='******',
                                                   password='******'))

        def loginOk(root):
            raise AssertionError('should not get here')

        def loginFailed(failure):

            def gotRoot(root):
                # an idempotent method, should return a network failure if
                # the remote side disconnects as it should
                return root.callRemote('getKeycardClasses')

            def gotError(failure):
                self.assertAdditionalFDsOpen(1, 'feedSent (socket)')
                self.info('success')

            def gotKeycardClasses(classes):
                raise AssertionError('should not get here')

            self.info('loginFailed: %s', log.getFailureMessage(failure))
            failure.trap(errors.NotAuthenticatedError)
            d = factory.getRootObject() # should fire immediately
            d.addCallback(gotRoot)
            d.addCallbacks(gotKeycardClasses, gotError)

            return d

        d = login()
        d.addCallbacks(loginOk, loginFailed)
        return d
示例#7
0
    def connectEater(self, eaterAlias):
        """
        Connect one of the medium's component's eaters to a remote feed.
        Called by the component, both on initial connection and for
        reconnecting.

        @returns: deferred that will fire with a value of None
        """

        # FIXME: There's no indication if the connection was made or not

        def gotFeed((feedId, fd)):
            self._feederPendingConnections.pop(eaterAlias, None)
            self.comp.eatFromFD(eaterAlias, feedId, fd)

        if eaterAlias not in self._feederFeedServer:
            self.debug("eatFrom() hasn't been called yet for eater %s",
                       eaterAlias)
            # unclear if this function should have a return value at
            # all...
            return defer.succeed(None)

        (fullFeedId, host, port) = self._feederFeedServer[eaterAlias]

        cancel = self._feederPendingConnections.pop(eaterAlias, None)
        if cancel:
            self.debug('cancelling previous connection attempt on %s',
                       eaterAlias)
            cancel()

        client = feed.FeedMedium(logName=self.comp.name)

        d = client.requestFeed(host, port,
                               self._getAuthenticatorForFeed(eaterAlias),
                               fullFeedId)
        self._feederPendingConnections[eaterAlias] = client.stopConnecting
        d.addCallback(gotFeed)
        return d
    def testConnectWithoutDroppingPB(self):
        client = feed.FeedMedium(logName='test')
        factory = feed.FeedClientFactory(client)

        self.failIf(client.hasRemoteReference())

        def login():
            port = self.feedServer.getPortNum()
            self.assertAdditionalFDsOpen(1, 'connect (socket)')
            reactor.connectTCP('localhost', port, factory)
            self.assertAdditionalFDsOpen(2, 'connect (socket, client)')
            return factory.login(fpb.Authenticator(username='******',
                                                   password='******'))

        def cleanup(res):
            # We're not using requestFeed, so no reference should be set
            self.failIf(client.hasRemoteReference())

            self.assertAdditionalFDsOpen(3, 'cleanup (socket, client, server)')
            factory.disconnect()

            # disconnect calls loseConnection() on the transport, which
            # can return a deferred. In the case of TCP sockets it does
            # this, actually disconnecting from a callLater, so we can't
            # assert on the open FD's at this point
            # self.assertAdditionalFDsOpen(2, 'cleanup (socket, server)')

            # have to drop into the reactor to wait for this one
            return self.feedServer.waitForAvatarExit()

        def checkfds(res):
            self.assertAdditionalFDsOpen(1, 'cleanup (socket)')

        d = login()
        d.addCallback(cleanup)
        d.addCallback(checkfds)
        return d