[CalendarServer-changes] [9055] CalendarServer/branches/users/glyph/ipv6-client

source_changes at macosforge.org source_changes at macosforge.org
Fri Apr 13 11:43:15 PDT 2012


Revision: 9055
          http://trac.macosforge.org/projects/calendarserver/changeset/9055
Author:   glyph at apple.com
Date:     2012-04-13 11:43:14 -0700 (Fri, 13 Apr 2012)
Log Message:
-----------
Add a temporary backport of required Twisted functionality for IPv6 clients.

Modified Paths:
--------------
    CalendarServer/branches/users/glyph/ipv6-client/calendarserver/__init__.py
    CalendarServer/branches/users/glyph/ipv6-client/support/build.sh
    CalendarServer/branches/users/glyph/ipv6-client/twext/patches.py

Added Paths:
-----------
    CalendarServer/branches/users/glyph/ipv6-client/twext/backport/
    CalendarServer/branches/users/glyph/ipv6-client/twext/backport/__init__.py
    CalendarServer/branches/users/glyph/ipv6-client/twext/backport/internet/
    CalendarServer/branches/users/glyph/ipv6-client/twext/backport/internet/__init__.py
    CalendarServer/branches/users/glyph/ipv6-client/twext/backport/internet/address.py
    CalendarServer/branches/users/glyph/ipv6-client/twext/backport/internet/endpoints.py
    CalendarServer/branches/users/glyph/ipv6-client/twext/backport/internet/tcp.py

Modified: CalendarServer/branches/users/glyph/ipv6-client/calendarserver/__init__.py
===================================================================
--- CalendarServer/branches/users/glyph/ipv6-client/calendarserver/__init__.py	2012-04-13 18:40:22 UTC (rev 9054)
+++ CalendarServer/branches/users/glyph/ipv6-client/calendarserver/__init__.py	2012-04-13 18:43:14 UTC (rev 9055)
@@ -19,6 +19,10 @@
 CalendarServer application code.
 """
 
+# Make sure we have twext's required Twisted patches loaded before we do
+# anything at all.
+__import__("twext")
+
 #
 # setuptools is annoying
 #

Modified: CalendarServer/branches/users/glyph/ipv6-client/support/build.sh
===================================================================
--- CalendarServer/branches/users/glyph/ipv6-client/support/build.sh	2012-04-13 18:40:22 UTC (rev 9054)
+++ CalendarServer/branches/users/glyph/ipv6-client/support/build.sh	2012-04-13 18:43:14 UTC (rev 9055)
@@ -717,6 +717,8 @@
     "PyGreSQL" "pgdb" "${pg}" \
     "${pypi}/P/PyGreSQL/${pg}.tar.gz";
 
+  # Maintenance note: next time the Twisted dependency gets updated, check out
+  # twext/patches.py.
   py_dependency -v 12 -r HEAD \
     "Twisted" "twisted" "Twisted" \
     "svn://svn.twistedmatrix.com/svn/Twisted/tags/releases/twisted-12.0.0";

Added: CalendarServer/branches/users/glyph/ipv6-client/twext/backport/__init__.py
===================================================================
Added: CalendarServer/branches/users/glyph/ipv6-client/twext/backport/internet/__init__.py
===================================================================
Added: CalendarServer/branches/users/glyph/ipv6-client/twext/backport/internet/address.py
===================================================================
--- CalendarServer/branches/users/glyph/ipv6-client/twext/backport/internet/address.py	                        (rev 0)
+++ CalendarServer/branches/users/glyph/ipv6-client/twext/backport/internet/address.py	2012-04-13 18:43:14 UTC (rev 9055)
@@ -0,0 +1,144 @@
+# Copyright (c) Twisted Matrix Laboratories.
+# See LICENSE for details.
+
+"""
+Address objects for network connections.
+"""
+
+import warnings, os
+
+from zope.interface import implements
+
+from twisted.internet.interfaces import IAddress
+from twisted.python import util
+
+
+class _IPAddress(object, util.FancyEqMixin):
+    """
+    An L{_IPAddress} represents the address of an IP socket endpoint, providing
+    common behavior for IPv4 and IPv6.
+
+    @ivar type: A string describing the type of transport, either 'TCP' or
+        'UDP'.
+
+    @ivar host: A string containing the presentation format of the IP address;
+        for example, "127.0.0.1" or "::1".
+    @type host: C{str}
+
+    @ivar port: An integer representing the port number.
+    @type port: C{int}
+    """
+
+    implements(IAddress)
+
+    compareAttributes = ('type', 'host', 'port')
+
+    def __init__(self, type, host, port):
+        assert type in ('TCP', 'UDP')
+        self.type = type
+        self.host = host
+        self.port = port
+
+
+    def __repr__(self):
+        return '%s(%s, %r, %d)' % (
+            self.__class__.__name__, self.type, self.host, self.port)
+
+
+    def __hash__(self):
+        return hash((self.type, self.host, self.port))
+
+
+
+class IPv4Address(_IPAddress):
+    """
+    An L{IPv4Address} represents the address of an IPv4 socket endpoint.
+
+    @ivar host: A string containing a dotted-quad IPv4 address; for example,
+        "127.0.0.1".
+    @type host: C{str}
+    """
+
+    def __init__(self, type, host, port, _bwHack=None):
+        _IPAddress.__init__(self, type, host, port)
+        if _bwHack is not None:
+            warnings.warn("twisted.internet.address.IPv4Address._bwHack "
+                          "is deprecated since Twisted 11.0",
+                          DeprecationWarning, stacklevel=2)
+
+
+
+class IPv6Address(_IPAddress):
+    """
+    An L{IPv6Address} represents the address of an IPv6 socket endpoint.
+
+    @ivar host: A string containing a colon-separated, hexadecimal formatted
+        IPv6 address; for example, "::1".
+    @type host: C{str}
+    """
+
+
+
+class UNIXAddress(object, util.FancyEqMixin):
+    """
+    Object representing a UNIX socket endpoint.
+
+    @ivar name: The filename associated with this socket.
+    @type name: C{str}
+    """
+
+    implements(IAddress)
+
+    compareAttributes = ('name', )
+
+    def __init__(self, name, _bwHack = None):
+        self.name = name
+        if _bwHack is not None:
+            warnings.warn("twisted.internet.address.UNIXAddress._bwHack is deprecated since Twisted 11.0",
+                    DeprecationWarning, stacklevel=2)
+
+
+    if getattr(os.path, 'samefile', None) is not None:
+        def __eq__(self, other):
+            """
+            overriding L{util.FancyEqMixin} to ensure the os level samefile
+            check is done if the name attributes do not match.
+            """
+            res = super(UNIXAddress, self).__eq__(other)
+            if res == False:
+                try:
+                    return os.path.samefile(self.name, other.name)
+                except OSError:
+                    pass
+            return res
+
+
+    def __repr__(self):
+        return 'UNIXAddress(%r)' % (self.name,)
+
+
+    def __hash__(self):
+        try:
+            s1 = os.stat(self.name)
+            return hash((s1.st_ino, s1.st_dev))
+        except OSError:
+            return hash(self.name)
+
+
+
+# These are for buildFactory backwards compatability due to
+# stupidity-induced inconsistency.
+
+class _ServerFactoryIPv4Address(IPv4Address):
+    """Backwards compatability hack. Just like IPv4Address in practice."""
+
+    def __eq__(self, other):
+        if isinstance(other, tuple):
+            warnings.warn("IPv4Address.__getitem__ is deprecated.  Use attributes instead.",
+                          category=DeprecationWarning, stacklevel=2)
+            return (self.host, self.port) == other
+        elif isinstance(other, IPv4Address):
+            a = (self.type, self.host, self.port)
+            b = (other.type, other.host, other.port)
+            return a == b
+        return False

Added: CalendarServer/branches/users/glyph/ipv6-client/twext/backport/internet/endpoints.py
===================================================================
--- CalendarServer/branches/users/glyph/ipv6-client/twext/backport/internet/endpoints.py	                        (rev 0)
+++ CalendarServer/branches/users/glyph/ipv6-client/twext/backport/internet/endpoints.py	2012-04-13 18:43:14 UTC (rev 9055)
@@ -0,0 +1,1159 @@
+# -*- test-case-name: twisted.internet.test.test_endpoints -*-
+# Copyright (c) Twisted Matrix Laboratories.
+# See LICENSE for details.
+"""
+Implementations of L{IStreamServerEndpoint} and L{IStreamClientEndpoint} that
+wrap the L{IReactorTCP}, L{IReactorSSL}, and L{IReactorUNIX} interfaces.
+
+This also implements an extensible mini-language for describing endpoints,
+parsed by the L{clientFromString} and L{serverFromString} functions.
+
+ at since: 10.1
+"""
+
+import os, socket
+
+from zope.interface import implements, directlyProvides
+import warnings
+
+from twisted.internet import interfaces, defer, error, fdesc
+from twisted.internet.protocol import ClientFactory, Protocol
+from twisted.plugin import IPlugin, getPlugins
+from twisted.internet.interfaces import IStreamServerEndpointStringParser
+from twisted.internet.interfaces import IStreamClientEndpointStringParser
+from twisted.python.filepath import FilePath
+from twisted.python.systemd import ListenFDs
+
+
+__all__ = ["clientFromString", "serverFromString",
+           "TCP4ServerEndpoint", "TCP4ClientEndpoint",
+           "UNIXServerEndpoint", "UNIXClientEndpoint",
+           "SSL4ServerEndpoint", "SSL4ClientEndpoint",
+           "AdoptedStreamServerEndpoint"]
+
+
+class _WrappingProtocol(Protocol):
+    """
+    Wrap another protocol in order to notify my user when a connection has
+    been made.
+
+    @ivar _connectedDeferred: The L{Deferred} that will callback
+        with the C{wrappedProtocol} when it is connected.
+
+    @ivar _wrappedProtocol: An L{IProtocol} provider that will be
+        connected.
+    """
+
+    def __init__(self, connectedDeferred, wrappedProtocol):
+        """
+        @param connectedDeferred: The L{Deferred} that will callback
+            with the C{wrappedProtocol} when it is connected.
+
+        @param wrappedProtocol: An L{IProtocol} provider that will be
+            connected.
+        """
+        self._connectedDeferred = connectedDeferred
+        self._wrappedProtocol = wrappedProtocol
+
+        if interfaces.IHalfCloseableProtocol.providedBy(
+            self._wrappedProtocol):
+            directlyProvides(self, interfaces.IHalfCloseableProtocol)
+
+
+    def logPrefix(self):
+        """
+        Transparently pass through the wrapped protocol's log prefix.
+        """
+        if interfaces.ILoggingContext.providedBy(self._wrappedProtocol):
+            return self._wrappedProtocol.logPrefix()
+        return self._wrappedProtocol.__class__.__name__
+
+
+    def connectionMade(self):
+        """
+        Connect the C{self._wrappedProtocol} to our C{self.transport} and
+        callback C{self._connectedDeferred} with the C{self._wrappedProtocol}
+        """
+        self._wrappedProtocol.makeConnection(self.transport)
+        self._connectedDeferred.callback(self._wrappedProtocol)
+
+
+    def dataReceived(self, data):
+        """
+        Proxy C{dataReceived} calls to our C{self._wrappedProtocol}
+        """
+        return self._wrappedProtocol.dataReceived(data)
+
+
+    def connectionLost(self, reason):
+        """
+        Proxy C{connectionLost} calls to our C{self._wrappedProtocol}
+        """
+        return self._wrappedProtocol.connectionLost(reason)
+
+
+    def readConnectionLost(self):
+        """
+        Proxy L{IHalfCloseableProtocol.readConnectionLost} to our
+        C{self._wrappedProtocol}
+        """
+        self._wrappedProtocol.readConnectionLost()
+
+
+    def writeConnectionLost(self):
+        """
+        Proxy L{IHalfCloseableProtocol.writeConnectionLost} to our
+        C{self._wrappedProtocol}
+        """
+        self._wrappedProtocol.writeConnectionLost()
+
+
+
+class _WrappingFactory(ClientFactory):
+    """
+    Wrap a factory in order to wrap the protocols it builds.
+
+    @ivar _wrappedFactory:  A provider of I{IProtocolFactory} whose
+        buildProtocol method will be called and whose resulting protocol
+        will be wrapped.
+
+    @ivar _onConnection: An L{Deferred} that fires when the protocol is
+        connected
+    """
+    protocol = _WrappingProtocol
+
+    def __init__(self, wrappedFactory):
+        """
+        @param wrappedFactory: A provider of I{IProtocolFactory} whose
+            buildProtocol method will be called and whose resulting protocol
+            will be wrapped.
+        """
+        self._wrappedFactory = wrappedFactory
+        self._onConnection = defer.Deferred(canceller=self._canceller)
+
+
+    def startedConnecting(self, connector):
+        self._connector = connector
+
+
+    def _canceller(self, deferred):
+        deferred.errback(
+            error.ConnectingCancelledError(
+                self._connector.getDestination()))
+        self._connector.stopConnecting()
+
+
+    def doStart(self):
+        """
+        Start notifications are passed straight through to the wrapped factory.
+        """
+        self._wrappedFactory.doStart()
+
+
+    def doStop(self):
+        """
+        Stop notifications are passed straight through to the wrapped factory.
+        """
+        self._wrappedFactory.doStop()
+
+
+    def buildProtocol(self, addr):
+        """
+        Proxy C{buildProtocol} to our C{self._wrappedFactory} or errback
+        the C{self._onConnection} L{Deferred}.
+
+        @return: An instance of L{_WrappingProtocol} or C{None}
+        """
+        try:
+            proto = self._wrappedFactory.buildProtocol(addr)
+        except:
+            self._onConnection.errback()
+        else:
+            return self.protocol(self._onConnection, proto)
+
+
+    def clientConnectionFailed(self, connector, reason):
+        """
+        Errback the C{self._onConnection} L{Deferred} when the
+        client connection fails.
+        """
+        if not self._onConnection.called:
+            self._onConnection.errback(reason)
+
+
+
+class TCP4ServerEndpoint(object):
+    """
+    TCP server endpoint with an IPv4 configuration
+
+    @ivar _reactor: An L{IReactorTCP} provider.
+
+    @type _port: int
+    @ivar _port: The port number on which to listen for incoming connections.
+
+    @type _backlog: int
+    @ivar _backlog: size of the listen queue
+
+    @type _interface: str
+    @ivar _interface: the hostname to bind to, defaults to '' (all)
+    """
+    implements(interfaces.IStreamServerEndpoint)
+
+    def __init__(self, reactor, port, backlog=50, interface=''):
+        """
+        @param reactor: An L{IReactorTCP} provider.
+        @param port: The port number used listening
+        @param backlog: size of the listen queue
+        @param interface: the hostname to bind to, defaults to '' (all)
+        """
+        self._reactor = reactor
+        self._port = port
+        self._listenArgs = dict(backlog=50, interface='')
+        self._backlog = backlog
+        self._interface = interface
+
+
+    def listen(self, protocolFactory):
+        """
+        Implement L{IStreamServerEndpoint.listen} to listen on a TCP socket
+        """
+        return defer.execute(self._reactor.listenTCP,
+                             self._port,
+                             protocolFactory,
+                             backlog=self._backlog,
+                             interface=self._interface)
+
+
+
+class TCP4ClientEndpoint(object):
+    """
+    TCP client endpoint with an IPv4 configuration.
+
+    @ivar _reactor: An L{IReactorTCP} provider.
+
+    @type _host: str
+    @ivar _host: The hostname to connect to as a C{str}
+
+    @type _port: int
+    @ivar _port: The port to connect to as C{int}
+
+    @type _timeout: int
+    @ivar _timeout: number of seconds to wait before assuming the
+        connection has failed.
+
+    @type _bindAddress: tuple
+    @type _bindAddress: a (host, port) tuple of local address to bind
+        to, or None.
+    """
+    implements(interfaces.IStreamClientEndpoint)
+
+    def __init__(self, reactor, host, port, timeout=30, bindAddress=None):
+        """
+        @param reactor: An L{IReactorTCP} provider
+        @param host: A hostname, used when connecting
+        @param port: The port number, used when connecting
+        @param timeout: number of seconds to wait before assuming the
+            connection has failed.
+        @param bindAddress: a (host, port tuple of local address to bind to,
+            or None.
+        """
+        self._reactor = reactor
+        self._host = host
+        self._port = port
+        self._timeout = timeout
+        self._bindAddress = bindAddress
+
+
+    def connect(self, protocolFactory):
+        """
+        Implement L{IStreamClientEndpoint.connect} to connect via TCP.
+        """
+        try:
+            wf = _WrappingFactory(protocolFactory)
+            self._reactor.connectTCP(
+                self._host, self._port, wf,
+                timeout=self._timeout, bindAddress=self._bindAddress)
+            return wf._onConnection
+        except:
+            return defer.fail()
+
+
+
+class SSL4ServerEndpoint(object):
+    """
+    SSL secured TCP server endpoint with an IPv4 configuration.
+
+    @ivar _reactor: An L{IReactorSSL} provider.
+
+    @type _host: str
+    @ivar _host: The hostname to connect to as a C{str}
+
+    @type _port: int
+    @ivar _port: The port to connect to as C{int}
+
+    @type _sslContextFactory: L{OpenSSLCertificateOptions}
+    @var _sslContextFactory: SSL Configuration information as an
+        L{OpenSSLCertificateOptions}
+
+    @type _backlog: int
+    @ivar _backlog: size of the listen queue
+
+    @type _interface: str
+    @ivar _interface: the hostname to bind to, defaults to '' (all)
+    """
+    implements(interfaces.IStreamServerEndpoint)
+
+    def __init__(self, reactor, port, sslContextFactory,
+                 backlog=50, interface=''):
+        """
+        @param reactor: An L{IReactorSSL} provider.
+        @param port: The port number used listening
+        @param sslContextFactory: An instance of
+            L{twisted.internet._sslverify.OpenSSLCertificateOptions}.
+        @param timeout: number of seconds to wait before assuming the
+            connection has failed.
+        @param bindAddress: a (host, port tuple of local address to bind to,
+            or None.
+        """
+        self._reactor = reactor
+        self._port = port
+        self._sslContextFactory = sslContextFactory
+        self._backlog = backlog
+        self._interface = interface
+
+
+    def listen(self, protocolFactory):
+        """
+        Implement L{IStreamServerEndpoint.listen} to listen for SSL on a
+        TCP socket.
+        """
+        return defer.execute(self._reactor.listenSSL, self._port,
+                             protocolFactory,
+                             contextFactory=self._sslContextFactory,
+                             backlog=self._backlog,
+                             interface=self._interface)
+
+
+
+class SSL4ClientEndpoint(object):
+    """
+    SSL secured TCP client endpoint with an IPv4 configuration
+
+    @ivar _reactor: An L{IReactorSSL} provider.
+
+    @type _host: str
+    @ivar _host: The hostname to connect to as a C{str}
+
+    @type _port: int
+    @ivar _port: The port to connect to as C{int}
+
+    @type _sslContextFactory: L{OpenSSLCertificateOptions}
+    @var _sslContextFactory: SSL Configuration information as an
+        L{OpenSSLCertificateOptions}
+
+    @type _timeout: int
+    @ivar _timeout: number of seconds to wait before assuming the
+        connection has failed.
+
+    @type _bindAddress: tuple
+    @ivar _bindAddress: a (host, port) tuple of local address to bind
+        to, or None.
+    """
+    implements(interfaces.IStreamClientEndpoint)
+
+    def __init__(self, reactor, host, port, sslContextFactory,
+                 timeout=30, bindAddress=None):
+        """
+        @param reactor: An L{IReactorSSL} provider.
+        @param host: A hostname, used when connecting
+        @param port: The port number, used when connecting
+        @param sslContextFactory: SSL Configuration information as An instance
+            of L{OpenSSLCertificateOptions}.
+        @param timeout: number of seconds to wait before assuming the
+            connection has failed.
+        @param bindAddress: a (host, port tuple of local address to bind to,
+            or None.
+        """
+        self._reactor = reactor
+        self._host = host
+        self._port = port
+        self._sslContextFactory = sslContextFactory
+        self._timeout = timeout
+        self._bindAddress = bindAddress
+
+
+    def connect(self, protocolFactory):
+        """
+        Implement L{IStreamClientEndpoint.connect} to connect with SSL over
+        TCP.
+        """
+        try:
+            wf = _WrappingFactory(protocolFactory)
+            self._reactor.connectSSL(
+                self._host, self._port, wf, self._sslContextFactory,
+                timeout=self._timeout, bindAddress=self._bindAddress)
+            return wf._onConnection
+        except:
+            return defer.fail()
+
+
+
+class UNIXServerEndpoint(object):
+    """
+    UnixSocket server endpoint.
+
+    @type path: str
+    @ivar path: a path to a unix socket on the filesystem.
+
+    @type _listenArgs: dict
+    @ivar _listenArgs: A C{dict} of keyword args that will be passed
+        to L{IReactorUNIX.listenUNIX}
+
+    @var _reactor: An L{IReactorTCP} provider.
+    """
+    implements(interfaces.IStreamServerEndpoint)
+
+    def __init__(self, reactor, address, backlog=50, mode=0666, wantPID=0):
+        """
+        @param reactor: An L{IReactorUNIX} provider.
+        @param address: The path to the Unix socket file, used when listening
+        @param listenArgs: An optional dict of keyword args that will be
+            passed to L{IReactorUNIX.listenUNIX}
+        @param backlog: number of connections to allow in backlog.
+        @param mode: mode to set on the unix socket.  This parameter is
+            deprecated.  Permissions should be set on the directory which
+            contains the UNIX socket.
+        @param wantPID: if True, create a pidfile for the socket.
+        """
+        self._reactor = reactor
+        self._address = address
+        self._backlog = backlog
+        self._mode = mode
+        self._wantPID = wantPID
+
+
+    def listen(self, protocolFactory):
+        """
+        Implement L{IStreamServerEndpoint.listen} to listen on a UNIX socket.
+        """
+        return defer.execute(self._reactor.listenUNIX, self._address,
+                             protocolFactory,
+                             backlog=self._backlog,
+                             mode=self._mode,
+                             wantPID=self._wantPID)
+
+
+
+class UNIXClientEndpoint(object):
+    """
+    UnixSocket client endpoint.
+
+    @type _path: str
+    @ivar _path: a path to a unix socket on the filesystem.
+
+    @type _timeout: int
+    @ivar _timeout: number of seconds to wait before assuming the connection
+        has failed.
+
+    @type _checkPID: bool
+    @ivar _checkPID: if True, check for a pid file to verify that a server
+        is listening.
+
+    @var _reactor: An L{IReactorUNIX} provider.
+    """
+    implements(interfaces.IStreamClientEndpoint)
+
+    def __init__(self, reactor, path, timeout=30, checkPID=0):
+        """
+        @param reactor: An L{IReactorUNIX} provider.
+        @param path: The path to the Unix socket file, used when connecting
+        @param timeout: number of seconds to wait before assuming the
+            connection has failed.
+        @param checkPID: if True, check for a pid file to verify that a server
+            is listening.
+        """
+        self._reactor = reactor
+        self._path = path
+        self._timeout = timeout
+        self._checkPID = checkPID
+
+
+    def connect(self, protocolFactory):
+        """
+        Implement L{IStreamClientEndpoint.connect} to connect via a
+        UNIX Socket
+        """
+        def _canceller(deferred):
+            connector.stopConnecting()
+            deferred.errback(
+                error.ConnectingCancelledError(connector.getDestination()))
+
+        try:
+            wf = _WrappingFactory(protocolFactory)
+            connector = self._reactor.connectUNIX(
+                self._path, wf,
+                timeout=self._timeout,
+                checkPID=self._checkPID)
+            return wf._onConnection
+        except:
+            return defer.fail()
+
+
+
+class AdoptedStreamServerEndpoint(object):
+    """
+    An endpoint for listening on a file descriptor initialized outside of
+    Twisted.
+
+    @ivar _used: A C{bool} indicating whether this endpoint has been used to
+        listen with a factory yet.  C{True} if so.
+    """
+    _close = os.close
+    _setNonBlocking = staticmethod(fdesc.setNonBlocking)
+
+    def __init__(self, reactor, fileno, addressFamily):
+        """
+        @param reactor: An L{IReactorSocket} provider.
+
+        @param fileno: An integer file descriptor corresponding to a listening
+            I{SOCK_STREAM} socket.
+
+        @param addressFamily: The address family of the socket given by
+            C{fileno}.
+        """
+        self.reactor = reactor
+        self.fileno = fileno
+        self.addressFamily = addressFamily
+        self._used = False
+
+
+    def listen(self, factory):
+        """
+        Implement L{IStreamServerEndpoint.listen} to start listening on, and
+        then close, C{self._fileno}.
+        """
+        if self._used:
+            return defer.fail(error.AlreadyListened())
+        self._used = True
+
+        try:
+            self._setNonBlocking(self.fileno)
+            port = self.reactor.adoptStreamPort(
+                self.fileno, self.addressFamily, factory)
+            self._close(self.fileno)
+        except:
+            return defer.fail()
+        return defer.succeed(port)
+
+
+
+def _parseTCP(factory, port, interface="", backlog=50):
+    """
+    Internal parser function for L{_parseServer} to convert the string
+    arguments for a TCP(IPv4) stream endpoint into the structured arguments.
+
+    @param factory: the protocol factory being parsed, or C{None}.  (This was a
+        leftover argument from when this code was in C{strports}, and is now
+        mostly None and unused.)
+
+    @type factory: L{IProtocolFactory} or C{NoneType}
+
+    @param port: the integer port number to bind
+    @type port: C{str}
+
+    @param interface: the interface IP to listen on
+    @param backlog: the length of the listen queue
+    @type backlog: C{str}
+
+    @return: a 2-tuple of (args, kwargs), describing  the parameters to
+        L{IReactorTCP.listenTCP} (or, modulo argument 2, the factory, arguments
+        to L{TCP4ServerEndpoint}.
+    """
+    return (int(port), factory), {'interface': interface,
+                                  'backlog': int(backlog)}
+
+
+
+def _parseUNIX(factory, address, mode='666', backlog=50, lockfile=True):
+    """
+    Internal parser function for L{_parseServer} to convert the string
+    arguments for a UNIX (AF_UNIX/SOCK_STREAM) stream endpoint into the
+    structured arguments.
+
+    @param factory: the protocol factory being parsed, or C{None}.  (This was a
+        leftover argument from when this code was in C{strports}, and is now
+        mostly None and unused.)
+
+    @type factory: L{IProtocolFactory} or C{NoneType}
+
+    @param address: the pathname of the unix socket
+    @type address: C{str}
+
+    @param backlog: the length of the listen queue
+    @type backlog: C{str}
+
+    @param lockfile: A string '0' or '1', mapping to True and False
+        respectively.  See the C{wantPID} argument to C{listenUNIX}
+
+    @return: a 2-tuple of (args, kwargs), describing  the parameters to
+        L{IReactorTCP.listenUNIX} (or, modulo argument 2, the factory,
+        arguments to L{UNIXServerEndpoint}.
+    """
+    return (
+        (address, factory),
+        {'mode': int(mode, 8), 'backlog': int(backlog),
+         'wantPID': bool(int(lockfile))})
+
+
+
+def _parseSSL(factory, port, privateKey="server.pem", certKey=None,
+              sslmethod=None, interface='', backlog=50):
+    """
+    Internal parser function for L{_parseServer} to convert the string
+    arguments for an SSL (over TCP/IPv4) stream endpoint into the structured
+    arguments.
+
+    @param factory: the protocol factory being parsed, or C{None}.  (This was a
+        leftover argument from when this code was in C{strports}, and is now
+        mostly None and unused.)
+
+    @type factory: L{IProtocolFactory} or C{NoneType}
+
+    @param port: the integer port number to bind
+    @type port: C{str}
+
+    @param interface: the interface IP to listen on
+    @param backlog: the length of the listen queue
+    @type backlog: C{str}
+
+    @param privateKey: The file name of a PEM format private key file.
+    @type privateKey: C{str}
+
+    @param certKey: The file name of a PEM format certificate file.
+    @type certKey: C{str}
+
+    @param sslmethod: The string name of an SSL method, based on the name of a
+        constant in C{OpenSSL.SSL}.  Must be one of: "SSLv23_METHOD",
+        "SSLv2_METHOD", "SSLv3_METHOD", "TLSv1_METHOD".
+    @type sslmethod: C{str}
+
+    @return: a 2-tuple of (args, kwargs), describing  the parameters to
+        L{IReactorSSL.listenSSL} (or, modulo argument 2, the factory, arguments
+        to L{SSL4ServerEndpoint}.
+    """
+    from twisted.internet import ssl
+    if certKey is None:
+        certKey = privateKey
+    kw = {}
+    if sslmethod is not None:
+        kw['sslmethod'] = getattr(ssl.SSL, sslmethod)
+    cf = ssl.DefaultOpenSSLContextFactory(privateKey, certKey, **kw)
+    return ((int(port), factory, cf),
+            {'interface': interface, 'backlog': int(backlog)})
+
+
+class _SystemdParser(object):
+    """
+    Stream server endpoint string parser for the I{systemd} endpoint type.
+
+    @ivar prefix: See L{IStreamClientEndpointStringParser.prefix}.
+
+    @ivar _sddaemon: A L{ListenFDs} instance used to translate an index into an
+        actual file descriptor.
+    """
+    implements(IPlugin, IStreamServerEndpointStringParser)
+
+    _sddaemon = ListenFDs.fromEnvironment()
+
+    prefix = "systemd"
+
+    def _parseServer(self, reactor, domain, index):
+        """
+        Internal parser function for L{_parseServer} to convert the string
+        arguments for a systemd server endpoint into structured arguments for
+        L{AdoptedStreamServerEndpoint}.
+
+        @param reactor: An L{IReactorSocket} provider.
+
+        @param domain: The domain (or address family) of the socket inherited
+            from systemd.  This is a string like C{"INET"} or C{"UNIX"}, ie the
+            name of an address family from the L{socket} module, without the
+            C{"AF_"} prefix.
+        @type domain: C{str}
+
+        @param index: An offset into the list of file descriptors inherited from
+            systemd.
+        @type index: C{str}
+
+        @return: A two-tuple of parsed positional arguments and parsed keyword
+            arguments (a tuple and a dictionary).  These can be used to
+            construct a L{AdoptedStreamServerEndpoint}.
+        """
+        index = int(index)
+        fileno = self._sddaemon.inheritedDescriptors()[index]
+        addressFamily = getattr(socket, 'AF_' + domain)
+        return AdoptedStreamServerEndpoint(reactor, fileno, addressFamily)
+
+
+    def parseStreamServer(self, reactor, *args, **kwargs):
+        # Delegate to another function with a sane signature.  This function has
+        # an insane signature to trick zope.interface into believing the
+        # interface is correctly implemented.
+        return self._parseServer(reactor, *args, **kwargs)
+
+
+
+_serverParsers = {"tcp": _parseTCP,
+                  "unix": _parseUNIX,
+                  "ssl": _parseSSL,
+                  }
+
+_OP, _STRING = range(2)
+
+def _tokenize(description):
+    """
+    Tokenize a strports string and yield each token.
+
+    @param description: a string as described by L{serverFromString} or
+        L{clientFromString}.
+
+    @return: an iterable of 2-tuples of (L{_OP} or L{_STRING}, string).  Tuples
+        starting with L{_OP} will contain a second element of either ':' (i.e.
+        'next parameter') or '=' (i.e. 'assign parameter value').  For example,
+        the string 'hello:greet\=ing=world' would result in a generator
+        yielding these values::
+
+            _STRING, 'hello'
+            _OP, ':'
+            _STRING, 'greet=ing'
+            _OP, '='
+            _STRING, 'world'
+    """
+    current = ''
+    ops = ':='
+    nextOps = {':': ':=', '=': ':'}
+    description = iter(description)
+    for n in description:
+        if n in ops:
+            yield _STRING, current
+            yield _OP, n
+            current = ''
+            ops = nextOps[n]
+        elif n == '\\':
+            current += description.next()
+        else:
+            current += n
+    yield _STRING, current
+
+
+
+def _parse(description):
+    """
+    Convert a description string into a list of positional and keyword
+    parameters, using logic vaguely like what Python does.
+
+    @param description: a string as described by L{serverFromString} or
+        L{clientFromString}.
+
+    @return: a 2-tuple of C{(args, kwargs)}, where 'args' is a list of all
+        ':'-separated C{str}s not containing an '=' and 'kwargs' is a map of
+        all C{str}s which do contain an '='.  For example, the result of
+        C{_parse('a:b:d=1:c')} would be C{(['a', 'b', 'c'], {'d': '1'})}.
+    """
+    args, kw = [], {}
+    def add(sofar):
+        if len(sofar) == 1:
+            args.append(sofar[0])
+        else:
+            kw[sofar[0]] = sofar[1]
+    sofar = ()
+    for (type, value) in _tokenize(description):
+        if type is _STRING:
+            sofar += (value,)
+        elif value == ':':
+            add(sofar)
+            sofar = ()
+    add(sofar)
+    return args, kw
+
+
+# Mappings from description "names" to endpoint constructors.
+_endpointServerFactories = {
+    'TCP': TCP4ServerEndpoint,
+    'SSL': SSL4ServerEndpoint,
+    'UNIX': UNIXServerEndpoint,
+    }
+
+_endpointClientFactories = {
+    'TCP': TCP4ClientEndpoint,
+    'SSL': SSL4ClientEndpoint,
+    'UNIX': UNIXClientEndpoint,
+    }
+
+
+_NO_DEFAULT = object()
+
+def _parseServer(description, factory, default=None):
+    """
+    Parse a stports description into a 2-tuple of arguments and keyword values.
+
+    @param description: A description in the format explained by
+        L{serverFromString}.
+    @type description: C{str}
+
+    @param factory: A 'factory' argument; this is left-over from
+        twisted.application.strports, it's not really used.
+    @type factory: L{IProtocolFactory} or L{None}
+
+    @param default: Deprecated argument, specifying the default parser mode to
+        use for unqualified description strings (those which do not have a ':'
+        and prefix).
+    @type default: C{str} or C{NoneType}
+
+    @return: a 3-tuple of (plugin or name, arguments, keyword arguments)
+    """
+    args, kw = _parse(description)
+    if not args or (len(args) == 1 and not kw):
+        deprecationMessage = (
+            "Unqualified strport description passed to 'service'."
+            "Use qualified endpoint descriptions; for example, 'tcp:%s'."
+            % (description,))
+        if default is None:
+            default = 'tcp'
+            warnings.warn(
+                deprecationMessage, category=DeprecationWarning, stacklevel=4)
+        elif default is _NO_DEFAULT:
+            raise ValueError(deprecationMessage)
+        # If the default has been otherwise specified, the user has already
+        # been warned.
+        args[0:0] = [default]
+    endpointType = args[0]
+    parser = _serverParsers.get(endpointType)
+    if parser is None:
+        for plugin in getPlugins(IStreamServerEndpointStringParser):
+            if plugin.prefix == endpointType:
+                return (plugin, args[1:], kw)
+        raise ValueError("Unknown endpoint type: '%s'" % (endpointType,))
+    return (endpointType.upper(),) + parser(factory, *args[1:], **kw)
+
+
+
+def _serverFromStringLegacy(reactor, description, default):
+    """
+    Underlying implementation of L{serverFromString} which avoids exposing the
+    deprecated 'default' argument to anything but L{strports.service}.
+    """
+    nameOrPlugin, args, kw = _parseServer(description, None, default)
+    if type(nameOrPlugin) is not str:
+        plugin = nameOrPlugin
+        return plugin.parseStreamServer(reactor, *args, **kw)
+    else:
+        name = nameOrPlugin
+    # Chop out the factory.
+    args = args[:1] + args[2:]
+    return _endpointServerFactories[name](reactor, *args, **kw)
+
+
+
+def serverFromString(reactor, description):
+    """
+    Construct a stream server endpoint from an endpoint description string.
+
+    The format for server endpoint descriptions is a simple string.  It is a
+    prefix naming the type of endpoint, then a colon, then the arguments for
+    that endpoint.
+
+    For example, you can call it like this to create an endpoint that will
+    listen on TCP port 80::
+
+        serverFromString(reactor, "tcp:80")
+
+    Additional arguments may be specified as keywords, separated with colons.
+    For example, you can specify the interface for a TCP server endpoint to
+    bind to like this::
+
+        serverFromString(reactor, "tcp:80:interface=127.0.0.1")
+
+    SSL server endpoints may be specified with the 'ssl' prefix, and the
+    private key and certificate files may be specified by the C{privateKey} and
+    C{certKey} arguments::
+
+        serverFromString(reactor, "ssl:443:privateKey=key.pem:certKey=crt.pem")
+
+    If a private key file name (C{privateKey}) isn't provided, a "server.pem"
+    file is assumed to exist which contains the private key. If the certificate
+    file name (C{certKey}) isn't provided, the private key file is assumed to
+    contain the certificate as well.
+
+    You may escape colons in arguments with a backslash, which you will need to
+    use if you want to specify a full pathname argument on Windows::
+
+        serverFromString(reactor,
+            "ssl:443:privateKey=C\\:/key.pem:certKey=C\\:/cert.pem")
+
+    finally, the 'unix' prefix may be used to specify a filesystem UNIX socket,
+    optionally with a 'mode' argument to specify the mode of the socket file
+    created by C{listen}::
+
+        serverFromString(reactor, "unix:/var/run/finger")
+        serverFromString(reactor, "unix:/var/run/finger:mode=660")
+
+    This function is also extensible; new endpoint types may be registered as
+    L{IStreamServerEndpointStringParser} plugins.  See that interface for more
+    information.
+
+    @param reactor: The server endpoint will be constructed with this reactor.
+
+    @param description: The strports description to parse.
+
+    @return: A new endpoint which can be used to listen with the parameters
+        given by by C{description}.
+
+    @rtype: L{IStreamServerEndpoint<twisted.internet.interfaces.IStreamServerEndpoint>}
+
+    @raise ValueError: when the 'description' string cannot be parsed.
+
+    @since: 10.2
+    """
+    return _serverFromStringLegacy(reactor, description, _NO_DEFAULT)
+
+
+
+def quoteStringArgument(argument):
+    """
+    Quote an argument to L{serverFromString} and L{clientFromString}.  Since
+    arguments are separated with colons and colons are escaped with
+    backslashes, some care is necessary if, for example, you have a pathname,
+    you may be tempted to interpolate into a string like this::
+
+        serverFromString("ssl:443:privateKey=%s" % (myPathName,))
+
+    This may appear to work, but will have portability issues (Windows
+    pathnames, for example).  Usually you should just construct the appropriate
+    endpoint type rather than interpolating strings, which in this case would
+    be L{SSL4ServerEndpoint}.  There are some use-cases where you may need to
+    generate such a string, though; for example, a tool to manipulate a
+    configuration file which has strports descriptions in it.  To be correct in
+    those cases, do this instead::
+
+        serverFromString("ssl:443:privateKey=%s" %
+                         (quoteStringArgument(myPathName),))
+
+    @param argument: The part of the endpoint description string you want to
+        pass through.
+
+    @type argument: C{str}
+
+    @return: The quoted argument.
+
+    @rtype: C{str}
+    """
+    return argument.replace('\\', '\\\\').replace(':', '\\:')
+
+
+
+def _parseClientTCP(*args, **kwargs):
+    """
+    Perform any argument value coercion necessary for TCP client parameters.
+
+    Valid positional arguments to this function are host and port.
+
+    Valid keyword arguments to this function are all L{IReactorTCP.connectTCP}
+    arguments.
+
+    @return: The coerced values as a C{dict}.
+    """
+
+    if len(args) == 2:
+        kwargs['port'] = int(args[1])
+        kwargs['host'] = args[0]
+    elif len(args) == 1:
+        if 'host' in kwargs:
+            kwargs['port'] = int(args[0])
+        else:
+            kwargs['host'] = args[0]
+
+    try:
+        kwargs['port'] = int(kwargs['port'])
+    except KeyError:
+        pass
+
+    try:
+        kwargs['timeout'] = int(kwargs['timeout'])
+    except KeyError:
+        pass
+    return kwargs
+
+
+
+def _loadCAsFromDir(directoryPath):
+    """
+    Load certificate-authority certificate objects in a given directory.
+
+    @param directoryPath: a L{FilePath} pointing at a directory to load .pem
+        files from.
+
+    @return: a C{list} of L{OpenSSL.crypto.X509} objects.
+    """
+    from twisted.internet import ssl
+
+    caCerts = {}
+    for child in directoryPath.children():
+        if not child.basename().split('.')[-1].lower() == 'pem':
+            continue
+        try:
+            data = child.getContent()
+        except IOError:
+            # Permission denied, corrupt disk, we don't care.
+            continue
+        try:
+            theCert = ssl.Certificate.loadPEM(data)
+        except ssl.SSL.Error:
+            # Duplicate certificate, invalid certificate, etc.  We don't care.
+            pass
+        else:
+            caCerts[theCert.digest()] = theCert.original
+    return caCerts.values()
+
+
+
+def _parseClientSSL(*args, **kwargs):
+    """
+    Perform any argument value coercion necessary for SSL client parameters.
+
+    Valid keyword arguments to this function are all L{IReactorSSL.connectSSL}
+    arguments except for C{contextFactory}.  Instead, C{certKey} (the path name
+    of the certificate file) C{privateKey} (the path name of the private key
+    associated with the certificate) are accepted and used to construct a
+    context factory.
+
+    Valid positional arguments to this function are host and port.
+
+    @param caCertsDir: The one parameter which is not part of
+        L{IReactorSSL.connectSSL}'s signature, this is a path name used to
+        construct a list of certificate authority certificates.  The directory
+        will be scanned for files ending in C{.pem}, all of which will be
+        considered valid certificate authorities for this connection.
+
+    @type caCertsDir: C{str}
+
+    @return: The coerced values as a C{dict}.
+    """
+    from twisted.internet import ssl
+    kwargs = _parseClientTCP(*args, **kwargs)
+    certKey = kwargs.pop('certKey', None)
+    privateKey = kwargs.pop('privateKey', None)
+    caCertsDir = kwargs.pop('caCertsDir', None)
+    if certKey is not None:
+        certx509 = ssl.Certificate.loadPEM(
+            FilePath(certKey).getContent()).original
+    else:
+        certx509 = None
+    if privateKey is not None:
+        privateKey = ssl.PrivateCertificate.loadPEM(
+            FilePath(privateKey).getContent()).privateKey.original
+    else:
+        privateKey = None
+    if caCertsDir is not None:
+        verify = True
+        caCerts = _loadCAsFromDir(FilePath(caCertsDir))
+    else:
+        verify = False
+        caCerts = None
+    kwargs['sslContextFactory'] = ssl.CertificateOptions(
+        method=ssl.SSL.SSLv23_METHOD,
+        certificate=certx509,
+        privateKey=privateKey,
+        verify=verify,
+        caCerts=caCerts
+    )
+    return kwargs
+
+
+
+def _parseClientUNIX(**kwargs):
+    """
+    Perform any argument value coercion necessary for UNIX client parameters.
+
+    Valid keyword arguments to this function are all L{IReactorUNIX.connectUNIX}
+    arguments except for C{checkPID}.  Instead, C{lockfile} is accepted and has
+    the same meaning.
+
+    @return: The coerced values as a C{dict}.
+    """
+    try:
+        kwargs['checkPID'] = bool(int(kwargs.pop('lockfile')))
+    except KeyError:
+        pass
+    try:
+        kwargs['timeout'] = int(kwargs['timeout'])
+    except KeyError:
+        pass
+    return kwargs
+
+_clientParsers = {
+    'TCP': _parseClientTCP,
+    'SSL': _parseClientSSL,
+    'UNIX': _parseClientUNIX,
+    }
+
+
+
+def clientFromString(reactor, description):
+    """
+    Construct a client endpoint from a description string.
+
+    Client description strings are much like server description strings,
+    although they take all of their arguments as keywords, aside from host and
+    port.
+
+    You can create a TCP client endpoint with the 'host' and 'port' arguments,
+    like so::
+
+        clientFromString(reactor, "tcp:host=www.example.com:port=80")
+
+    or, without specifying host and port keywords::
+
+        clientFromString(reactor, "tcp:www.example.com:80")
+
+    Or you can specify only one or the other, as in the following 2 examples::
+
+        clientFromString(reactor, "tcp:host=www.example.com:80")
+        clientFromString(reactor, "tcp:www.example.com:port=80")
+
+    or an SSL client endpoint with those arguments, plus the arguments used by
+    the server SSL, for a client certificate::
+
+        clientFromString(reactor, "ssl:web.example.com:443:"
+                                  "privateKey=foo.pem:certKey=foo.pem")
+
+    to specify your certificate trust roots, you can identify a directory with
+    PEM files in it with the C{caCertsDir} argument::
+
+        clientFromString(reactor, "ssl:host=web.example.com:port=443:"
+                                  "caCertsDir=/etc/ssl/certs")
+
+    This function is also extensible; new endpoint types may be registered as
+    L{IStreamClientEndpointStringParser} plugins.  See that interface for more
+    information.
+
+    @param reactor: The client endpoint will be constructed with this reactor.
+
+    @param description: The strports description to parse.
+
+    @return: A new endpoint which can be used to connect with the parameters
+        given by by C{description}.
+    @rtype: L{IStreamClientEndpoint<twisted.internet.interfaces.IStreamClientEndpoint>}
+
+    @since: 10.2
+    """
+    args, kwargs = _parse(description)
+    aname = args.pop(0)
+    name = aname.upper()
+    for plugin in getPlugins(IStreamClientEndpointStringParser):
+        if plugin.prefix.upper() == name:
+            return plugin.parseStreamClient(*args, **kwargs)
+    if name not in _clientParsers:
+        raise ValueError("Unknown endpoint type: %r" % (aname,))
+    kwargs = _clientParsers[name](*args, **kwargs)
+    return _endpointClientFactories[name](reactor, **kwargs)

Added: CalendarServer/branches/users/glyph/ipv6-client/twext/backport/internet/tcp.py
===================================================================
--- CalendarServer/branches/users/glyph/ipv6-client/twext/backport/internet/tcp.py	                        (rev 0)
+++ CalendarServer/branches/users/glyph/ipv6-client/twext/backport/internet/tcp.py	2012-04-13 18:43:14 UTC (rev 9055)
@@ -0,0 +1,1122 @@
+# -*- test-case-name: twisted.test.test_tcp -*-
+# Copyright (c) Twisted Matrix Laboratories.
+# See LICENSE for details.
+
+"""
+Various asynchronous TCP/IP classes.
+
+End users shouldn't use this module directly - use the reactor APIs instead.
+"""
+
+
+# System Imports
+import types
+import socket
+import sys
+import operator
+import struct
+
+from zope.interface import implements
+
+from twisted.python.runtime import platformType
+from twisted.python import versions, deprecate
+
+try:
+    # Try to get the memory BIO based startTLS implementation, available since
+    # pyOpenSSL 0.10
+    from twisted.internet._newtls import (
+        ConnectionMixin as _TLSConnectionMixin,
+        ClientMixin as _TLSClientMixin,
+        ServerMixin as _TLSServerMixin)
+except ImportError:
+    try:
+        # Try to get the socket BIO based startTLS implementation, available in
+        # all pyOpenSSL versions
+        from twisted.internet._oldtls import (
+            ConnectionMixin as _TLSConnectionMixin,
+            ClientMixin as _TLSClientMixin,
+            ServerMixin as _TLSServerMixin)
+    except ImportError:
+        # There is no version of startTLS available
+        class _TLSConnectionMixin(object):
+            TLS = False
+        class _TLSClientMixin(object):
+            pass
+        class _TLSServerMixin(object):
+            pass
+
+if platformType == 'win32':
+    # no such thing as WSAEPERM or error code 10001 according to winsock.h or MSDN
+    EPERM = object()
+    from errno import WSAEINVAL as EINVAL
+    from errno import WSAEWOULDBLOCK as EWOULDBLOCK
+    from errno import WSAEINPROGRESS as EINPROGRESS
+    from errno import WSAEALREADY as EALREADY
+    from errno import WSAECONNRESET as ECONNRESET
+    from errno import WSAEISCONN as EISCONN
+    from errno import WSAENOTCONN as ENOTCONN
+    from errno import WSAEINTR as EINTR
+    from errno import WSAENOBUFS as ENOBUFS
+    from errno import WSAEMFILE as EMFILE
+    # No such thing as WSAENFILE, either.
+    ENFILE = object()
+    # Nor ENOMEM
+    ENOMEM = object()
+    EAGAIN = EWOULDBLOCK
+    from errno import WSAECONNRESET as ECONNABORTED
+
+    from twisted.python.win32 import formatError as strerror
+else:
+    from errno import EPERM
+    from errno import EINVAL
+    from errno import EWOULDBLOCK
+    from errno import EINPROGRESS
+    from errno import EALREADY
+    from errno import ECONNRESET
+    from errno import EISCONN
+    from errno import ENOTCONN
+    from errno import EINTR
+    from errno import ENOBUFS
+    from errno import EMFILE
+    from errno import ENFILE
+    from errno import ENOMEM
+    from errno import EAGAIN
+    from errno import ECONNABORTED
+
+    from os import strerror
+
+
+from errno import errorcode
+
+# Twisted Imports
+from twisted.internet import base, address, fdesc
+from twisted.internet.task import deferLater
+from twisted.python import log, failure, reflect
+from twisted.python.util import unsignedID
+from twisted.internet.error import CannotListenError
+from twisted.internet import abstract, main, interfaces, error
+
+# Not all platforms have, or support, this flag.
+_AI_NUMERICSERV = getattr(socket, "AI_NUMERICSERV", 0)
+
+
+
+class _SocketCloser(object):
+    _socketShutdownMethod = 'shutdown'
+
+    def _closeSocket(self, orderly):
+        # The call to shutdown() before close() isn't really necessary, because
+        # we set FD_CLOEXEC now, which will ensure this is the only process
+        # holding the FD, thus ensuring close() really will shutdown the TCP
+        # socket. However, do it anyways, just to be safe.
+        skt = self.socket
+        try:
+            if orderly:
+                getattr(skt, self._socketShutdownMethod)(2)
+            else:
+                # Set SO_LINGER to 1,0 which, by convention, causes a
+                # connection reset to be sent when close is called,
+                # instead of the standard FIN shutdown sequence.
+                self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER,
+                                       struct.pack("ii", 1, 0))
+
+        except socket.error:
+            pass
+        try:
+            skt.close()
+        except socket.error:
+            pass
+
+
+
+class _AbortingMixin(object):
+    """
+    Common implementation of C{abortConnection}.
+
+    @ivar _aborting: Set to C{True} when C{abortConnection} is called.
+    @type _aborting: C{bool}
+    """
+    _aborting = False
+
+    def abortConnection(self):
+        """
+        Aborts the connection immediately, dropping any buffered data.
+
+        @since: 11.1
+        """
+        if self.disconnected or self._aborting:
+            return
+        self._aborting = True
+        self.stopReading()
+        self.stopWriting()
+        self.doRead = lambda *args, **kwargs: None
+        self.doWrite = lambda *args, **kwargs: None
+        self.reactor.callLater(0, self.connectionLost,
+                               failure.Failure(error.ConnectionAborted()))
+
+
+
+class Connection(_TLSConnectionMixin, abstract.FileDescriptor, _SocketCloser,
+                 _AbortingMixin):
+    """
+    Superclass of all socket-based FileDescriptors.
+
+    This is an abstract superclass of all objects which represent a TCP/IP
+    connection based socket.
+
+    @ivar logstr: prefix used when logging events related to this connection.
+    @type logstr: C{str}
+    """
+    implements(interfaces.ITCPTransport, interfaces.ISystemHandle)
+
+
+    def __init__(self, skt, protocol, reactor=None):
+        abstract.FileDescriptor.__init__(self, reactor=reactor)
+        self.socket = skt
+        self.socket.setblocking(0)
+        self.fileno = skt.fileno
+        self.protocol = protocol
+
+
+    def getHandle(self):
+        """Return the socket for this connection."""
+        return self.socket
+
+
+    def doRead(self):
+        """Calls self.protocol.dataReceived with all available data.
+
+        This reads up to self.bufferSize bytes of data from its socket, then
+        calls self.dataReceived(data) to process it.  If the connection is not
+        lost through an error in the physical recv(), this function will return
+        the result of the dataReceived call.
+        """
+        try:
+            data = self.socket.recv(self.bufferSize)
+        except socket.error, se:
+            if se.args[0] == EWOULDBLOCK:
+                return
+            else:
+                return main.CONNECTION_LOST
+        if not data:
+            return main.CONNECTION_DONE
+        rval = self.protocol.dataReceived(data)
+        if rval is not None:
+            offender = self.protocol.dataReceived
+            warningFormat = (
+                'Returning a value other than None from %(fqpn)s is '
+                'deprecated since %(version)s.')
+            warningString = deprecate.getDeprecationWarningString(
+                offender, versions.Version('Twisted', 11, 0, 0),
+                format=warningFormat)
+            deprecate.warnAboutFunction(offender, warningString)
+        return rval
+
+
+    def writeSomeData(self, data):
+        """
+        Write as much as possible of the given data to this TCP connection.
+
+        This sends up to C{self.SEND_LIMIT} bytes from C{data}.  If the
+        connection is lost, an exception is returned.  Otherwise, the number
+        of bytes successfully written is returned.
+        """
+        try:
+            # Limit length of buffer to try to send, because some OSes are too
+            # stupid to do so themselves (ahem windows)
+            return self.socket.send(buffer(data, 0, self.SEND_LIMIT))
+        except socket.error, se:
+            if se.args[0] == EINTR:
+                return self.writeSomeData(data)
+            elif se.args[0] in (EWOULDBLOCK, ENOBUFS):
+                return 0
+            else:
+                return main.CONNECTION_LOST
+
+
+    def _closeWriteConnection(self):
+        try:
+            getattr(self.socket, self._socketShutdownMethod)(1)
+        except socket.error:
+            pass
+        p = interfaces.IHalfCloseableProtocol(self.protocol, None)
+        if p:
+            try:
+                p.writeConnectionLost()
+            except:
+                f = failure.Failure()
+                log.err()
+                self.connectionLost(f)
+
+
+    def readConnectionLost(self, reason):
+        p = interfaces.IHalfCloseableProtocol(self.protocol, None)
+        if p:
+            try:
+                p.readConnectionLost()
+            except:
+                log.err()
+                self.connectionLost(failure.Failure())
+        else:
+            self.connectionLost(reason)
+
+
+
+    def connectionLost(self, reason):
+        """See abstract.FileDescriptor.connectionLost().
+        """
+        # Make sure we're not called twice, which can happen e.g. if
+        # abortConnection() is called from protocol's dataReceived and then
+        # code immediately after throws an exception that reaches the
+        # reactor. We can't rely on "disconnected" attribute for this check
+        # since twisted.internet._oldtls does evil things to it:
+        if not hasattr(self, "socket"):
+            return
+        abstract.FileDescriptor.connectionLost(self, reason)
+        self._closeSocket(not reason.check(error.ConnectionAborted))
+        protocol = self.protocol
+        del self.protocol
+        del self.socket
+        del self.fileno
+        protocol.connectionLost(reason)
+
+
+    logstr = "Uninitialized"
+
+    def logPrefix(self):
+        """Return the prefix to log with when I own the logging thread.
+        """
+        return self.logstr
+
+    def getTcpNoDelay(self):
+        return operator.truth(self.socket.getsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY))
+
+    def setTcpNoDelay(self, enabled):
+        self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, enabled)
+
+    def getTcpKeepAlive(self):
+        return operator.truth(self.socket.getsockopt(socket.SOL_SOCKET,
+                                                     socket.SO_KEEPALIVE))
+
+    def setTcpKeepAlive(self, enabled):
+        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, enabled)
+
+
+
+
+class _BaseBaseClient(object):
+    """
+    Code shared with other (non-POSIX) reactors for management of general
+    outgoing connections.
+
+    Requirements upon subclasses are documented as instance variables rather
+    than abstract methods, in order to avoid MRO confusion, since this base is
+    mixed in to unfortunately weird and distinctive multiple-inheritance
+    hierarchies and many of these attributes are provided by peer classes
+    rather than descendant classes in those hierarchies.
+
+    @ivar addressFamily: The address family constant (C{socket.AF_INET},
+        C{socket.AF_INET6}, C{socket.AF_UNIX}) of the underlying socket of this
+        client connection.
+    @type addressFamily: C{int}
+
+    @ivar socketType: The socket type constant (C{socket.SOCK_STREAM} or
+        C{socket.SOCK_DGRAM}) of the underlying socket.
+    @type socketType: C{int}
+
+    @ivar _requiresResolution: A flag indicating whether the address of this
+        client will require name resolution.  C{True} if the hostname of said
+        address indicates a name that must be resolved by hostname lookup,
+        C{False} if it indicates an IP address literal.
+    @type _requiresResolution: C{bool}
+
+    @cvar _commonConnection: Subclasses must provide this attribute, which
+        indicates the L{Connection}-alike class to invoke C{__init__} and
+        C{connectionLost} on.
+    @type _commonConnection: C{type}
+
+    @ivar _stopReadingAndWriting: Subclasses must implement in order to remove
+        this transport from its reactor's notifications in response to a
+        terminated connection attempt.
+    @type _stopReadingAndWriting: 0-argument callable returning C{None}
+
+    @ivar _closeSocket: Subclasses must implement in order to close the socket
+        in response to a terminated connection attempt.
+    @type _closeSocket: 1-argument callable; see L{_SocketCloser._closeSocket}
+
+    @ivar _collectSocketDetails: Clean up references to the attached socket in
+        its underlying OS resource (such as a file descriptor or file handle),
+        as part of post connection-failure cleanup.
+    @type _collectSocketDetails: 0-argument callable returning C{None}.
+
+    @ivar reactor: The class pointed to by C{_commonConnection} should set this
+        attribute in its constructor.
+    @type reactor: L{twisted.internet.interfaces.IReactorTime},
+        L{twisted.internet.interfaces.IReactorCore},
+        L{twisted.internet.interfaces.IReactorFDSet}
+    """
+
+    addressFamily = socket.AF_INET
+    socketType = socket.SOCK_STREAM
+
+    def _finishInit(self, whenDone, skt, error, reactor):
+        """
+        Called by subclasses to continue to the stage of initialization where
+        the socket connect attempt is made.
+
+        @param whenDone: A 0-argument callable to invoke once the connection is
+            set up.  This is C{None} if the connection could not be prepared
+            due to a previous error.
+
+        @param skt: The socket object to use to perform the connection.
+        @type skt: C{socket._socketobject}
+
+        @param error: The error to fail the connection with.
+
+        @param reactor: The reactor to use for this client.
+        @type reactor: L{twisted.internet.interfaces.IReactorTime}
+        """
+        if whenDone:
+            self._commonConnection.__init__(self, skt, None, reactor)
+            reactor.callLater(0, whenDone)
+        else:
+            reactor.callLater(0, self.failIfNotConnected, error)
+
+
+    def resolveAddress(self):
+        """
+        Resolve the name that was passed to this L{_BaseBaseClient}, if
+        necessary, and then move on to attempting the connection once an
+        address has been determined.  (The connection will be attempted
+        immediately within this function if either name resolution can be
+        synchronous or the address was an IP address literal.)
+
+        @note: You don't want to call this method from outside, as it won't do
+            anything useful; it's just part of the connection bootstrapping
+            process.  Also, although this method is on L{_BaseBaseClient} for
+            historical reasons, it's not used anywhere except for L{Client}
+            itself.
+
+        @return: C{None}
+        """
+        if self._requiresResolution:
+            d = self.reactor.resolve(self.addr[0])
+            d.addCallback(lambda n: (n,) + self.addr[1:])
+            d.addCallbacks(self._setRealAddress, self.failIfNotConnected)
+        else:
+            self._setRealAddress(self.addr)
+
+
+    def _setRealAddress(self, address):
+        """
+        Set the resolved address of this L{_BaseBaseClient} and initiate the
+        connection attempt.
+
+        @param address: Depending on whether this is an IPv4 or IPv6 connection
+            attempt, a 2-tuple of C{(host, port)} or a 4-tuple of C{(host,
+            port, flow, scope)}.  At this point it is a fully resolved address,
+            and the 'host' portion will always be an IP address, not a DNS
+            name.
+        """
+        self.realAddress = address
+        self.doConnect()
+
+
+    def failIfNotConnected(self, err):
+        """
+        Generic method called when the attemps to connect failed. It basically
+        cleans everything it can: call connectionFailed, stop read and write,
+        delete socket related members.
+        """
+        if (self.connected or self.disconnected or
+            not hasattr(self, "connector")):
+            return
+
+        self._stopReadingAndWriting()
+        try:
+            self._closeSocket(True)
+        except AttributeError:
+            pass
+        else:
+            self._collectSocketDetails()
+        self.connector.connectionFailed(failure.Failure(err))
+        del self.connector
+
+
+    def stopConnecting(self):
+        """
+        If a connection attempt is still outstanding (i.e.  no connection is
+        yet established), immediately stop attempting to connect.
+        """
+        self.failIfNotConnected(error.UserError())
+
+
+    def connectionLost(self, reason):
+        """
+        Invoked by lower-level logic when it's time to clean the socket up.
+        Depending on the state of the connection, either inform the attached
+        L{Connector} that the connection attempt has failed, or inform the
+        connected L{IProtocol} that the established connection has been lost.
+
+        @param reason: the reason that the connection was terminated
+        @type reason: L{Failure}
+        """
+        if not self.connected:
+            self.failIfNotConnected(error.ConnectError(string=reason))
+        else:
+            self._commonConnection.connectionLost(self, reason)
+            self.connector.connectionLost(reason)
+
+
+
+class BaseClient(_BaseBaseClient, _TLSClientMixin, Connection):
+    """
+    A base class for client TCP (and similiar) sockets.
+
+    @ivar realAddress: The address object that will be used for socket.connect;
+        this address is an address tuple (the number of elements dependent upon
+        the address family) which does not contain any names which need to be
+        resolved.
+    @type realAddress: C{tuple}
+
+    @ivar _base: L{Connection}, which is the base class of this class which has
+        all of the useful file descriptor methods.  This is used by
+        L{_TLSServerMixin} to call the right methods to directly manipulate the
+        transport, as is necessary for writing TLS-encrypted bytes (whereas
+        those methods on L{Server} will go through another layer of TLS if it
+        has been enabled).
+    """
+
+    _base = Connection
+    _commonConnection = Connection
+
+    def _stopReadingAndWriting(self):
+        """
+        Implement the POSIX-ish (i.e.
+        L{twisted.internet.interfaces.IReactorFDSet}) method of detaching this
+        socket from the reactor for L{_BaseBaseClient}.
+        """
+        if hasattr(self, "reactor"):
+            # this doesn't happen if we failed in __init__
+            self.stopReading()
+            self.stopWriting()
+
+
+    def _collectSocketDetails(self):
+        """
+        Clean up references to the socket and its file descriptor.
+
+        @see: L{_BaseBaseClient}
+        """
+        del self.socket, self.fileno
+
+
+    def createInternetSocket(self):
+        """(internal) Create a non-blocking socket using
+        self.addressFamily, self.socketType.
+        """
+        s = socket.socket(self.addressFamily, self.socketType)
+        s.setblocking(0)
+        fdesc._setCloseOnExec(s.fileno())
+        return s
+
+
+    def doConnect(self):
+        """
+        Initiate the outgoing connection attempt.
+
+        @note: Applications do not need to call this method; it will be invoked
+            internally as part of L{IReactorTCP.connectTCP}.
+        """
+        self.doWrite = self.doConnect
+        self.doRead = self.doConnect
+        if not hasattr(self, "connector"):
+            # this happens when connection failed but doConnect
+            # was scheduled via a callLater in self._finishInit
+            return
+
+        err = self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR)
+        if err:
+            self.failIfNotConnected(error.getConnectError((err, strerror(err))))
+            return
+
+        # doConnect gets called twice.  The first time we actually need to
+        # start the connection attempt.  The second time we don't really
+        # want to (SO_ERROR above will have taken care of any errors, and if
+        # it reported none, the mere fact that doConnect was called again is
+        # sufficient to indicate that the connection has succeeded), but it
+        # is not /particularly/ detrimental to do so.  This should get
+        # cleaned up some day, though.
+        try:
+            connectResult = self.socket.connect_ex(self.realAddress)
+        except socket.error, se:
+            connectResult = se.args[0]
+        if connectResult:
+            if connectResult == EISCONN:
+                pass
+            # on Windows EINVAL means sometimes that we should keep trying:
+            # http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winsock/winsock/connect_2.asp
+            elif ((connectResult in (EWOULDBLOCK, EINPROGRESS, EALREADY)) or
+                  (connectResult == EINVAL and platformType == "win32")):
+                self.startReading()
+                self.startWriting()
+                return
+            else:
+                self.failIfNotConnected(error.getConnectError((connectResult, strerror(connectResult))))
+                return
+
+        # If I have reached this point without raising or returning, that means
+        # that the socket is connected.
+        del self.doWrite
+        del self.doRead
+        # we first stop and then start, to reset any references to the old doRead
+        self.stopReading()
+        self.stopWriting()
+        self._connectDone()
+
+
+    def _connectDone(self):
+        """
+        This is a hook for when a connection attempt has succeeded.
+
+        Here, we build the protocol from the
+        L{twisted.internet.protocol.ClientFactory} that was passed in, compute
+        a log string, begin reading so as to send traffic to the newly built
+        protocol, and finally hook up the protocol itself.
+
+        This hook is overridden by L{ssl.Client} to initiate the TLS protocol.
+        """
+        self.protocol = self.connector.buildProtocol(self.getPeer())
+        self.connected = 1
+        logPrefix = self._getLogPrefix(self.protocol)
+        self.logstr = "%s,client" % logPrefix
+        self.startReading()
+        self.protocol.makeConnection(self)
+
+
+
+_NUMERIC_ONLY = socket.AI_NUMERICHOST | _AI_NUMERICSERV
+
+def _resolveIPv6(ip, port):
+    """
+    Resolve an IPv6 literal into an IPv6 address.
+
+    This is necessary to resolve any embedded scope identifiers to the relevant
+    C{sin6_scope_id} for use with C{socket.connect()}, C{socket.listen()}, or
+    C{socket.bind()}; see U{RFC 3493 <https://tools.ietf.org/html/rfc3493>} for
+    more information.
+
+    @param ip: An IPv6 address literal.
+    @type ip: C{str}
+
+    @param port: A port number.
+    @type port: C{int}
+
+    @return: a 4-tuple of C{(host, port, flow, scope)}, suitable for use as an
+        IPv6 address.
+
+    @raise socket.gaierror: if either the IP or port is not numeric as it
+        should be.
+    """
+    return socket.getaddrinfo(ip, port, 0, 0, 0, _NUMERIC_ONLY)[0][4]
+
+
+
+class _BaseTCPClient(object):
+    """
+    Code shared with other (non-POSIX) reactors for management of outgoing TCP
+    connections (both TCPv4 and TCPv6).
+
+    @note: In order to be functional, this class must be mixed into the same
+        hierarchy as L{_BaseBaseClient}.  It would subclass L{_BaseBaseClient}
+        directly, but the class hierarchy here is divided in strange ways out
+        of the need to share code along multiple axes; specifically, with the
+        IOCP reactor and also with UNIX clients in other reactors.
+
+    @ivar _addressType: The Twisted _IPAddress implementation for this client
+    @type _addressType: L{IPv4Address} or L{IPv6Address}
+
+    @ivar connector: The L{Connector} which is driving this L{_BaseTCPClient}'s
+        connection attempt.
+
+    @ivar addr: The address that this socket will be connecting to.
+    @type addr: If IPv4, a 2-C{tuple} of C{(str host, int port)}.  If IPv6, a
+        4-C{tuple} of (C{str host, int port, int ignored, int scope}).
+
+    @ivar createInternetSocket: Subclasses must implement this as a method to
+        create a python socket object of the appropriate address family and
+        socket type.
+    @type createInternetSocket: 0-argument callable returning
+        C{socket._socketobject}.
+    """
+
+    _addressType = address.IPv4Address
+
+    def __init__(self, host, port, bindAddress, connector, reactor=None):
+        # BaseClient.__init__ is invoked later
+        self.connector = connector
+        self.addr = (host, port)
+
+        whenDone = self.resolveAddress
+        err = None
+        skt = None
+
+        if abstract.isIPAddress(host):
+            self._requiresResolution = False
+        elif abstract.isIPv6Address(host):
+            self._requiresResolution = False
+            self.addr = _resolveIPv6(host, port)
+            self.addressFamily = socket.AF_INET6
+            self._addressType = address.IPv6Address
+        else:
+            self._requiresResolution = True
+        try:
+            skt = self.createInternetSocket()
+        except socket.error, se:
+            err = error.ConnectBindError(se.args[0], se.args[1])
+            whenDone = None
+        if whenDone and bindAddress is not None:
+            try:
+                if abstract.isIPv6Address(bindAddress[0]):
+                    bindinfo = _resolveIPv6(*bindAddress)
+                else:
+                    bindinfo = bindAddress
+                skt.bind(bindinfo)
+            except socket.error, se:
+                err = error.ConnectBindError(se.args[0], se.args[1])
+                whenDone = None
+        self._finishInit(whenDone, skt, err, reactor)
+
+
+    def getHost(self):
+        """
+        Returns an L{IPv4Address} or L{IPv6Address}.
+
+        This indicates the address from which I am connecting.
+        """
+        return self._addressType('TCP', *self.socket.getsockname()[:2])
+
+
+    def getPeer(self):
+        """
+        Returns an L{IPv4Address} or L{IPv6Address}.
+
+        This indicates the address that I am connected to.
+        """
+        # an ipv6 realAddress has more than two elements, but the IPv6Address
+        # constructor still only takes two.
+        return self._addressType('TCP', *self.realAddress[:2])
+
+
+    def __repr__(self):
+        s = '<%s to %s at %x>' % (self.__class__, self.addr, unsignedID(self))
+        return s
+
+
+
+class Client(_BaseTCPClient, BaseClient):
+    """
+    A transport for a TCP protocol; either TCPv4 or TCPv6.
+
+    Do not create these directly; use L{IReactorTCP.connectTCP}.
+    """
+
+
+
+class Server(_TLSServerMixin, Connection):
+    """
+    Serverside socket-stream connection class.
+
+    This is a serverside network connection transport; a socket which came from
+    an accept() on a server.
+
+    @ivar _base: L{Connection}, which is the base class of this class which has
+        all of the useful file descriptor methods.  This is used by
+        L{_TLSServerMixin} to call the right methods to directly manipulate the
+        transport, as is necessary for writing TLS-encrypted bytes (whereas
+        those methods on L{Server} will go through another layer of TLS if it
+        has been enabled).
+    """
+    _base = Connection
+
+    _addressType = address.IPv4Address
+
+    def __init__(self, sock, protocol, client, server, sessionno, reactor):
+        """
+        Server(sock, protocol, client, server, sessionno)
+
+        Initialize it with a socket, a protocol, a descriptor for my peer (a
+        tuple of host, port describing the other end of the connection), an
+        instance of Port, and a session number.
+        """
+        Connection.__init__(self, sock, protocol, reactor)
+        if len(client) != 2:
+            self._addressType = address.IPv6Address
+        self.server = server
+        self.client = client
+        self.sessionno = sessionno
+        self.hostname = client[0]
+
+        logPrefix = self._getLogPrefix(self.protocol)
+        self.logstr = "%s,%s,%s" % (logPrefix,
+                                    sessionno,
+                                    self.hostname)
+        self.repstr = "<%s #%s on %s>" % (self.protocol.__class__.__name__,
+                                          self.sessionno,
+                                          self.server._realPortNumber)
+        self.startReading()
+        self.connected = 1
+
+    def __repr__(self):
+        """A string representation of this connection.
+        """
+        return self.repstr
+
+
+    def getHost(self):
+        """
+        Returns an L{IPv4Address} or L{IPv6Address}.
+
+        This indicates the server's address.
+        """
+        host, port = self.socket.getsockname()[:2]
+        return self._addressType('TCP', host, port)
+
+
+    def getPeer(self):
+        """
+        Returns an L{IPv4Address} or L{IPv6Address}.
+
+        This indicates the client's address.
+        """
+        return self._addressType('TCP', *self.client[:2])
+
+
+
+class Port(base.BasePort, _SocketCloser):
+    """
+    A TCP server port, listening for connections.
+
+    When a connection is accepted, this will call a factory's buildProtocol
+    with the incoming address as an argument, according to the specification
+    described in L{twisted.internet.interfaces.IProtocolFactory}.
+
+    If you wish to change the sort of transport that will be used, the
+    C{transport} attribute will be called with the signature expected for
+    C{Server.__init__}, so it can be replaced.
+
+    @ivar deferred: a deferred created when L{stopListening} is called, and
+        that will fire when connection is lost. This is not to be used it
+        directly: prefer the deferred returned by L{stopListening} instead.
+    @type deferred: L{defer.Deferred}
+
+    @ivar disconnecting: flag indicating that the L{stopListening} method has
+        been called and that no connections should be accepted anymore.
+    @type disconnecting: C{bool}
+
+    @ivar connected: flag set once the listen has successfully been called on
+        the socket.
+    @type connected: C{bool}
+
+    @ivar _type: A string describing the connections which will be created by
+        this port.  Normally this is C{"TCP"}, since this is a TCP port, but
+        when the TLS implementation re-uses this class it overrides the value
+        with C{"TLS"}.  Only used for logging.
+
+    @ivar _preexistingSocket: If not C{None}, a L{socket.socket} instance which
+        was created and initialized outside of the reactor and will be used to
+        listen for connections (instead of a new socket being created by this
+        L{Port}).
+    """
+
+    implements(interfaces.IListeningPort)
+
+    socketType = socket.SOCK_STREAM
+
+    transport = Server
+    sessionno = 0
+    interface = ''
+    backlog = 50
+
+    _type = 'TCP'
+
+    # Actual port number being listened on, only set to a non-None
+    # value when we are actually listening.
+    _realPortNumber = None
+
+    # An externally initialized socket that we will use, rather than creating
+    # our own.
+    _preexistingSocket = None
+
+    addressFamily = socket.AF_INET
+    _addressType = address.IPv4Address
+
+    def __init__(self, port, factory, backlog=50, interface='', reactor=None):
+        """Initialize with a numeric port to listen on.
+        """
+        base.BasePort.__init__(self, reactor=reactor)
+        self.port = port
+        self.factory = factory
+        self.backlog = backlog
+        if abstract.isIPv6Address(interface):
+            self.addressFamily = socket.AF_INET6
+            self._addressType = address.IPv6Address
+        self.interface = interface
+
+
+    @classmethod
+    def _fromListeningDescriptor(cls, reactor, fd, addressFamily, factory):
+        """
+        Create a new L{Port} based on an existing listening I{SOCK_STREAM}
+        I{AF_INET} socket.
+
+        Arguments are the same as to L{Port.__init__}, except where noted.
+
+        @param fd: An integer file descriptor associated with a listening
+            socket.  The socket must be in non-blocking mode.  Any additional
+            attributes desired, such as I{FD_CLOEXEC}, must also be set already.
+
+        @param addressFamily: The address family (sometimes called I{domain}) of
+            the existing socket.  For example, L{socket.AF_INET}.
+
+        @return: A new instance of C{cls} wrapping the socket given by C{fd}.
+        """
+        port = socket.fromfd(fd, addressFamily, cls.socketType)
+        interface = port.getsockname()[0]
+        self = cls(None, factory, None, interface, reactor)
+        self._preexistingSocket = port
+        return self
+
+
+    def __repr__(self):
+        if self._realPortNumber is not None:
+            return "<%s of %s on %s>" % (self.__class__,
+                self.factory.__class__, self._realPortNumber)
+        else:
+            return "<%s of %s (not listening)>" % (self.__class__, self.factory.__class__)
+
+    def createInternetSocket(self):
+        s = base.BasePort.createInternetSocket(self)
+        if platformType == "posix" and sys.platform != "cygwin":
+            s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+        return s
+
+
+    def startListening(self):
+        """Create and bind my socket, and begin listening on it.
+
+        This is called on unserialization, and must be called after creating a
+        server to begin listening on the specified port.
+        """
+        if self._preexistingSocket is None:
+            # Create a new socket and make it listen
+            try:
+                skt = self.createInternetSocket()
+                if self.addressFamily == socket.AF_INET6:
+                    addr = _resolveIPv6(self.interface, self.port)
+                else:
+                    addr = (self.interface, self.port)
+                skt.bind(addr)
+            except socket.error, le:
+                raise CannotListenError, (self.interface, self.port, le)
+            skt.listen(self.backlog)
+        else:
+            # Re-use the externally specified socket
+            skt = self._preexistingSocket
+            self._preexistingSocket = None
+
+        # Make sure that if we listened on port 0, we update that to
+        # reflect what the OS actually assigned us.
+        self._realPortNumber = skt.getsockname()[1]
+
+        log.msg("%s starting on %s" % (
+                self._getLogPrefix(self.factory), self._realPortNumber))
+
+        # The order of the next 5 lines is kind of bizarre.  If no one
+        # can explain it, perhaps we should re-arrange them.
+        self.factory.doStart()
+        self.connected = True
+        self.socket = skt
+        self.fileno = self.socket.fileno
+        self.numberAccepts = 100
+
+        self.startReading()
+
+
+    def _buildAddr(self, address):
+        host, port = address[:2]
+        return self._addressType('TCP', host, port)
+
+
+    def doRead(self):
+        """Called when my socket is ready for reading.
+
+        This accepts a connection and calls self.protocol() to handle the
+        wire-level protocol.
+        """
+        try:
+            if platformType == "posix":
+                numAccepts = self.numberAccepts
+            else:
+                # win32 event loop breaks if we do more than one accept()
+                # in an iteration of the event loop.
+                numAccepts = 1
+            for i in range(numAccepts):
+                # we need this so we can deal with a factory's buildProtocol
+                # calling our loseConnection
+                if self.disconnecting:
+                    return
+                try:
+                    skt, addr = self.socket.accept()
+                except socket.error, e:
+                    if e.args[0] in (EWOULDBLOCK, EAGAIN):
+                        self.numberAccepts = i
+                        break
+                    elif e.args[0] == EPERM:
+                        # Netfilter on Linux may have rejected the
+                        # connection, but we get told to try to accept()
+                        # anyway.
+                        continue
+                    elif e.args[0] in (EMFILE, ENOBUFS, ENFILE, ENOMEM, ECONNABORTED):
+
+                        # Linux gives EMFILE when a process is not allowed
+                        # to allocate any more file descriptors.  *BSD and
+                        # Win32 give (WSA)ENOBUFS.  Linux can also give
+                        # ENFILE if the system is out of inodes, or ENOMEM
+                        # if there is insufficient memory to allocate a new
+                        # dentry.  ECONNABORTED is documented as possible on
+                        # both Linux and Windows, but it is not clear
+                        # whether there are actually any circumstances under
+                        # which it can happen (one might expect it to be
+                        # possible if a client sends a FIN or RST after the
+                        # server sends a SYN|ACK but before application code
+                        # calls accept(2), however at least on Linux this
+                        # _seems_ to be short-circuited by syncookies.
+
+                        log.msg("Could not accept new connection (%s)" % (
+                            errorcode[e.args[0]],))
+                        break
+                    raise
+
+                fdesc._setCloseOnExec(skt.fileno())
+                protocol = self.factory.buildProtocol(self._buildAddr(addr))
+                if protocol is None:
+                    skt.close()
+                    continue
+                s = self.sessionno
+                self.sessionno = s+1
+                transport = self.transport(skt, protocol, addr, self, s, self.reactor)
+                protocol.makeConnection(transport)
+            else:
+                self.numberAccepts = self.numberAccepts+20
+        except:
+            # Note that in TLS mode, this will possibly catch SSL.Errors
+            # raised by self.socket.accept()
+            #
+            # There is no "except SSL.Error:" above because SSL may be
+            # None if there is no SSL support.  In any case, all the
+            # "except SSL.Error:" suite would probably do is log.deferr()
+            # and return, so handling it here works just as well.
+            log.deferr()
+
+    def loseConnection(self, connDone=failure.Failure(main.CONNECTION_DONE)):
+        """
+        Stop accepting connections on this port.
+
+        This will shut down the socket and call self.connectionLost().  It
+        returns a deferred which will fire successfully when the port is
+        actually closed, or with a failure if an error occurs shutting down.
+        """
+        self.disconnecting = True
+        self.stopReading()
+        if self.connected:
+            self.deferred = deferLater(
+                self.reactor, 0, self.connectionLost, connDone)
+            return self.deferred
+
+    stopListening = loseConnection
+
+    def _logConnectionLostMsg(self):
+        """
+        Log message for closing port
+        """
+        log.msg('(%s Port %s Closed)' % (self._type, self._realPortNumber))
+
+
+    def connectionLost(self, reason):
+        """
+        Cleans up the socket.
+        """
+        self._logConnectionLostMsg()
+        self._realPortNumber = None
+
+        base.BasePort.connectionLost(self, reason)
+        self.connected = False
+        self._closeSocket(True)
+        del self.socket
+        del self.fileno
+
+        try:
+            self.factory.doStop()
+        finally:
+            self.disconnecting = False
+
+
+    def logPrefix(self):
+        """Returns the name of my class, to prefix log entries with.
+        """
+        return reflect.qual(self.factory.__class__)
+
+
+    def getHost(self):
+        """
+        Return an L{IPv4Address} or L{IPv6Address} indicating the listening
+        address of this port.
+        """
+        host, port = self.socket.getsockname()[:2]
+        return self._addressType('TCP', host, port)
+
+
+
+class Connector(base.BaseConnector):
+    """
+    A L{Connector} provides of L{twisted.internet.interfaces.IConnector} for
+    all POSIX-style reactors.
+
+    @ivar _addressType: the type returned by L{Connector.getDestination}.
+        Either L{IPv4Address} or L{IPv6Address}, depending on the type of
+        address.
+    @type _addressType: C{type}
+    """
+    _addressType = address.IPv4Address
+
+    def __init__(self, host, port, factory, timeout, bindAddress, reactor=None):
+        if isinstance(port, types.StringTypes):
+            try:
+                port = socket.getservbyname(port, 'tcp')
+            except socket.error, e:
+                raise error.ServiceNameUnknownError(string="%s (%r)" % (e, port))
+        self.host, self.port = host, port
+        if abstract.isIPv6Address(host):
+            self._addressType = address.IPv6Address
+        self.bindAddress = bindAddress
+        base.BaseConnector.__init__(self, factory, timeout, reactor)
+
+
+    def _makeTransport(self):
+        """
+        Create a L{Client} bound to this L{Connector}.
+
+        @return: a new L{Client}
+        @rtype: L{Client}
+        """
+        return Client(self.host, self.port, self.bindAddress, self, self.reactor)
+
+
+    def getDestination(self):
+        """
+        @see: L{twisted.internet.interfaces.IConnector.getDestination}.
+        """
+        return self._addressType('TCP', self.host, self.port)
+
+

Modified: CalendarServer/branches/users/glyph/ipv6-client/twext/patches.py
===================================================================
--- CalendarServer/branches/users/glyph/ipv6-client/twext/patches.py	2012-04-13 18:40:22 UTC (rev 9054)
+++ CalendarServer/branches/users/glyph/ipv6-client/twext/patches.py	2012-04-13 18:43:14 UTC (rev 9055)
@@ -1,5 +1,5 @@
 ##
-# Copyright (c) 2005-2010 Apple Inc. All rights reserved.
+# Copyright (c) 2005-2012 Apple Inc. All rights reserved.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -20,6 +20,65 @@
 
 __all__ = []
 
+import sys
+
+from twisted import version
+from twisted.python.versions import Version
+from twisted.python.modules import getModule
+
+def _hasIPv6ClientSupport():
+    """
+    Does the loaded version of Twisted have IPv6 client support?
+    """
+    lastVersionWithoutIPv6Clients = Version("twisted", 12, 0, 0)
+    if version > lastVersionWithoutIPv6Clients:
+        return True
+    elif version == lastVersionWithoutIPv6Clients:
+        # It could be a snapshot of trunk or a branch with this bug fixed. Don't
+        # load the module, though, as that would be a bunch of unnecessary work.
+        return "_resolveIPv6" in (getModule("twisted.internet.tcp")
+                                  .filePath.getContent())
+    else:
+        return False
+
+
+
+def _addBackports():
+    """
+    We currently require 2 backported bugfixes from a future release of Twisted,
+    for IPv6 support:
+
+        - U{IPv6 client support <http://tm.tl/5085>}
+
+        - U{TCP endpoint cancellation <http://tm.tl/4710>}
+
+    This function will activate those backports.  (Note it must be run before
+    any of the modules in question are imported or it will raise an exception.)
+
+    This function, L{_hasIPv6ClientSupport}, and all the associated backports
+    (i.e., all of C{twext/backport}) should be removed upon upgrading our
+    minimum required Twisted version.
+    """
+    from twext.backport import internet as bpinternet
+    from twisted import internet
+    internet.__path__[:] = bpinternet.__path__ + internet.__path__
+
+    # Make sure none of the backports are loaded yet.
+    backports = getModule("twext.backport.internet")
+    for submod in backports.iterModules():
+        subname = submod.name.split(".")[-1]
+        tiname = 'twisted.internet.' + subname
+        if tiname in sys.modules:
+            raise RuntimeError(
+                tiname + "already loaded, cannot load required backport")
+
+
+
+if not _hasIPv6ClientSupport():
+    _addBackports()
+
+
+
 from twisted.mail.imap4 import Command
 
 Command._1_RESPONSES += tuple(['BYE'])
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20120413/6364222d/attachment-0001.html>


More information about the calendarserver-changes mailing list