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
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