def startTLSAfterRegisterProducer(self, streaming): """ When a producer is registered, and then startTLS is called, the producer is re-registered with the C{TLSMemoryBIOProtocol}. """ clientContext = self.getClientContext() serverContext = self.getServerContext() result = [] producer = FakeProducer() class RegisterTLSProtocol(ConnectableProtocol): def connectionMade(self): self.transport.registerProducer(producer, streaming) self.transport.startTLS(serverContext) # Store TLSMemoryBIOProtocol and underlying transport producer # status: if streaming: # _ProducerMembrane -> producer: result.append(self.transport.protocol._producer._producer) result.append(self.transport.producer._producer) else: # _ProducerMembrane -> _PullToPush -> producer: result.append( self.transport.protocol._producer._producer._producer) result.append(self.transport.producer._producer._producer) self.transport.unregisterProducer() self.transport.loseConnection() class StartTLSProtocol(ConnectableProtocol): def connectionMade(self): self.transport.startTLS(clientContext) runProtocolsWithReactor(self, RegisterTLSProtocol(), StartTLSProtocol(), TCPCreator()) self.assertEqual(result, [producer, producer])
def startTLSAfterRegisterProducer(self, streaming): """ When a producer is registered, and then startTLS is called, the producer is re-registered with the C{TLSMemoryBIOProtocol}. """ clientContext = self.getClientContext() serverContext = self.getServerContext() result = [] producer = FakeProducer() class RegisterTLSProtocol(ConnectableProtocol): def connectionMade(self): self.transport.registerProducer(producer, streaming) self.transport.startTLS(serverContext) # Store TLSMemoryBIOProtocol and underlying transport producer # status: if streaming: # _ProducerMembrane -> producer: result.append(self.transport.protocol._producer._producer) result.append(self.transport.producer._producer) else: # _ProducerMembrane -> _PullToPush -> producer: result.append( self.transport.protocol._producer._producer._producer) result.append(self.transport.producer._producer._producer) self.transport.unregisterProducer() self.transport.loseConnection() class StartTLSProtocol(ConnectableProtocol): def connectionMade(self): self.transport.startTLS(clientContext) runProtocolsWithReactor(self, RegisterTLSProtocol(), StartTLSProtocol(), TCPCreator()) self.assertEqual(result, [producer, producer])
def test_logPrefix(self): """ Client and server transports implement L{ILoggingContext.logPrefix} to return a message reflecting the protocol they are running. """ class CustomLogPrefixProtocol(ConnectableProtocol): def __init__(self, prefix): self._prefix = prefix self.system = None def connectionMade(self): self.transport.write("a") def logPrefix(self): return self._prefix def dataReceived(self, bytes): self.system = context.get(ILogContext)["system"] self.transport.write("b") # Only close connection if both sides have received data, so # that both sides have system set. if "b" in bytes: self.transport.loseConnection() client = CustomLogPrefixProtocol("Custom Client") server = CustomLogPrefixProtocol("Custom Server") runProtocolsWithReactor(self, server, client, self.endpoints) self.assertIn("Custom Client", client.system) self.assertIn("Custom Server", server.system)
def test_descriptorDeliveredBeforeBytes(self): """ L{IUNIXTransport.sendFileDescriptor} sends file descriptors before L{ITransport.write} sends normal bytes. """ class RecordEvents(ConnectableProtocol): implements(IFileDescriptorReceiver) def connectionMade(self): ConnectableProtocol.connectionMade(self) self.events = [] def fileDescriptorReceived(innerSelf, descriptor): self.addCleanup(close, descriptor) innerSelf.events.append(type(descriptor)) def dataReceived(self, data): self.events.extend(data) cargo = socket() server = SendFileDescriptor(cargo.fileno(), "junk") client = RecordEvents() runProtocolsWithReactor(self, server, client, self.endpoints) self.assertEqual([int, "j", "u", "n", "k"], client.events)
def test_logPrefix(self): """ Client and server transports implement L{ILoggingContext.logPrefix} to return a message reflecting the protocol they are running. """ class CustomLogPrefixProtocol(ConnectableProtocol): def __init__(self, prefix): self._prefix = prefix self.system = None def connectionMade(self): self.transport.write("a") def logPrefix(self): return self._prefix def dataReceived(self, bytes): self.system = context.get(ILogContext)["system"] self.transport.write("b") # Only close connection if both sides have received data, so # that both sides have system set. if "b" in bytes: self.transport.loseConnection() client = CustomLogPrefixProtocol("Custom Client") server = CustomLogPrefixProtocol("Custom Server") runProtocolsWithReactor(self, server, client, self.endpoints) self.assertIn("Custom Client", client.system) self.assertIn("Custom Server", server.system)
def test_sendFileDescriptor(self): """ L{IUNIXTransport.sendFileDescriptor} accepts an integer file descriptor and sends a copy of it to the process reading from the connection. """ from socket import fromfd s = socket() s.bind(('', 0)) server = SendFileDescriptor(s.fileno(), "junk") client = ReceiveFileDescriptor() d = client.waitForDescriptor() def checkDescriptor(descriptor): received = fromfd(descriptor, AF_INET, SOCK_STREAM) # Thanks for the free dup, fromfd() close(descriptor) # If the sockets have the same local address, they're probably the # same. self.assertEqual(s.getsockname(), received.getsockname()) # But it would be cheating for them to be identified by the same # file descriptor. The point was to get a copy, as we might get if # there were two processes involved here. self.assertNotEqual(s.fileno(), received.fileno()) d.addCallback(checkDescriptor) d.addErrback(err, "Sending file descriptor encountered a problem") d.addBoth(lambda ignored: server.transport.loseConnection()) runProtocolsWithReactor(self, server, client, self.endpoints)
def test_descriptorDeliveredBeforeBytes(self): """ L{IUNIXTransport.sendFileDescriptor} sends file descriptors before L{ITransport.write} sends normal bytes. """ class RecordEvents(ConnectableProtocol): implements(IFileDescriptorReceiver) def connectionMade(self): ConnectableProtocol.connectionMade(self) self.events = [] def fileDescriptorReceived(innerSelf, descriptor): self.addCleanup(close, descriptor) innerSelf.events.append(type(descriptor)) def dataReceived(self, data): self.events.extend(data) cargo = socket() server = SendFileDescriptor(cargo.fileno(), "junk") client = RecordEvents() runProtocolsWithReactor(self, server, client, self.endpoints) self.assertEqual([int, "j", "u", "n", "k"], client.events)
def test_sendFileDescriptor(self): """ L{IUNIXTransport.sendFileDescriptor} accepts an integer file descriptor and sends a copy of it to the process reading from the connection. """ from socket import fromfd s = socket() s.bind(('', 0)) server = SendFileDescriptor(s.fileno(), "junk") client = ReceiveFileDescriptor() d = client.waitForDescriptor() def checkDescriptor(descriptor): received = fromfd(descriptor, AF_INET, SOCK_STREAM) # Thanks for the free dup, fromfd() close(descriptor) # If the sockets have the same local address, they're probably the # same. self.assertEqual(s.getsockname(), received.getsockname()) # But it would be cheating for them to be identified by the same # file descriptor. The point was to get a copy, as we might get if # there were two processes involved here. self.assertNotEqual(s.fileno(), received.fileno()) d.addCallback(checkDescriptor) d.addErrback(err, "Sending file descriptor encountered a problem") d.addBoth(lambda ignored: server.transport.loseConnection()) runProtocolsWithReactor(self, server, client, self.endpoints)
def test_producerSSLFromStart(self): """ C{registerProducer} and C{unregisterProducer} on TLS transports created as SSL from the get go are passed to the C{TLSMemoryBIOProtocol}, not the underlying transport directly. """ result = [] producer = FakeProducer() runProtocolsWithReactor(self, ConnectableProtocol(), ProducerProtocol(producer, result), SSLCreator()) self.assertEqual(result, [producer, None])
def test_producerAfterStartTLS(self): """ C{registerProducer} and C{unregisterProducer} on TLS transports created by C{startTLS} are passed to the C{TLSMemoryBIOProtocol}, not the underlying transport directly. """ result = [] producer = FakeProducer() runProtocolsWithReactor(self, ConnectableProtocol(), ProducerProtocol(producer, result), StartTLSClientCreator()) self.assertEqual(result, [producer, None])
def test_sendFileDescriptorTriggersPauseProducing(self): """ If a L{IUNIXTransport.sendFileDescriptor} call fills up the send buffer, any registered producer is paused. """ class DoesNotRead(ConnectableProtocol): def connectionMade(self): self.transport.pauseProducing() class SendsManyFileDescriptors(ConnectableProtocol): paused = False def connectionMade(self): self.socket = socket() self.transport.registerProducer(self, True) def sender(): self.transport.sendFileDescriptor(self.socket.fileno()) self.transport.write("x") self.task = LoopingCall(sender) self.task.clock = self.transport.reactor self.task.start(0).addErrback(err, "Send loop failure") def stopProducing(self): self._disconnect() def resumeProducing(self): self._disconnect() def pauseProducing(self): self.paused = True self.transport.unregisterProducer() self._disconnect() def _disconnect(self): self.task.stop() self.transport.abortConnection() self.other.transport.abortConnection() server = SendsManyFileDescriptors() client = DoesNotRead() server.other = client runProtocolsWithReactor(self, server, client, self.endpoints) self.assertTrue(server.paused, "sendFileDescriptor producer was not paused")
def test_sendFileDescriptorTriggersPauseProducing(self): """ If a L{IUNIXTransport.sendFileDescriptor} call fills up the send buffer, any registered producer is paused. """ class DoesNotRead(ConnectableProtocol): def connectionMade(self): self.transport.pauseProducing() class SendsManyFileDescriptors(ConnectableProtocol): paused = False def connectionMade(self): self.socket = socket() self.transport.registerProducer(self, True) def sender(): self.transport.sendFileDescriptor(self.socket.fileno()) self.transport.write("x") self.task = LoopingCall(sender) self.task.clock = self.transport.reactor self.task.start(0).addErrback(err, "Send loop failure") def stopProducing(self): self._disconnect() def resumeProducing(self): self._disconnect() def pauseProducing(self): self.paused = True self.transport.unregisterProducer() self._disconnect() def _disconnect(self): self.task.stop() self.transport.abortConnection() self.other.transport.abortConnection() server = SendsManyFileDescriptors() client = DoesNotRead() server.other = client runProtocolsWithReactor(self, server, client, self.endpoints) self.assertTrue( server.paused, "sendFileDescriptor producer was not paused")
def test_addresses(self): """ A client's transport's C{getHost} and C{getPeer} return L{UNIXAddress} instances which have the filesystem path of the host and peer ends of the connection. """ class SaveAddress(ConnectableProtocol): def makeConnection(self, transport): self.addresses = dict(host=transport.getHost(), peer=transport.getPeer()) transport.loseConnection() server = SaveAddress() client = SaveAddress() runProtocolsWithReactor(self, server, client, self.endpoints) self.assertEqual(server.addresses['host'], client.addresses['peer']) self.assertEqual(server.addresses['peer'], client.addresses['host'])
def test_addresses(self): """ A client's transport's C{getHost} and C{getPeer} return L{UNIXAddress} instances which have the filesystem path of the host and peer ends of the connection. """ class SaveAddress(ConnectableProtocol): def makeConnection(self, transport): self.addresses = dict( host=transport.getHost(), peer=transport.getPeer()) transport.loseConnection() server = SaveAddress() client = SaveAddress() runProtocolsWithReactor(self, server, client, self.endpoints) self.assertEqual(server.addresses['host'], client.addresses['peer']) self.assertEqual(server.addresses['peer'], client.addresses['host'])
def test_fileDescriptorOverrun(self): """ If L{IUNIXTransport.sendFileDescriptor} is used to queue a greater number of file descriptors than the number of bytes sent using L{ITransport.write}, the connection is closed and the protocol connected to the transport has its C{connectionLost} method called with a failure wrapping L{FileDescriptorOverrun}. """ cargo = socket() server = SendFileDescriptor(cargo.fileno(), None) client = ReceiveFileDescriptor() d = self.assertFailure(client.waitForDescriptor(), ConnectionClosed) d.addErrback(err, "Sending file descriptor encountered unexpected problem") d.addBoth(lambda ignored: server.transport.loseConnection()) runProtocolsWithReactor(self, server, client, self.endpoints) self.assertIsInstance(server.reason.value, FileDescriptorOverrun)
def test_fileDescriptorOverrun(self): """ If L{IUNIXTransport.sendFileDescriptor} is used to queue a greater number of file descriptors than the number of bytes sent using L{ITransport.write}, the connection is closed and the protocol connected to the transport has its C{connectionLost} method called with a failure wrapping L{FileDescriptorOverrun}. """ cargo = socket() server = SendFileDescriptor(cargo.fileno(), None) client = ReceiveFileDescriptor() d = self.assertFailure( client.waitForDescriptor(), ConnectionClosed) d.addErrback( err, "Sending file descriptor encountered unexpected problem") d.addBoth(lambda ignored: server.transport.loseConnection()) runProtocolsWithReactor(self, server, client, self.endpoints) self.assertIsInstance(server.reason.value, FileDescriptorOverrun)
def test_avoidLeakingFileDescriptors(self): """ If associated with a protocol which does not provide L{IFileDescriptorReceiver}, file descriptors received by the L{IUNIXTransport} implementation are closed and a warning is emitted. """ # To verify this, establish a connection. Send one end of the # connection over the IUNIXTransport implementation. After the copy # should no longer exist, close the original. If the opposite end of # the connection decides the connection is closed, the copy does not # exist. from socket import socketpair probeClient, probeServer = socketpair() events = [] addObserver(events.append) self.addCleanup(removeObserver, events.append) class RecordEndpointAddresses(SendFileDescriptor): def connectionMade(self): self.hostAddress = self.transport.getHost() self.peerAddress = self.transport.getPeer() SendFileDescriptor.connectionMade(self) server = RecordEndpointAddresses(probeClient.fileno(), "junk") client = ConnectableProtocol() runProtocolsWithReactor(self, server, client, self.endpoints) # Get rid of the original reference to the socket. probeClient.close() # A non-blocking recv will return "" if the connection is closed, as # desired. If the connection has not been closed, because the duplicate # file descriptor is still open, it will fail with EAGAIN instead. probeServer.setblocking(False) self.assertEqual("", probeServer.recv(1024)) # This is a surprising circumstance, so it should be logged. format = ("%(protocolName)s (on %(hostAddress)r) does not " "provide IFileDescriptorReceiver; closing file " "descriptor received (from %(peerAddress)r).") clsName = "ConnectableProtocol" # Reverse host and peer, since the log event is from the client # perspective. expectedEvent = dict(hostAddress=server.peerAddress, peerAddress=server.hostAddress, protocolName=clsName, format=format) for logEvent in events: for k, v in expectedEvent.iteritems(): if v != logEvent.get(k): break else: # No mismatches were found, stop looking at events break else: # No fully matching events were found, fail the test. self.fail("Expected event (%s) not found in logged events (%s)" % (expectedEvent, pformat(events, )))
def test_avoidLeakingFileDescriptors(self): """ If associated with a protocol which does not provide L{IFileDescriptorReceiver}, file descriptors received by the L{IUNIXTransport} implementation are closed and a warning is emitted. """ # To verify this, establish a connection. Send one end of the # connection over the IUNIXTransport implementation. After the copy # should no longer exist, close the original. If the opposite end of # the connection decides the connection is closed, the copy does not # exist. from socket import socketpair probeClient, probeServer = socketpair() events = [] addObserver(events.append) self.addCleanup(removeObserver, events.append) class RecordEndpointAddresses(SendFileDescriptor): def connectionMade(self): self.hostAddress = self.transport.getHost() self.peerAddress = self.transport.getPeer() SendFileDescriptor.connectionMade(self) server = RecordEndpointAddresses(probeClient.fileno(), "junk") client = ConnectableProtocol() runProtocolsWithReactor(self, server, client, self.endpoints) # Get rid of the original reference to the socket. probeClient.close() # A non-blocking recv will return "" if the connection is closed, as # desired. If the connection has not been closed, because the duplicate # file descriptor is still open, it will fail with EAGAIN instead. probeServer.setblocking(False) self.assertEqual("", probeServer.recv(1024)) # This is a surprising circumstance, so it should be logged. format = ( "%(protocolName)s (on %(hostAddress)r) does not " "provide IFileDescriptorReceiver; closing file " "descriptor received (from %(peerAddress)r).") clsName = "ConnectableProtocol" # Reverse host and peer, since the log event is from the client # perspective. expectedEvent = dict(hostAddress=server.peerAddress, peerAddress=server.hostAddress, protocolName=clsName, format=format) for logEvent in events: for k, v in expectedEvent.iteritems(): if v != logEvent.get(k): break else: # No mismatches were found, stop looking at events break else: # No fully matching events were found, fail the test. self.fail( "Expected event (%s) not found in logged events (%s)" % ( expectedEvent, pformat(events,)))