Index: third_party/twisted_8_1/twisted/internet/tcp.py |
diff --git a/third_party/twisted_8_1/twisted/internet/tcp.py b/third_party/twisted_8_1/twisted/internet/tcp.py |
deleted file mode 100644 |
index 29852aef5da33b69a3fdfa79626ebe7043ff8e17..0000000000000000000000000000000000000000 |
--- a/third_party/twisted_8_1/twisted/internet/tcp.py |
+++ /dev/null |
@@ -1,894 +0,0 @@ |
-# -*- test-case-name: twisted.test.test_tcp -*- |
-# Copyright (c) 2001-2007 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. |
- |
-Maintainer: U{Itamar Shtull-Trauring<mailto:twisted@itamarst.org>} |
-""" |
- |
- |
-# System Imports |
-import os |
-import types |
-import socket |
-import sys |
-import operator |
-import warnings |
- |
-try: |
- import fcntl |
-except ImportError: |
- fcntl = None |
-from zope.interface import implements, classImplements |
- |
-try: |
- from OpenSSL import SSL |
-except ImportError: |
- SSL = None |
- |
-from twisted.python.runtime import platformType |
- |
- |
-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 defer, base, address |
-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 |
- |
- |
- |
-class _SocketCloser: |
- _socketShutdownMethod = 'shutdown' |
- |
- def _closeSocket(self): |
- # socket.close() doesn't *really* close if there's another reference |
- # to it in the TCP/IP stack, e.g. if it was was inherited by a |
- # subprocess. And we really do want to close the connection. So we |
- # use shutdown() instead, and then close() in order to release the |
- # filedescriptor. |
- skt = self.socket |
- try: |
- getattr(skt, self._socketShutdownMethod)(2) |
- except socket.error: |
- pass |
- try: |
- skt.close() |
- except socket.error: |
- pass |
- |
-class _TLSMixin: |
- _socketShutdownMethod = 'sock_shutdown' |
- |
- writeBlockedOnRead = 0 |
- readBlockedOnWrite = 0 |
- _userWantRead = _userWantWrite = True |
- |
- def getPeerCertificate(self): |
- return self.socket.get_peer_certificate() |
- |
- def doRead(self): |
- if self.writeBlockedOnRead: |
- self.writeBlockedOnRead = 0 |
- self._resetReadWrite() |
- try: |
- return Connection.doRead(self) |
- except SSL.ZeroReturnError: |
- return main.CONNECTION_DONE |
- except SSL.WantReadError: |
- return |
- except SSL.WantWriteError: |
- self.readBlockedOnWrite = 1 |
- Connection.startWriting(self) |
- Connection.stopReading(self) |
- return |
- except SSL.SysCallError, (retval, desc): |
- if ((retval == -1 and desc == 'Unexpected EOF') |
- or retval > 0): |
- return main.CONNECTION_LOST |
- log.err() |
- return main.CONNECTION_LOST |
- except SSL.Error, e: |
- return e |
- |
- def doWrite(self): |
- # Retry disconnecting |
- if self.disconnected: |
- return self._postLoseConnection() |
- if self._writeDisconnected: |
- return self._closeWriteConnection() |
- |
- if self.readBlockedOnWrite: |
- self.readBlockedOnWrite = 0 |
- self._resetReadWrite() |
- return Connection.doWrite(self) |
- |
- def writeSomeData(self, data): |
- try: |
- return Connection.writeSomeData(self, data) |
- except SSL.WantWriteError: |
- return 0 |
- except SSL.WantReadError: |
- self.writeBlockedOnRead = 1 |
- Connection.stopWriting(self) |
- Connection.startReading(self) |
- return 0 |
- except SSL.ZeroReturnError: |
- return main.CONNECTION_LOST |
- except SSL.SysCallError, e: |
- if e[0] == -1 and data == "": |
- # errors when writing empty strings are expected |
- # and can be ignored |
- return 0 |
- else: |
- return main.CONNECTION_LOST |
- except SSL.Error, e: |
- return e |
- |
- def _postLoseConnection(self): |
- """Gets called after loseConnection(), after buffered data is sent. |
- |
- We try to send an SSL shutdown alert, but if it doesn't work, retry |
- when the socket is writable. |
- """ |
- self.disconnected=1 |
- if hasattr(self.socket, 'set_shutdown'): |
- self.socket.set_shutdown(SSL.RECEIVED_SHUTDOWN) |
- return self._sendCloseAlert() |
- |
- _first=False |
- def _sendCloseAlert(self): |
- # Okay, *THIS* is a bit complicated. |
- |
- # Basically, the issue is, OpenSSL seems to not actually return |
- # errors from SSL_shutdown. Therefore, the only way to |
- # determine if the close notification has been sent is by |
- # SSL_shutdown returning "done". However, it will not claim it's |
- # done until it's both sent *and* received a shutdown notification. |
- |
- # I don't actually want to wait for a received shutdown |
- # notification, though, so, I have to set RECEIVED_SHUTDOWN |
- # before calling shutdown. Then, it'll return True once it's |
- # *SENT* the shutdown. |
- |
- # However, RECEIVED_SHUTDOWN can't be left set, because then |
- # reads will fail, breaking half close. |
- |
- # Also, since shutdown doesn't report errors, an empty write call is |
- # done first, to try to detect if the connection has gone away. |
- # (*NOT* an SSL_write call, because that fails once you've called |
- # shutdown) |
- try: |
- os.write(self.socket.fileno(), '') |
- except OSError, se: |
- if se.args[0] in (EINTR, EWOULDBLOCK, ENOBUFS): |
- return 0 |
- # Write error, socket gone |
- return main.CONNECTION_LOST |
- |
- try: |
- if hasattr(self.socket, 'set_shutdown'): |
- laststate = self.socket.get_shutdown() |
- self.socket.set_shutdown(laststate | SSL.RECEIVED_SHUTDOWN) |
- done = self.socket.shutdown() |
- if not (laststate & SSL.RECEIVED_SHUTDOWN): |
- self.socket.set_shutdown(SSL.SENT_SHUTDOWN) |
- else: |
- #warnings.warn("SSL connection shutdown possibly unreliable, " |
- # "please upgrade to ver 0.XX", category=UserWarning) |
- self.socket.shutdown() |
- done = True |
- except SSL.Error, e: |
- return e |
- |
- if done: |
- self.stopWriting() |
- # Note that this is tested for by identity below. |
- return main.CONNECTION_DONE |
- else: |
- self.startWriting() |
- return None |
- |
- def _closeWriteConnection(self): |
- result = self._sendCloseAlert() |
- |
- if result is main.CONNECTION_DONE: |
- return Connection._closeWriteConnection(self) |
- |
- return result |
- |
- def startReading(self): |
- self._userWantRead = True |
- if not self.readBlockedOnWrite: |
- return Connection.startReading(self) |
- |
- def stopReading(self): |
- self._userWantRead = False |
- if not self.writeBlockedOnRead: |
- return Connection.stopReading(self) |
- |
- def startWriting(self): |
- self._userWantWrite = True |
- if not self.writeBlockedOnRead: |
- return Connection.startWriting(self) |
- |
- def stopWriting(self): |
- self._userWantWrite = False |
- if not self.readBlockedOnWrite: |
- return Connection.stopWriting(self) |
- |
- def _resetReadWrite(self): |
- # After changing readBlockedOnWrite or writeBlockedOnRead, |
- # call this to reset the state to what the user requested. |
- if self._userWantWrite: |
- self.startWriting() |
- else: |
- self.stopWriting() |
- |
- if self._userWantRead: |
- self.startReading() |
- else: |
- self.stopReading() |
- |
-def _getTLSClass(klass, _existing={}): |
- if klass not in _existing: |
- class TLSConnection(_TLSMixin, klass): |
- implements(interfaces.ISSLTransport) |
- _existing[klass] = TLSConnection |
- return _existing[klass] |
- |
-class Connection(abstract.FileDescriptor, _SocketCloser): |
- """ |
- 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) |
- |
- TLS = 0 |
- |
- 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 |
- |
- if SSL: |
- |
- def startTLS(self, ctx): |
- assert not self.TLS |
- error=False |
- if self.dataBuffer or self._tempDataBuffer: |
- self.dataBuffer += "".join(self._tempDataBuffer) |
- self._tempDataBuffer = [] |
- self._tempDataLen = 0 |
- written = self.writeSomeData(buffer(self.dataBuffer, self.offset)) |
- offset = self.offset |
- dataLen = len(self.dataBuffer) |
- self.offset = 0 |
- self.dataBuffer = "" |
- if isinstance(written, Exception) or (offset + written != dataLen): |
- error=True |
- |
- |
- self.stopReading() |
- self.stopWriting() |
- self._startTLS() |
- self.socket = SSL.Connection(ctx.getContext(), self.socket) |
- self.fileno = self.socket.fileno |
- self.startReading() |
- if error: |
- warnings.warn("startTLS with unwritten buffered data currently doesn't work right. See issue #686. Closing connection.", category=RuntimeWarning, stacklevel=2) |
- self.loseConnection() |
- return |
- |
- def _startTLS(self): |
- self.TLS = 1 |
- self.__class__ = _getTLSClass(self.__class__) |
- |
- 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 |
- return self.protocol.dataReceived(data) |
- |
- def writeSomeData(self, data): |
- """Connection.writeSomeData(data) -> #of bytes written | CONNECTION_LOST |
- This writes as much data as possible to the socket and returns either |
- the number of bytes read (which is positive) or a connection error code |
- (which is negative) |
- """ |
- 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(). |
- """ |
- abstract.FileDescriptor.connectionLost(self, reason) |
- self._closeSocket() |
- 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) |
- |
-if SSL: |
- classImplements(Connection, interfaces.ITLSTransport) |
- |
-class BaseClient(Connection): |
- """A base class for client TCP (and similiar) sockets. |
- """ |
- addressFamily = socket.AF_INET |
- socketType = socket.SOCK_STREAM |
- |
- def _finishInit(self, whenDone, skt, error, reactor): |
- """Called by base classes to continue to next stage of initialization.""" |
- if whenDone: |
- Connection.__init__(self, skt, None, reactor) |
- self.doWrite = self.doConnect |
- self.doRead = self.doConnect |
- reactor.callLater(0, whenDone) |
- else: |
- reactor.callLater(0, self.failIfNotConnected, error) |
- |
- def startTLS(self, ctx, client=1): |
- holder = Connection.startTLS(self, ctx) |
- if client: |
- self.socket.set_connect_state() |
- else: |
- self.socket.set_accept_state() |
- return holder |
- |
- def stopConnecting(self): |
- """Stop attempt to connect.""" |
- self.failIfNotConnected(error.UserError()) |
- |
- 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.connector.connectionFailed(failure.Failure(err)) |
- if hasattr(self, "reactor"): |
- # this doesn't happen if we failed in __init__ |
- self.stopReading() |
- self.stopWriting() |
- del self.connector |
- |
- try: |
- self._closeSocket() |
- except AttributeError: |
- pass |
- else: |
- 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) |
- if fcntl and hasattr(fcntl, 'FD_CLOEXEC'): |
- old = fcntl.fcntl(s.fileno(), fcntl.F_GETFD) |
- fcntl.fcntl(s.fileno(), fcntl.F_SETFD, old | fcntl.FD_CLOEXEC) |
- return s |
- |
- def resolveAddress(self): |
- if abstract.isIPAddress(self.addr[0]): |
- self._setRealAddress(self.addr[0]) |
- else: |
- d = self.reactor.resolve(self.addr[0]) |
- d.addCallbacks(self._setRealAddress, self.failIfNotConnected) |
- |
- def _setRealAddress(self, address): |
- self.realAddress = (address, self.addr[1]) |
- self.doConnect() |
- |
- def doConnect(self): |
- """I connect the socket. |
- |
- Then, call the protocol's makeConnection, and start waiting for data. |
- """ |
- 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): |
- self.protocol = self.connector.buildProtocol(self.getPeer()) |
- self.connected = 1 |
- self.logstr = self.protocol.__class__.__name__ + ",client" |
- self.startReading() |
- self.protocol.makeConnection(self) |
- |
- def connectionLost(self, reason): |
- if not self.connected: |
- self.failIfNotConnected(error.ConnectError(string=reason)) |
- else: |
- Connection.connectionLost(self, reason) |
- self.connector.connectionLost(reason) |
- |
- |
-class Client(BaseClient): |
- """A TCP client.""" |
- |
- 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 |
- |
- try: |
- skt = self.createInternetSocket() |
- except socket.error, se: |
- err = error.ConnectBindError(se[0], se[1]) |
- whenDone = None |
- if whenDone and bindAddress is not None: |
- try: |
- skt.bind(bindAddress) |
- except socket.error, se: |
- err = error.ConnectBindError(se[0], se[1]) |
- whenDone = None |
- self._finishInit(whenDone, skt, err, reactor) |
- |
- def getHost(self): |
- """Returns an IPv4Address. |
- |
- This indicates the address from which I am connecting. |
- """ |
- return address.IPv4Address('TCP', *(self.socket.getsockname() + ('INET',))) |
- |
- def getPeer(self): |
- """Returns an IPv4Address. |
- |
- This indicates the address that I am connected to. |
- """ |
- return address.IPv4Address('TCP', *(self.addr + ('INET',))) |
- |
- def __repr__(self): |
- s = '<%s to %s at %x>' % (self.__class__, self.addr, unsignedID(self)) |
- return s |
- |
- |
-class Server(Connection): |
- """ |
- Serverside socket-stream connection class. |
- |
- This is a serverside network connection transport; a socket which came from |
- an accept() on a server. |
- """ |
- |
- def __init__(self, sock, protocol, client, server, sessionno): |
- """ |
- 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) |
- self.server = server |
- self.client = client |
- self.sessionno = sessionno |
- self.hostname = client[0] |
- self.logstr = "%s,%s,%s" % (self.protocol.__class__.__name__, |
- 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 startTLS(self, ctx, server=1): |
- holder = Connection.startTLS(self, ctx) |
- if server: |
- self.socket.set_accept_state() |
- else: |
- self.socket.set_connect_state() |
- return holder |
- |
- def getHost(self): |
- """Returns an IPv4Address. |
- |
- This indicates the server's address. |
- """ |
- return address.IPv4Address('TCP', *(self.socket.getsockname() + ('INET',))) |
- |
- def getPeer(self): |
- """Returns an IPv4Address. |
- |
- This indicates the client's address. |
- """ |
- return address.IPv4Address('TCP', *(self.client + ('INET',))) |
- |
-class Port(base.BasePort, _SocketCloser): |
- """I am a TCP server port, listening for connections. |
- |
- When a connection is accepted, I will call my factory's buildProtocol with |
- the incoming connection as an argument, according to the specification |
- described in twisted.internet.interfaces.IProtocolFactory. |
- |
- If you wish to change the sort of transport that will be used, my |
- `transport' attribute will be called with the signature expected for |
- Server.__init__, so it can be replaced. |
- """ |
- |
- implements(interfaces.IListeningPort) |
- |
- addressFamily = socket.AF_INET |
- socketType = socket.SOCK_STREAM |
- |
- transport = Server |
- sessionno = 0 |
- interface = '' |
- backlog = 50 |
- |
- # Actual port number being listened on, only set to a non-None |
- # value when we are actually listening. |
- _realPortNumber = None |
- |
- 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 |
- self.interface = interface |
- |
- 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. |
- """ |
- try: |
- skt = self.createInternetSocket() |
- skt.bind((self.interface, self.port)) |
- except socket.error, le: |
- raise CannotListenError, (self.interface, self.port, le) |
- |
- # 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.factory.__class__, self._realPortNumber)) |
- |
- # The order of the next 6 lines is kind of bizarre. If no one |
- # can explain it, perhaps we should re-arrange them. |
- self.factory.doStart() |
- skt.listen(self.backlog) |
- self.connected = 1 |
- self.socket = skt |
- self.fileno = self.socket.fileno |
- self.numberAccepts = 100 |
- |
- self.startReading() |
- |
- def _buildAddr(self, (host, port)): |
- return address._ServerFactoryIPv4Address('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 |
- |
- 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) |
- transport = self._preMakeConnection(transport) |
- 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 _preMakeConnection(self, transport): |
- return transport |
- |
- def loseConnection(self, connDone=failure.Failure(main.CONNECTION_DONE)): |
- """Stop accepting connections on this port. |
- |
- This will shut down my socket and call self.connectionLost(). |
- It returns a deferred which will fire successfully when the |
- port is actually closed. |
- """ |
- self.disconnecting = 1 |
- self.stopReading() |
- if self.connected: |
- self.deferred = defer.Deferred() |
- self.reactor.callLater(0, self.connectionLost, connDone) |
- return self.deferred |
- |
- stopListening = loseConnection |
- |
- def connectionLost(self, reason): |
- """Cleans up my socket. |
- """ |
- log.msg('(Port %s Closed)' % self._realPortNumber) |
- self._realPortNumber = None |
- base.BasePort.connectionLost(self, reason) |
- self.connected = 0 |
- self._closeSocket() |
- del self.socket |
- del self.fileno |
- self.factory.doStop() |
- if hasattr(self, "deferred"): |
- self.deferred.callback(None) |
- del self.deferred |
- |
- def logPrefix(self): |
- """Returns the name of my class, to prefix log entries with. |
- """ |
- return reflect.qual(self.factory.__class__) |
- |
- def getHost(self): |
- """Returns an IPv4Address. |
- |
- This indicates the server's address. |
- """ |
- return address.IPv4Address('TCP', *(self.socket.getsockname() + ('INET',))) |
- |
-class Connector(base.BaseConnector): |
- def __init__(self, host, port, factory, timeout, bindAddress, reactor=None): |
- self.host = host |
- if isinstance(port, types.StringTypes): |
- try: |
- port = socket.getservbyname(port, 'tcp') |
- except socket.error, e: |
- raise error.ServiceNameUnknownError(string="%s (%r)" % (e, port)) |
- self.port = port |
- self.bindAddress = bindAddress |
- base.BaseConnector.__init__(self, factory, timeout, reactor) |
- |
- def _makeTransport(self): |
- return Client(self.host, self.port, self.bindAddress, self, self.reactor) |
- |
- def getDestination(self): |
- return address.IPv4Address('TCP', self.host, self.port, 'INET') |