def startService(self): local_addr = convert_onion_to_ipv6(self.onion) tun_protocol = TunProducerConsumer() frame_producer_protocol = TcpFrameProducer(local_addr, consumer=tun_protocol) persistentFactory = PersistentSingletonFactory(frame_producer_protocol) ipv6_onion_consumer = IPv6OnionConsumer(reactor) tun_protocol.setConsumer(ipv6_onion_consumer) # listen to onion virtport 8060 for onioncat compatibility onion_endpoint = serverFromString( reactor, "onion:8060:hiddenServiceDir=%s" % self.onion_key_dir) d = onion_endpoint.listen(persistentFactory) def display(result): print result d.addCallback(display) tun = TuntapPort(self.tun_name, tun_protocol, reactor=reactor) tun.startListening() return d
def startService(self): local_addr = convert_onion_to_ipv6(self.onion) tun_protocol = TunProducerConsumer() frame_producer_protocol = TcpFrameProducer(local_addr, consumer=tun_protocol) persistentFactory = PersistentSingletonFactory(frame_producer_protocol) ipv6_onion_consumer = IPv6OnionConsumer(reactor) tun_protocol.setConsumer(ipv6_onion_consumer) onion_endpoint = serverFromString( reactor, "onion:80:hiddenServiceDir=%s" % self.onion_key_dir ) d = onion_endpoint.listen(persistentFactory) def display(result): print result d.addCallback(display) tun = TuntapPort(self.tun_name, tun_protocol, reactor=reactor) tun.startListening() return d
def main(reactor): startLogging(stdout, setStdout=False) udp = RawUDPProtocol() udp.addProto(42, MyProto()) ip = IPProtocol() ip.addProto(17, udp) eth = EthernetProtocol() eth.addProto(0x800, ip) port = TuntapPort(interface='tap0', proto=eth, reactor=reactor) port.startListening() # Run forever return Deferred()
def startService(self): local_addr = convert_onion_to_ipv6(self.onion) tun_protocol = TunProducerConsumer() frame_producer_protocol = TcpFrameProducer(local_addr, consumer=tun_protocol) persistentFactory = PersistentSingletonFactory(frame_producer_protocol) ipv6_onion_consumer = IPv6OnionConsumer(reactor) tun_protocol.setConsumer(ipv6_onion_consumer) # must listen to onion virtport 8060 onion_endpoint = serverFromString(reactor,self.onion_endpoint) d = onion_endpoint.listen(persistentFactory) tun = TuntapPort(self.tun_name, tun_protocol, reactor=reactor) tun.startListening() return d
class TunnelTestsMixin: """ A mixin defining tests for L{TuntapPort}. These tests run against L{MemoryIOSystem} (proven equivalent to the real thing by the tests above) to avoid performing any real I/O. """ def setUp(self): """ Create an in-memory I/O system and set up a L{TuntapPort} against it. """ self.name = b"tun0" self.system = MemoryIOSystem() self.system.registerSpecialDevice(Tunnel._DEVICE_NAME, Tunnel) self.protocol = self.factory.buildProtocol( TunnelAddress(self.helper.TUNNEL_TYPE, self.name)) self.reactor = FSSetClock() self.port = TuntapPort( self.name, self.protocol, reactor=self.reactor, system=self.system) def _tunnelTypeOnly(self, flags): """ Mask off any flags except for L{TunnelType.IFF_TUN} and L{TunnelType.IFF_TAP}. @param flags: Flags from L{TunnelType} to mask. @type flags: L{FlagConstant} @return: The flags given by C{flags} except the two type flags. @rtype: L{FlagConstant} """ return flags & (TunnelFlags.IFF_TUN | TunnelFlags.IFF_TAP) def test_startListeningOpensDevice(self): """ L{TuntapPort.startListening} opens the tunnel factory character special device C{"/dev/net/tun"} and configures it as a I{tun} tunnel. """ system = self.system self.port.startListening() tunnel = self.system.getTunnel(self.port) expected = ( system.O_RDWR | system.O_CLOEXEC | system.O_NONBLOCK, b"tun0" + b"\x00" * (_IFNAMSIZ - len(b"tun0")), self.port.interface, False, True) actual = ( tunnel.openFlags, tunnel.requestedName, tunnel.name, tunnel.blocking, tunnel.closeOnExec) self.assertEqual(expected, actual) def test_startListeningSetsConnected(self): """ L{TuntapPort.startListening} sets C{connected} on the port object to C{True}. """ self.port.startListening() self.assertTrue(self.port.connected) def test_startListeningConnectsProtocol(self): """ L{TuntapPort.startListening} calls C{makeConnection} on the protocol the port was initialized with, passing the port as an argument. """ self.port.startListening() self.assertIs(self.port, self.protocol.transport) def test_startListeningStartsReading(self): """ L{TuntapPort.startListening} passes the port instance to the reactor's C{addReader} method to begin watching the port's file descriptor for data to read. """ self.port.startListening() self.assertIn(self.port, self.reactor.getReaders()) def test_startListeningHandlesOpenFailure(self): """ L{TuntapPort.startListening} raises L{CannotListenError} if opening the tunnel factory character special device fails. """ self.system.permissions.remove('open') self.assertRaises(CannotListenError, self.port.startListening) def test_startListeningHandlesConfigureFailure(self): """ L{TuntapPort.startListening} raises L{CannotListenError} if the C{ioctl} call to configure the tunnel device fails. """ self.system.permissions.remove('ioctl') self.assertRaises(CannotListenError, self.port.startListening) def _stopPort(self, port): """ Verify that the C{stopListening} method of an L{IListeningPort} removes that port from the reactor's "readers" set and also that the L{Deferred} returned by that method fires with L{None}. @param port: The port object to stop. @type port: L{IListeningPort} provider """ stopped = port.stopListening() self.assertNotIn(port, self.reactor.getReaders()) # An unfortunate implementation detail self.reactor.advance(0) self.assertIsNone(self.successResultOf(stopped)) def test_stopListeningStopsReading(self): """ L{TuntapPort.stopListening} returns a L{Deferred} which fires after the port has been removed from the reactor's reader list by passing it to the reactor's C{removeReader} method. """ self.port.startListening() fileno = self.port.fileno() self._stopPort(self.port) self.assertNotIn(fileno, self.system._openFiles) def test_stopListeningUnsetsConnected(self): """ After the L{Deferred} returned by L{TuntapPort.stopListening} fires, the C{connected} attribute of the port object is set to C{False}. """ self.port.startListening() self._stopPort(self.port) self.assertFalse(self.port.connected) def test_stopListeningStopsProtocol(self): """ L{TuntapPort.stopListening} calls C{doStop} on the protocol the port was initialized with. """ self.port.startListening() self._stopPort(self.port) self.assertIsNone(self.protocol.transport) def test_stopListeningWhenStopped(self): """ L{TuntapPort.stopListening} returns a L{Deferred} which succeeds immediately if it is called when the port is not listening. """ stopped = self.port.stopListening() self.assertIsNone(self.successResultOf(stopped)) def test_multipleStopListening(self): """ It is safe and a no-op to call L{TuntapPort.stopListening} more than once with no intervening L{TuntapPort.startListening} call. """ self.port.startListening() self.port.stopListening() second = self.port.stopListening() self.reactor.advance(0) self.assertIsNone(self.successResultOf(second)) def test_loseConnection(self): """ L{TuntapPort.loseConnection} stops the port and is deprecated. """ self.port.startListening() self.port.loseConnection() # An unfortunate implementation detail self.reactor.advance(0) self.assertFalse(self.port.connected) warnings = self.flushWarnings([self.test_loseConnection]) self.assertEqual(DeprecationWarning, warnings[0]['category']) self.assertEqual( "twisted.pair.tuntap.TuntapPort.loseConnection was deprecated " "in Twisted 14.0.0; please use twisted.pair.tuntap.TuntapPort." "stopListening instead", warnings[0]['message']) self.assertEqual(1, len(warnings)) def _stopsReadingTest(self, style): """ Test that L{TuntapPort.doRead} has no side-effects under a certain exception condition. @param style: An exception instance to arrange for the (python wrapper around the) underlying platform I{read} call to fail with. @raise C{self.failureException}: If there are any observable side-effects. """ self.port.startListening() tunnel = self.system.getTunnel(self.port) tunnel.nonBlockingExceptionStyle = style self.port.doRead() self.assertEqual([], self.protocol.received) def test_eagainStopsReading(self): """ Once L{TuntapPort.doRead} encounters an I{EAGAIN} errno from a C{read} call, it returns. """ self._stopsReadingTest(Tunnel.EAGAIN_STYLE) def test_ewouldblockStopsReading(self): """ Once L{TuntapPort.doRead} encounters an I{EWOULDBLOCK} errno from a C{read} call, it returns. """ self._stopsReadingTest(Tunnel.EWOULDBLOCK_STYLE) def test_eintrblockStopsReading(self): """ Once L{TuntapPort.doRead} encounters an I{EINTR} errno from a C{read} call, it returns. """ self._stopsReadingTest(Tunnel.EINTR_STYLE) def test_unhandledReadError(self): """ If L{Tuntap.doRead} encounters any exception other than one explicitly handled by the code, the exception propagates to the caller. """ class UnexpectedException(Exception): pass self.assertRaises( UnexpectedException, self._stopsReadingTest, UnexpectedException()) def test_unhandledEnvironmentReadError(self): """ Just like C{test_unhandledReadError}, but for the case where the exception that is not explicitly handled happens to be of type C{EnvironmentError} (C{OSError} or C{IOError}). """ self.assertRaises( IOError, self._stopsReadingTest, IOError(EPERM, "Operation not permitted")) def test_doReadSmallDatagram(self): """ L{TuntapPort.doRead} reads a datagram of fewer than C{TuntapPort.maxPacketSize} from the port's file descriptor and passes it to its protocol's C{datagramReceived} method. """ datagram = b'x' * (self.port.maxPacketSize - 1) self.port.startListening() tunnel = self.system.getTunnel(self.port) tunnel.readBuffer.append(datagram) self.port.doRead() self.assertEqual([datagram], self.protocol.received) def test_doReadLargeDatagram(self): """ L{TuntapPort.doRead} reads the first part of a datagram of more than C{TuntapPort.maxPacketSize} from the port's file descriptor and passes the truncated data to its protocol's C{datagramReceived} method. """ datagram = b'x' * self.port.maxPacketSize self.port.startListening() tunnel = self.system.getTunnel(self.port) tunnel.readBuffer.append(datagram + b'y') self.port.doRead() self.assertEqual([datagram], self.protocol.received) def test_doReadSeveralDatagrams(self): """ L{TuntapPort.doRead} reads several datagrams, of up to C{TuntapPort.maxThroughput} bytes total, before returning. """ values = cycle(iterbytes(b'abcdefghijklmnopqrstuvwxyz')) total = 0 datagrams = [] while total < self.port.maxThroughput: datagrams.append(next(values) * self.port.maxPacketSize) total += self.port.maxPacketSize self.port.startListening() tunnel = self.system.getTunnel(self.port) tunnel.readBuffer.extend(datagrams) tunnel.readBuffer.append(b'excessive datagram, not to be read') self.port.doRead() self.assertEqual(datagrams, self.protocol.received) def _datagramReceivedException(self): """ Deliver some data to a L{TuntapPort} hooked up to an application protocol that raises an exception from its C{datagramReceived} method. @return: Whatever L{AttributeError} exceptions are logged. """ self.port.startListening() self.system.getTunnel(self.port).readBuffer.append(b"ping") # Break the application logic self.protocol.received = None self.port.doRead() return self.flushLoggedErrors(AttributeError) def test_datagramReceivedException(self): """ If the protocol's C{datagramReceived} method raises an exception, the exception is logged. """ errors = self._datagramReceivedException() self.assertEqual(1, len(errors)) def test_datagramReceivedExceptionIdentifiesProtocol(self): """ The exception raised by C{datagramReceived} is logged with a message identifying the offending protocol. """ messages = [] addObserver(messages.append) self.addCleanup(removeObserver, messages.append) self._datagramReceivedException() error = next(m for m in messages if m['isError']) message = textFromEventDict(error) self.assertEqual( "Unhandled exception from %s.datagramReceived" % ( fullyQualifiedName(self.protocol.__class__),), message.splitlines()[0]) def test_write(self): """ L{TuntapPort.write} sends a datagram into the tunnel. """ datagram = b"a b c d e f g" self.port.startListening() self.port.write(datagram) self.assertEqual( self.system.getTunnel(self.port).writeBuffer, deque([datagram])) def test_interruptedWrite(self): """ If the platform write call is interrupted (causing the Python wrapper to raise C{IOError} with errno set to C{EINTR}), the write is re-tried. """ self.port.startListening() tunnel = self.system.getTunnel(self.port) tunnel.pendingSignals.append(SIGINT) self.port.write(b"hello, world") self.assertEqual(deque([b"hello, world"]), tunnel.writeBuffer) def test_unhandledWriteError(self): """ Any exception raised by the underlying write call, except for EINTR, is propagated to the caller. """ self.port.startListening() tunnel = self.system.getTunnel(self.port) self.assertRaises( IOError, self.port.write, b"x" * tunnel.SEND_BUFFER_SIZE + b"y") def test_writeSequence(self): """ L{TuntapPort.writeSequence} sends a datagram into the tunnel by concatenating the byte strings in the list passed to it. """ datagram = [b"a", b"b", b"c", b"d"] self.port.startListening() self.port.writeSequence(datagram) self.assertEqual( self.system.getTunnel(self.port).writeBuffer, deque([b"".join(datagram)])) def test_getHost(self): """ L{TuntapPort.getHost} returns a L{TunnelAddress} including the tunnel's type and name. """ self.port.startListening() address = self.port.getHost() self.assertEqual( TunnelAddress( self._tunnelTypeOnly(self.helper.TUNNEL_TYPE), self.system.getTunnel(self.port).name), address) def test_listeningString(self): """ The string representation of a L{TuntapPort} instance includes the tunnel type and interface and the protocol associated with the port. """ self.port.startListening() self.assertRegex(str(self.port), fullyQualifiedName(self.protocol.__class__)) expected = " listening on %s/%s>" % ( self._tunnelTypeOnly(self.helper.TUNNEL_TYPE).name, self.system.getTunnel(self.port).name) self.assertTrue(str(self.port).find(expected) != -1) def test_unlisteningString(self): """ The string representation of a L{TuntapPort} instance includes the tunnel type and interface and the protocol associated with the port. """ self.assertRegex(str(self.port), fullyQualifiedName(self.protocol.__class__)) expected = " not listening on %s/%s>" % ( self._tunnelTypeOnly(self.helper.TUNNEL_TYPE).name, self.name) self.assertTrue(str(self.port).find(expected) != -1) def test_logPrefix(self): """ L{TuntapPort.logPrefix} returns a string identifying the application protocol and the type of tunnel. """ self.assertEqual( "%s (%s)" % ( self.protocol.__class__.__name__, self._tunnelTypeOnly(self.helper.TUNNEL_TYPE).name), self.port.logPrefix())
if vport == port: outgoing = self.connections[:(vport, endpoint)] # return the UDP6Forwarder instance responsible for this port # and the IP6Endpoint where the should be sent to return (self.sockets[outgoing[0]], outgoing[1]) # reached this? Ohoh. print "No connection found for virtual port %d" % (port) return (None, None) def listen(self): for port in self.ports: self.sockets[port] = UDP6Forwarder(self) reactor.listenUDP(port, self.sockets[port], interface='::1') # START config = read_configuration() riot = RiotProtocol() udp = UDPConnectionManager(config['UDP6'], riot) udp.listen() print "Listening on UDP ports: %s" % (udp.ports) tap = TuntapPort(interface=config['interface'], proto=riot, reactor=reactor) tap.startListening() config['tap_mac'] = get_tap_mac(config['interface'], tap.fileno()) print "Listening on tap interface %s with MAC address %s" % (config['interface'], config['tap_mac']) reactor.run()
class TunnelTestsMixin(object): """ A mixin defining tests for L{TuntapPort}. These tests run against L{MemoryIOSystem} (proven equivalent to the real thing by the tests above) to avoid performing any real I/O. """ def setUp(self): """ Create an in-memory I/O system and set up a L{TuntapPort} against it. """ self.name = b"tun0" self.system = MemoryIOSystem() self.system.registerSpecialDevice(Tunnel._DEVICE_NAME, Tunnel) self.protocol = self.factory.buildProtocol( TunnelAddress(self.helper.TUNNEL_TYPE, self.name)) self.reactor = FSSetClock() self.port = TuntapPort( self.name, self.protocol, reactor=self.reactor, system=self.system) def _tunnelTypeOnly(self, flags): """ Mask off any flags except for L{TunnelType.IFF_TUN} and L{TunnelType.IFF_TAP}. @param flags: Flags from L{TunnelType} to mask. @type flags: L{FlagConstant} @return: The flags given by C{flags} except the two type flags. @rtype: L{FlagConstant} """ return flags & (TunnelFlags.IFF_TUN | TunnelFlags.IFF_TAP) def test_startListeningOpensDevice(self): """ L{TuntapPort.startListening} opens the tunnel factory character special device C{"/dev/net/tun"} and configures it as a I{tun} tunnel. """ system = self.system self.port.startListening() tunnel = self.system.getTunnel(self.port) expected = ( system.O_RDWR | system.O_CLOEXEC | system.O_NONBLOCK, b"tun0" + "\x00" * (_IFNAMSIZ - len(b"tun0")), self.port.interface, False, True) actual = ( tunnel.openFlags, tunnel.requestedName, tunnel.name, tunnel.blocking, tunnel.closeOnExec) self.assertEqual(expected, actual) def test_startListeningSetsConnected(self): """ L{TuntapPort.startListening} sets C{connected} on the port object to C{True}. """ self.port.startListening() self.assertTrue(self.port.connected) def test_startListeningConnectsProtocol(self): """ L{TuntapPort.startListening} calls C{makeConnection} on the protocol the port was initialized with, passing the port as an argument. """ self.port.startListening() self.assertIs(self.port, self.protocol.transport) def test_startListeningStartsReading(self): """ L{TuntapPort.startListening} passes the port instance to the reactor's C{addReader} method to begin watching the port's file descriptor for data to read. """ self.port.startListening() self.assertIn(self.port, self.reactor.getReaders()) def test_startListeningHandlesOpenFailure(self): """ L{TuntapPort.startListening} raises L{CannotListenError} if opening the tunnel factory character special device fails. """ self.system.permissions.remove('open') self.assertRaises(CannotListenError, self.port.startListening) def test_startListeningHandlesConfigureFailure(self): """ L{TuntapPort.startListening} raises L{CannotListenError} if the C{ioctl} call to configure the tunnel device fails. """ self.system.permissions.remove('ioctl') self.assertRaises(CannotListenError, self.port.startListening) def _stopPort(self, port): """ Verify that the C{stopListening} method of an L{IListeningPort} removes that port from the reactor's "readers" set and also that the L{Deferred} returned by that method fires with C{None}. @param port: The port object to stop. @type port: L{IListeningPort} provider """ stopped = port.stopListening() self.assertNotIn(port, self.reactor.getReaders()) # An unfortunate implementation detail self.reactor.advance(0) self.assertIs(None, self.successResultOf(stopped)) def test_stopListeningStopsReading(self): """ L{TuntapPort.stopListening} returns a L{Deferred} which fires after the port has been removed from the reactor's reader list by passing it to the reactor's C{removeReader} method. """ self.port.startListening() fileno = self.port.fileno() self._stopPort(self.port) self.assertNotIn(fileno, self.system._openFiles) def test_stopListeningUnsetsConnected(self): """ After the L{Deferred} returned by L{TuntapPort.stopListening} fires, the C{connected} attribute of the port object is set to C{False}. """ self.port.startListening() self._stopPort(self.port) self.assertFalse(self.port.connected) def test_stopListeningStopsProtocol(self): """ L{TuntapPort.stopListening} calls C{doStop} on the protocol the port was initialized with. """ self.port.startListening() self._stopPort(self.port) self.assertIs(None, self.protocol.transport) def test_stopListeningWhenStopped(self): """ L{TuntapPort.stopListening} returns a L{Deferred} which succeeds immediately if it is called when the port is not listening. """ stopped = self.port.stopListening() self.assertIs(None, self.successResultOf(stopped)) def test_multipleStopListening(self): """ It is safe and a no-op to call L{TuntapPort.stopListening} more than once with no intervening L{TuntapPort.startListening} call. """ self.port.startListening() self.port.stopListening() second = self.port.stopListening() self.reactor.advance(0) self.assertIs(None, self.successResultOf(second)) def test_loseConnection(self): """ L{TuntapPort.loseConnection} stops the port and is deprecated. """ self.port.startListening() self.port.loseConnection() # An unfortunate implementation detail self.reactor.advance(0) self.assertFalse(self.port.connected) warnings = self.flushWarnings([self.test_loseConnection]) self.assertEqual(DeprecationWarning, warnings[0]['category']) self.assertEqual( "twisted.pair.tuntap.TuntapPort.loseConnection was deprecated " "in Twisted 14.0.0; please use twisted.pair.tuntap.TuntapPort." "stopListening instead", warnings[0]['message']) self.assertEqual(1, len(warnings)) def _stopsReadingTest(self, style): """ Test that L{TuntapPort.doRead} has no side-effects under a certain exception condition. @param style: An exception instance to arrange for the (python wrapper around the) underlying platform I{read} call to fail with. @raise C{self.failureException}: If there are any observable side-effects. """ self.port.startListening() tunnel = self.system.getTunnel(self.port) tunnel.nonBlockingExceptionStyle = style self.port.doRead() self.assertEqual([], self.protocol.received) def test_eagainStopsReading(self): """ Once L{TuntapPort.doRead} encounters an I{EAGAIN} errno from a C{read} call, it returns. """ self._stopsReadingTest(Tunnel.EAGAIN_STYLE) def test_ewouldblockStopsReading(self): """ Once L{TuntapPort.doRead} encounters an I{EWOULDBLOCK} errno from a C{read} call, it returns. """ self._stopsReadingTest(Tunnel.EWOULDBLOCK_STYLE) def test_eintrblockStopsReading(self): """ Once L{TuntapPort.doRead} encounters an I{EINTR} errno from a C{read} call, it returns. """ self._stopsReadingTest(Tunnel.EINTR_STYLE) def test_unhandledReadError(self): """ If L{Tuntap.doRead} encounters any exception other than one explicitly handled by the code, the exception propagates to the caller. """ class UnexpectedException(Exception): pass self.assertRaises( UnexpectedException, self._stopsReadingTest, UnexpectedException()) def test_unhandledEnvironmentReadError(self): """ Just like C{test_unhandledReadError}, but for the case where the exception that is not explicitly handled happens to be of type C{EnvironmentError} (C{OSError} or C{IOError}). """ self.assertRaises( IOError, self._stopsReadingTest, IOError(EPERM, "Operation not permitted")) def test_doReadSmallDatagram(self): """ L{TuntapPort.doRead} reads a datagram of fewer than C{TuntapPort.maxPacketSize} from the port's file descriptor and passes it to its protocol's C{datagramReceived} method. """ datagram = b'x' * (self.port.maxPacketSize - 1) self.port.startListening() tunnel = self.system.getTunnel(self.port) tunnel.readBuffer.append(datagram) self.port.doRead() self.assertEqual([datagram], self.protocol.received) def test_doReadLargeDatagram(self): """ L{TuntapPort.doRead} reads the first part of a datagram of more than C{TuntapPort.maxPacketSize} from the port's file descriptor and passes the truncated data to its protocol's C{datagramReceived} method. """ datagram = b'x' * self.port.maxPacketSize self.port.startListening() tunnel = self.system.getTunnel(self.port) tunnel.readBuffer.append(datagram + b'y') self.port.doRead() self.assertEqual([datagram], self.protocol.received) def test_doReadSeveralDatagrams(self): """ L{TuntapPort.doRead} reads several datagrams, of up to C{TuntapPort.maxThroughput} bytes total, before returning. """ values = cycle(iterbytes(b'abcdefghijklmnopqrstuvwxyz')) total = 0 datagrams = [] while total < self.port.maxThroughput: datagrams.append(next(values) * self.port.maxPacketSize) total += self.port.maxPacketSize self.port.startListening() tunnel = self.system.getTunnel(self.port) tunnel.readBuffer.extend(datagrams) tunnel.readBuffer.append(b'excessive datagram, not to be read') self.port.doRead() self.assertEqual(datagrams, self.protocol.received) def _datagramReceivedException(self): """ Deliver some data to a L{TuntapPort} hooked up to an application protocol that raises an exception from its C{datagramReceived} method. @return: Whatever L{AttributeError} exceptions are logged. """ self.port.startListening() self.system.getTunnel(self.port).readBuffer.append(b"ping") # Break the application logic self.protocol.received = None self.port.doRead() return self.flushLoggedErrors(AttributeError) def test_datagramReceivedException(self): """ If the protocol's C{datagramReceived} method raises an exception, the exception is logged. """ errors = self._datagramReceivedException() self.assertEqual(1, len(errors)) def test_datagramReceivedExceptionIdentifiesProtocol(self): """ The exception raised by C{datagramReceived} is logged with a message identifying the offending protocol. """ messages = [] addObserver(messages.append) self.addCleanup(removeObserver, messages.append) self._datagramReceivedException() error = next(m for m in messages if m['isError']) message = textFromEventDict(error) self.assertEqual( "Unhandled exception from %s.datagramReceived" % ( fullyQualifiedName(self.protocol.__class__),), message.splitlines()[0]) def test_write(self): """ L{TuntapPort.write} sends a datagram into the tunnel. """ datagram = b"a b c d e f g" self.port.startListening() self.port.write(datagram) self.assertEqual( self.system.getTunnel(self.port).writeBuffer, deque([datagram])) def test_interruptedWrite(self): """ If the platform write call is interrupted (causing the Python wrapper to raise C{IOError} with errno set to C{EINTR}), the write is re-tried. """ self.port.startListening() tunnel = self.system.getTunnel(self.port) tunnel.pendingSignals.append(SIGINT) self.port.write(b"hello, world") self.assertEqual(deque([b"hello, world"]), tunnel.writeBuffer) def test_unhandledWriteError(self): """ Any exception raised by the underlying write call, except for EINTR, is propagated to the caller. """ self.port.startListening() tunnel = self.system.getTunnel(self.port) self.assertRaises( IOError, self.port.write, b"x" * tunnel.SEND_BUFFER_SIZE + b"y") def test_writeSequence(self): """ L{TuntapPort.writeSequence} sends a datagram into the tunnel by concatenating the byte strings in the list passed to it. """ datagram = [b"a", b"b", b"c", b"d"] self.port.startListening() self.port.writeSequence(datagram) self.assertEqual( self.system.getTunnel(self.port).writeBuffer, deque([b"".join(datagram)])) def test_getHost(self): """ L{TuntapPort.getHost} returns a L{TunnelAddress} including the tunnel's type and name. """ self.port.startListening() address = self.port.getHost() self.assertEqual( TunnelAddress( self._tunnelTypeOnly(self.helper.TUNNEL_TYPE), self.system.getTunnel(self.port).name), address) def test_listeningString(self): """ The string representation of a L{TuntapPort} instance includes the tunnel type and interface and the protocol associated with the port. """ self.port.startListening() expected = "<%s listening on %s/%s>" % ( fullyQualifiedName(self.protocol.__class__), self._tunnelTypeOnly(self.helper.TUNNEL_TYPE).name, self.system.getTunnel(self.port).name) self.assertEqual(expected, str(self.port)) def test_unlisteningString(self): """ The string representation of a L{TuntapPort} instance includes the tunnel type and interface and the protocol associated with the port. """ expected = "<%s not listening on %s/%s>" % ( fullyQualifiedName(self.protocol.__class__), self._tunnelTypeOnly(self.helper.TUNNEL_TYPE).name, self.name) self.assertEqual(expected, str(self.port)) def test_logPrefix(self): """ L{TuntapPort.logPrefix} returns a string identifying the application protocol and the type of tunnel. """ self.assertEqual( "%s (%s)" % ( self.protocol.__class__.__name__, self._tunnelTypeOnly(self.helper.TUNNEL_TYPE).name), self.port.logPrefix())
if vport == port: outgoing = self.connections[:(vport, endpoint)] # return the UDP6Forwarder instance responsible for this port # and the IP6Endpoint where the should be sent to return (self.sockets[outgoing[0]], outgoing[1]) # reached this? Ohoh. print "No connection found for virtual port %d" % (port) return (None, None) def listen(self): for port in self.ports: self.sockets[port] = UDP6Forwarder(self) reactor.listenUDP(port, self.sockets[port], interface='::1') # START config = read_configuration() riot = RiotProtocol() udp = UDPConnectionManager(config['UDP6'], riot) udp.listen() print "Listening on UDP ports: %s" % (udp.ports) tap = TuntapPort(interface=config['interface'], proto=riot, reactor=reactor) tap.startListening() config['tap_mac'] = get_tap_mac(config['interface'], tap.fileno()) print "Listening on tap interface %s with MAC address %s" % ( config['interface'], config['tap_mac']) reactor.run()