]> granicus.if.org Git - python/commitdiff
Sockets facelift. APIs that could return binary data (e.g. aton() and
authorGuido van Rossum <guido@python.org>
Mon, 21 May 2007 23:13:11 +0000 (23:13 +0000)
committerGuido van Rossum <guido@python.org>
Mon, 21 May 2007 23:13:11 +0000 (23:13 +0000)
recv()) now return bytes, not str or str8.  The socket.py code is
redone; it now subclasses _socket.socket and instead of having its own
_fileobject for makefile(), it uses io.SocketIO.  Some stuff in io.py
was moved around to make this work.  (I really need to rethink my
policy regarding readline() and read(-1) on raw files; and readline()
on buffered files ought to use peeking().  Later.)

Lib/io.py
Lib/socket.py
Lib/test/test_socket.py
Lib/urllib2.py
Modules/socketmodule.c

index 5f503c28429e4f17a38aaade64e8e9acd52cb35b..9cbc11c22f7c23f513ea1193ff6c9fa18f5a2972 100644 (file)
--- a/Lib/io.py
+++ b/Lib/io.py
@@ -295,6 +295,22 @@ class IOBase:
         """
         return False
 
+    ### Readline ###
+
+    def readline(self, sizehint: int = -1) -> bytes:
+        """For backwards compatibility, a (slow) readline()."""
+        if sizehint is None:
+            sizehint = -1
+        res = b""
+        while sizehint < 0 or len(res) < sizehint:
+            b = self.read(1)
+            if not b:
+                break
+            res += b
+            if b == b"\n":
+                break
+        return res
+
 
 class RawIOBase(IOBase):
 
@@ -366,7 +382,6 @@ class SocketIO(RawIOBase):
     """Raw I/O implementation for stream sockets."""
 
     # XXX More docs
-    # XXX Hook this up to socket.py
 
     def __init__(self, sock, mode):
         assert mode in ("r", "w", "rw")
@@ -377,13 +392,32 @@ class SocketIO(RawIOBase):
     def readinto(self, b):
         return self._sock.recv_into(b)
 
+    def read(self, n: int = None) -> bytes:
+        """read(n: int) -> bytes.  Read and return up to n bytes.
+
+        Returns an empty bytes array on EOF, or None if the object is
+        set not to block and has no data to read.
+        """
+        if n is None:
+            n = -1
+        if n >= 0:
+            return RawIOBase.read(self, n)
+        # Support reading until the end.
+        # XXX Why doesn't RawIOBase support this?
+        data = b""
+        while True:
+            more = RawIOBase.read(self, DEFAULT_BUFFER_SIZE)
+            if not more:
+                break
+            data += more
+        return data
+
     def write(self, b):
         return self._sock.send(b)
 
     def close(self):
         if not self.closed:
-            RawIOBase.close()
-            self._sock.close()
+            RawIOBase.close(self)
 
     def readable(self):
         return "r" in self._mode
@@ -450,20 +484,6 @@ class BufferedIOBase(IOBase):
         b[:n] = data
         return n
 
-    def readline(self, sizehint: int = -1) -> bytes:
-        """For backwards compatibility, a (slow) readline()."""
-        if sizehint is None:
-            sizehint = -1
-        res = b""
-        while sizehint < 0 or len(res) < sizehint:
-            b = self.read(1)
-            if not b:
-                break
-            res += b
-            if b == b"\n":
-                break
-        return res
-
     def write(self, b: bytes) -> int:
         """write(b: bytes) -> int.  Write the given buffer to the IO stream.
 
index 8dd23835d37984c6882f8c809d1f56010023e02d..03cdc65f764225a2ce12af33ddc7bf01683f40be 100644 (file)
@@ -54,7 +54,7 @@ try:
 except ImportError:
     pass
 
-import os, sys
+import os, sys, io
 
 try:
     from errno import EBADF
@@ -66,14 +66,6 @@ __all__.extend(os._get_exports_list(_socket))
 if _have_ssl:
     __all__.extend(os._get_exports_list(_ssl))
 
-_realsocket = socket
-if _have_ssl:
-    _realssl = ssl
-    def ssl(sock, keyfile=None, certfile=None):
-        if hasattr(sock, "_sock"):
-            sock = sock._sock
-        return _realssl(sock, keyfile, certfile)
-
 # WSA error codes
 if sys.platform.lower().startswith("win"):
     errorTab = {}
@@ -95,6 +87,99 @@ if sys.platform.lower().startswith("win"):
     __all__.append("errorTab")
 
 
+_os_has_dup = hasattr(os, "dup")
+if _os_has_dup:
+    def fromfd(fd, family=AF_INET, type=SOCK_STREAM, proto=0):
+        nfd = os.dup(fd)
+        return socket(family, type, proto, fileno=nfd)
+
+
+class socket(_socket.socket):
+
+    """A subclass of _socket.socket adding the makefile() method."""
+
+    __slots__ = ["__weakref__"]
+    if not _os_has_dup:
+        __slots__.append("_base")
+
+    def __repr__(self):
+        """Wrap __repr__() to reveal the real class name."""
+        s = _socket.socket.__repr__(self)
+        if s.startswith("<socket object"):
+            s = "<%s.%s%s" % (self.__class__.__module__,
+                              self.__class__.__name__,
+                              s[7:])
+        return s
+
+    def accept(self):
+        """Wrap accept() to give the connection the right type."""
+        conn, addr = _socket.socket.accept(self)
+        fd = conn.fileno()
+        nfd = fd
+        if _os_has_dup:
+            nfd = os.dup(fd)
+        wrapper = socket(self.family, self.type, self.proto, fileno=nfd)
+        if fd == nfd:
+            wrapper._base = conn  # Keep the base alive
+        else:
+            conn.close()
+        return wrapper, addr
+
+    if not _os_has_dup:
+        def close(self):
+            """Wrap close() to close the _base as well."""
+            _socket.socket.close(self)
+            base = getattr(self, "_base", None)
+            if base is not None:
+                base.close()
+
+    def makefile(self, mode="r", buffering=None, *,
+                 encoding=None, newline=None):
+        """Return an I/O stream connected to the socket.
+
+        The arguments are as for io.open() after the filename,
+        except the only mode characters supported are 'r', 'w' and 'b'.
+        The semantics are similar too.  (XXX refactor to share code?)
+        """
+        for c in mode:
+            if c not in {"r", "w", "b"}:
+                raise ValueError("invalid mode %r (only r, w, b allowed)")
+        writing = "w" in mode
+        reading = "r" in mode or not writing
+        assert reading or writing
+        binary = "b" in mode
+        rawmode = ""
+        if reading:
+            rawmode += "r"
+        if writing:
+            rawmode += "w"
+        raw = io.SocketIO(self, rawmode)
+        if buffering is None:
+            buffering = -1
+        if buffering < 0:
+            buffering = io.DEFAULT_BUFFER_SIZE
+        if buffering == 0:
+            if not binary:
+                raise ValueError("unbuffered streams must be binary")
+            raw.name = self.fileno()
+            raw.mode = mode
+            return raw
+        if reading and writing:
+            buffer = io.BufferedRWPair(raw, raw, buffering)
+        elif reading:
+            buffer = io.BufferedReader(raw, buffering)
+        else:
+            assert writing
+            buffer = io.BufferedWriter(raw, buffering)
+        if binary:
+            buffer.name = self.fileno()
+            buffer.mode = mode
+            return buffer
+        text = io.TextIOWrapper(buffer, encoding, newline)
+        text.name = self.fileno()
+        self.mode = mode
+        return text
+
 
 def getfqdn(name=''):
     """Get fully qualified domain name from name.
@@ -122,298 +207,6 @@ def getfqdn(name=''):
     return name
 
 
-_socketmethods = (
-    'bind', 'connect', 'connect_ex', 'fileno', 'listen',
-    'getpeername', 'getsockname', 'getsockopt', 'setsockopt',
-    'sendall', 'setblocking',
-    'settimeout', 'gettimeout', 'shutdown')
-
-if sys.platform == "riscos":
-    _socketmethods = _socketmethods + ('sleeptaskw',)
-
-# All the method names that must be delegated to either the real socket
-# object or the _closedsocket object.
-_delegate_methods = ("recv", "recvfrom", "recv_into", "recvfrom_into",
-                     "send", "sendto")
-
-class _closedsocket(object):
-    __slots__ = []
-    def _dummy(*args):
-        raise error(EBADF, 'Bad file descriptor')
-    # All _delegate_methods must also be initialized here.
-    send = recv = recv_into = sendto = recvfrom = recvfrom_into = _dummy
-    __getattr__ = _dummy
-
-class _socketobject(object):
-
-    __doc__ = _realsocket.__doc__
-
-    __slots__ = ["_sock", "__weakref__"] + list(_delegate_methods)
-
-    def __init__(self, family=AF_INET, type=SOCK_STREAM, proto=0, _sock=None):
-        if _sock is None:
-            _sock = _realsocket(family, type, proto)
-        self._sock = _sock
-        for method in _delegate_methods:
-            setattr(self, method, getattr(_sock, method))
-
-    def close(self):
-        self._sock = _closedsocket()
-        dummy = self._sock._dummy
-        for method in _delegate_methods:
-            setattr(self, method, dummy)
-    close.__doc__ = _realsocket.close.__doc__
-
-    def accept(self):
-        sock, addr = self._sock.accept()
-        return _socketobject(_sock=sock), addr
-    accept.__doc__ = _realsocket.accept.__doc__
-
-    def dup(self):
-        """dup() -> socket object
-
-        Return a new socket object connected to the same system resource."""
-        return _socketobject(_sock=self._sock)
-
-    def makefile(self, mode='r', bufsize=-1):
-        """makefile([mode[, bufsize]]) -> file object
-
-        Return a regular file object corresponding to the socket.  The mode
-        and bufsize arguments are as for the built-in open() function."""
-        return _fileobject(self._sock, mode, bufsize)
-
-    family = property(lambda self: self._sock.family, doc="the socket family")
-    type = property(lambda self: self._sock.type, doc="the socket type")
-    proto = property(lambda self: self._sock.proto, doc="the socket protocol")
-
-    _s = ("def %s(self, *args): return self._sock.%s(*args)\n\n"
-          "%s.__doc__ = _realsocket.%s.__doc__\n")
-    for _m in _socketmethods:
-        exec(_s % (_m, _m, _m, _m))
-    del _m, _s
-
-socket = SocketType = _socketobject
-
-class _fileobject(object):
-    """Faux file object attached to a socket object."""
-
-    default_bufsize = 8192
-    name = "<socket>"
-
-    __slots__ = ["mode", "bufsize",
-                 # "closed" is a property, see below
-                 "_sock", "_rbufsize", "_wbufsize", "_rbuf", "_wbuf",
-                 "_close"]
-
-    def __init__(self, sock, mode='rb', bufsize=-1, close=False):
-        self._sock = sock
-        self.mode = mode # Not actually used in this version
-        if bufsize < 0:
-            bufsize = self.default_bufsize
-        self.bufsize = bufsize
-        if bufsize == 0:
-            self._rbufsize = 1
-        elif bufsize == 1:
-            self._rbufsize = self.default_bufsize
-        else:
-            self._rbufsize = bufsize
-        self._wbufsize = bufsize
-        self._rbuf = "" # A string
-        self._wbuf = [] # A list of strings
-        self._close = close
-
-    def _getclosed(self):
-        return self._sock is None
-    closed = property(_getclosed, doc="True if the file is closed")
-
-    def close(self):
-        try:
-            if self._sock:
-                self.flush()
-        finally:
-            if self._close:
-                self._sock.close()
-            self._sock = None
-
-    def __del__(self):
-        try:
-            self.close()
-        except:
-            # close() may fail if __init__ didn't complete
-            pass
-
-    def flush(self):
-        if self._wbuf:
-            buffer = "".join(self._wbuf)
-            self._wbuf = []
-            self._sock.sendall(buffer)
-
-    def fileno(self):
-        return self._sock.fileno()
-
-    def write(self, data):
-        data = str(data) # XXX Should really reject non-string non-buffers
-        if not data:
-            return
-        self._wbuf.append(data)
-        if (self._wbufsize == 0 or
-            self._wbufsize == 1 and '\n' in data or
-            self._get_wbuf_len() >= self._wbufsize):
-            self.flush()
-
-    def writelines(self, list):
-        # XXX We could do better here for very long lists
-        # XXX Should really reject non-string non-buffers
-        self._wbuf.extend(filter(None, map(str, list)))
-        if (self._wbufsize <= 1 or
-            self._get_wbuf_len() >= self._wbufsize):
-            self.flush()
-
-    def _get_wbuf_len(self):
-        buf_len = 0
-        for x in self._wbuf:
-            buf_len += len(x)
-        return buf_len
-
-    def read(self, size=-1):
-        data = self._rbuf
-        if size < 0:
-            # Read until EOF
-            buffers = []
-            if data:
-                buffers.append(data)
-            self._rbuf = ""
-            if self._rbufsize <= 1:
-                recv_size = self.default_bufsize
-            else:
-                recv_size = self._rbufsize
-            while True:
-                data = self._sock.recv(recv_size)
-                if not data:
-                    break
-                buffers.append(data)
-            return "".join(buffers)
-        else:
-            # Read until size bytes or EOF seen, whichever comes first
-            buf_len = len(data)
-            if buf_len >= size:
-                self._rbuf = data[size:]
-                return data[:size]
-            buffers = []
-            if data:
-                buffers.append(data)
-            self._rbuf = ""
-            while True:
-                left = size - buf_len
-                recv_size = max(self._rbufsize, left)
-                data = self._sock.recv(recv_size)
-                if not data:
-                    break
-                buffers.append(data)
-                n = len(data)
-                if n >= left:
-                    self._rbuf = data[left:]
-                    buffers[-1] = data[:left]
-                    break
-                buf_len += n
-            return "".join(buffers)
-
-    def readline(self, size=-1):
-        data = self._rbuf
-        if size < 0:
-            # Read until \n or EOF, whichever comes first
-            if self._rbufsize <= 1:
-                # Speed up unbuffered case
-                assert data == ""
-                buffers = []
-                recv = self._sock.recv
-                while data != "\n":
-                    data = recv(1)
-                    if not data:
-                        break
-                    buffers.append(data)
-                return "".join(buffers)
-            nl = data.find('\n')
-            if nl >= 0:
-                nl += 1
-                self._rbuf = data[nl:]
-                return data[:nl]
-            buffers = []
-            if data:
-                buffers.append(data)
-            self._rbuf = ""
-            while True:
-                data = self._sock.recv(self._rbufsize)
-                if not data:
-                    break
-                buffers.append(data)
-                nl = data.find('\n')
-                if nl >= 0:
-                    nl += 1
-                    self._rbuf = data[nl:]
-                    buffers[-1] = data[:nl]
-                    break
-            return "".join(buffers)
-        else:
-            # Read until size bytes or \n or EOF seen, whichever comes first
-            nl = data.find('\n', 0, size)
-            if nl >= 0:
-                nl += 1
-                self._rbuf = data[nl:]
-                return data[:nl]
-            buf_len = len(data)
-            if buf_len >= size:
-                self._rbuf = data[size:]
-                return data[:size]
-            buffers = []
-            if data:
-                buffers.append(data)
-            self._rbuf = ""
-            while True:
-                data = self._sock.recv(self._rbufsize)
-                if not data:
-                    break
-                buffers.append(data)
-                left = size - buf_len
-                nl = data.find('\n', 0, left)
-                if nl >= 0:
-                    nl += 1
-                    self._rbuf = data[nl:]
-                    buffers[-1] = data[:nl]
-                    break
-                n = len(data)
-                if n >= left:
-                    self._rbuf = data[left:]
-                    buffers[-1] = data[:left]
-                    break
-                buf_len += n
-            return "".join(buffers)
-
-    def readlines(self, sizehint=0):
-        total = 0
-        list = []
-        while True:
-            line = self.readline()
-            if not line:
-                break
-            list.append(line)
-            total += len(line)
-            if sizehint and total >= sizehint:
-                break
-        return list
-
-    # Iterator protocols
-
-    def __iter__(self):
-        return self
-
-    def __next__(self):
-        line = self.readline()
-        if not line:
-            raise StopIteration
-        return line
-
-
 def create_connection(address, timeout=None):
     """Connect to address (host, port) with an optional timeout.
 
index 350adedc3e1e7b3222f4ee0449a358979e2e2f85..515837860350f584a1e0c10d8e23568944b3c6c9 100644 (file)
@@ -14,7 +14,7 @@ import signal
 
 PORT = 50007
 HOST = 'localhost'
-MSG = 'Michael Gilfix was here\n'
+MSG = b'Michael Gilfix was here\n'
 
 class SocketTCPTest(unittest.TestCase):
 
@@ -542,16 +542,16 @@ class BasicTCPTest(SocketConnectedTest):
 
     def testSendAll(self):
         # Testing sendall() with a 2048 byte string over TCP
-        msg = ''
+        msg = b''
         while 1:
             read = self.cli_conn.recv(1024)
             if not read:
                 break
             msg += read
-        self.assertEqual(msg, 'f' * 2048)
+        self.assertEqual(msg, b'f' * 2048)
 
     def _testSendAll(self):
-        big_chunk = 'f' * 2048
+        big_chunk = b'f' * 2048
         self.serv_conn.sendall(big_chunk)
 
     def testFromFd(self):
@@ -612,7 +612,7 @@ class TCPCloserTest(ThreadedTCPSocketTest):
         sd = self.cli
         read, write, err = select.select([sd], [], [], 1.0)
         self.assertEqual(read, [sd])
-        self.assertEqual(sd.recv(1), '')
+        self.assertEqual(sd.recv(1), b'')
 
     def _testClose(self):
         self.cli.connect((HOST, PORT))
@@ -754,7 +754,7 @@ class FileObjectClassTestCase(SocketConnectedTest):
 
     def testUnbufferedRead(self):
         # Performing unbuffered file read test
-        buf = ''
+        buf = b''
         while 1:
             char = self.serv_file.read(1)
             if not char:
@@ -796,14 +796,14 @@ class UnbufferedFileObjectClassTestCase(FileObjectClassTestCase):
     def testUnbufferedReadline(self):
         # Read a line, create a new file object, read another line with it
         line = self.serv_file.readline() # first line
-        self.assertEqual(line, "A. " + MSG) # first line
+        self.assertEqual(line, b"A. " + MSG) # first line
         self.serv_file = self.cli_conn.makefile('rb', 0)
         line = self.serv_file.readline() # second line
-        self.assertEqual(line, "B. " + MSG) # second line
+        self.assertEqual(line, b"B. " + MSG) # second line
 
     def _testUnbufferedReadline(self):
-        self.cli_file.write("A. " + MSG)
-        self.cli_file.write("B. " + MSG)
+        self.cli_file.write(b"A. " + MSG)
+        self.cli_file.write(b"B. " + MSG)
         self.cli_file.flush()
 
 class LineBufferedFileObjectClassTestCase(FileObjectClassTestCase):
@@ -818,6 +818,7 @@ class SmallBufferedFileObjectClassTestCase(FileObjectClassTestCase):
 
 class NetworkConnectionTest(object):
     """Prove network connection."""
+
     def clientSetUp(self):
         self.cli = socket.create_connection((HOST, PORT))
         self.serv_conn = self.cli
@@ -827,6 +828,7 @@ class BasicTCPTest2(NetworkConnectionTest, BasicTCPTest):
     """
 
 class NetworkConnectionNoServer(unittest.TestCase):
+
     def testWithoutServer(self):
         self.failUnlessRaises(socket.error, lambda: socket.create_connection((HOST, PORT)))
 
@@ -895,43 +897,19 @@ class NetworkConnectionBehaviourTest(SocketTCPTest, ThreadableTest):
     def testInsideTimeout(self):
         conn, addr = self.serv.accept()
         time.sleep(3)
-        conn.send("done!")
+        conn.send(b"done!")
     testOutsideTimeout = testInsideTimeout
 
     def _testInsideTimeout(self):
         self.cli = sock = socket.create_connection((HOST, PORT))
         data = sock.recv(5)
-        self.assertEqual(data, "done!")
+        self.assertEqual(data, b"done!")
 
     def _testOutsideTimeout(self):
         self.cli = sock = socket.create_connection((HOST, PORT), timeout=1)
         self.failUnlessRaises(socket.timeout, lambda: sock.recv(5))
 
 
-class Urllib2FileobjectTest(unittest.TestCase):
-
-    # urllib2.HTTPHandler has "borrowed" socket._fileobject, and requires that
-    # it close the socket if the close c'tor argument is true
-
-    def testClose(self):
-        class MockSocket:
-            closed = False
-            def flush(self): pass
-            def close(self): self.closed = True
-
-        # must not close unless we request it: the original use of _fileobject
-        # by module socket requires that the underlying socket not be closed until
-        # the _socketobject that created the _fileobject is closed
-        s = MockSocket()
-        f = socket._fileobject(s)
-        f.close()
-        self.assert_(not s.closed)
-
-        s = MockSocket()
-        f = socket._fileobject(s, close=True)
-        f.close()
-        self.assert_(s.closed)
-
 class TCPTimeoutTest(SocketTCPTest):
 
     def testTCPTimeout(self):
@@ -1055,7 +1033,7 @@ class BufferIOTest(SocketConnectedTest):
         buf = b" "*1024
         nbytes = self.cli_conn.recv_into(buf)
         self.assertEqual(nbytes, len(MSG))
-        msg = str(buf[:len(MSG)])
+        msg = buf[:len(MSG)]
         self.assertEqual(msg, MSG)
 
     def _testRecvInto(self):
@@ -1066,7 +1044,7 @@ class BufferIOTest(SocketConnectedTest):
         buf = b" "*1024
         nbytes, addr = self.cli_conn.recvfrom_into(buf)
         self.assertEqual(nbytes, len(MSG))
-        msg = str(buf[:len(MSG)])
+        msg = buf[:len(MSG)]
         self.assertEqual(msg, MSG)
 
     def _testRecvFromInto(self):
@@ -1085,7 +1063,6 @@ def test_main():
         UnbufferedFileObjectClassTestCase,
         LineBufferedFileObjectClassTestCase,
         SmallBufferedFileObjectClassTestCase,
-        Urllib2FileobjectTest,
         NetworkConnectionNoServer,
         NetworkConnectionAttributesTest,
         NetworkConnectionBehaviourTest,
index 284c921247abb354efad7616202caa0b678b9d4d..41274852ed0bdab895468f8b4b65d510c0b64077 100644 (file)
@@ -1085,10 +1085,8 @@ class AbstractHTTPHandler(BaseHandler):
         # to read().  This weird wrapping allows the returned object to
         # have readline() and readlines() methods.
 
-        # XXX It might be better to extract the read buffering code
-        # out of socket._fileobject() and into a base class.
-
         r.recv = r.read
+        # XXX socket._fileobject is gone; use some class from io.py instead
         fp = socket._fileobject(r, close=True)
 
         resp = addinfourl(fp, r.msg, req.get_full_url())
index 71eafe60fdf29a5a7a039aa983668812bac257e7..eca29dd0709ae430b10c8392b4521548c96bd8d2 100644 (file)
@@ -19,15 +19,14 @@ Module interface:
        a subclass of socket.error
 - socket.herror: exception raised for gethostby* errors,
        a subclass of socket.error
-- socket.fromfd(fd, family, type[, proto]) --> new socket object (created
-        from an existing file descriptor)
 - socket.gethostbyname(hostname) --> host IP address (string: 'dd.dd.dd.dd')
 - socket.gethostbyaddr(IP address) --> (hostname, [alias, ...], [IP addr, ...])
 - socket.gethostname() --> host name (string: 'spam' or 'spam.domain.com')
 - socket.getprotobyname(protocolname) --> protocol number
 - socket.getservbyname(servicename[, protocolname]) --> port number
 - socket.getservbyport(portnumber[, protocolname]) --> service name
-- socket.socket([family[, type [, proto]]]) --> new socket object
+- socket.socket([family[, type [, proto, fileno]]]) --> new socket object
+        (fileno specifies a pre-existing socket file descriptor)
 - socket.socketpair([family[, type [, proto]]]) --> (socket, socket)
 - socket.ntohs(16 bit value) --> new int object
 - socket.ntohl(32 bit value) --> new int object
@@ -102,7 +101,6 @@ getsockname() -- return local address\n\
 getsockopt(level, optname[, buflen]) -- get socket options\n\
 gettimeout() -- return timeout or None\n\
 listen(n) -- start listening for incoming connections\n\
-makefile([mode, [bufsize]]) -- return a file object for the socket [*]\n\
 recv(buflen[, flags]) -- receive data\n\
 recv_into(buffer[, nbytes[, flags]]) -- receive data (into a buffer)\n\
 recvfrom(buflen[, flags]) -- receive data and sender\'s address\n\
@@ -402,6 +400,10 @@ const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
 #define NI_MAXSERV 32
 #endif
 
+#ifndef INVALID_SOCKET /* MS defines this */
+#define INVALID_SOCKET (-1)
+#endif
+
 /* XXX There's a problem here: *static* functions are not supposed to have
    a Py prefix (or use CapitalizedWords).  Later... */
 
@@ -1551,7 +1553,7 @@ static PyObject *
 sock_accept(PySocketSockObject *s)
 {
        sock_addr_t addrbuf;
-       SOCKET_T newfd;
+       SOCKET_T newfd = INVALID_SOCKET;
        socklen_t addrlen;
        PyObject *sock = NULL;
        PyObject *addr = NULL;
@@ -1562,12 +1564,6 @@ sock_accept(PySocketSockObject *s)
                return NULL;
        memset(&addrbuf, 0, addrlen);
 
-#ifdef MS_WINDOWS
-       newfd = INVALID_SOCKET;
-#else
-       newfd = -1;
-#endif
-
        if (!IS_SELECTABLE(s))
                return select_error();
 
@@ -1582,11 +1578,7 @@ sock_accept(PySocketSockObject *s)
                return NULL;
        }
 
-#ifdef MS_WINDOWS
        if (newfd == INVALID_SOCKET)
-#else
-       if (newfd < 0)
-#endif
                return s->errorhandler();
 
        /* Create the new object with unspecified family,
@@ -1814,16 +1806,19 @@ sock_getsockopt(PySocketSockObject *s, PyObject *args)
                                "getsockopt buflen out of range");
                return NULL;
        }
-       buf = PyString_FromStringAndSize((char *)NULL, buflen);
+       buf = PyBytes_FromStringAndSize((char *)NULL, buflen);
        if (buf == NULL)
                return NULL;
        res = getsockopt(s->sock_fd, level, optname,
-                        (void *)PyString_AS_STRING(buf), &buflen);
+                        (void *)PyBytes_AS_STRING(buf), &buflen);
        if (res < 0) {
                Py_DECREF(buf);
                return s->errorhandler();
        }
-       _PyString_Resize(&buf, buflen);
+       if (PyBytes_Resize(buf, buflen) < 0) {
+               Py_DECREF(buf);
+               return NULL;
+       }
        return buf;
 #endif /* __BEOS__ */
 }
@@ -2173,69 +2168,6 @@ least 1; it specifies the number of unaccepted connection that the system\n\
 will allow before refusing new connections.");
 
 
-#ifndef NO_DUP
-/* s.makefile(mode) method.
-   Create a new open file object referring to a dupped version of
-   the socket's file descriptor.  (The dup() call is necessary so
-   that the open file and socket objects may be closed independent
-   of each other.)
-   The mode argument specifies 'r' or 'w' passed to fdopen(). */
-
-static PyObject *
-sock_makefile(PySocketSockObject *s, PyObject *args)
-{
-       extern int fclose(FILE *);
-       char *mode = "r";
-       int bufsize = -1;
-#ifdef MS_WIN32
-       Py_intptr_t fd;
-#else
-       int fd;
-#endif
-       FILE *fp;
-       PyObject *f;
-#ifdef __VMS
-       char *mode_r = "r";
-       char *mode_w = "w";
-#endif
-
-       if (!PyArg_ParseTuple(args, "|si:makefile", &mode, &bufsize))
-               return NULL;
-#ifdef __VMS
-       if (strcmp(mode,"rb") == 0) {
-           mode = mode_r;
-       }
-       else {
-               if (strcmp(mode,"wb") == 0) {
-                       mode = mode_w;
-               }
-       }
-#endif
-#ifdef MS_WIN32
-       if (((fd = _open_osfhandle(s->sock_fd, _O_BINARY)) < 0) ||
-           ((fd = dup(fd)) < 0) || ((fp = fdopen(fd, mode)) == NULL))
-#else
-       if ((fd = dup(s->sock_fd)) < 0 || (fp = fdopen(fd, mode)) == NULL)
-#endif
-       {
-               if (fd >= 0)
-                       SOCKETCLOSE(fd);
-               return s->errorhandler();
-       }
-       f = PyFile_FromFile(fp, "<socket>", mode, fclose);
-       if (f != NULL)
-               PyFile_SetBufSize(f, bufsize);
-       return f;
-}
-
-PyDoc_STRVAR(makefile_doc,
-"makefile([mode[, buffersize]]) -> file object\n\
-\n\
-Return a regular file object corresponding to the socket.\n\
-The mode and buffersize arguments are as for the built-in open() function.");
-
-#endif /* NO_DUP */
-
 /*
  * This is the guts of the recv() and recv_into() methods, which reads into a
  * char buffer.  If you have any inc/dec ref to do to the objects that contain
@@ -2339,12 +2271,12 @@ sock_recv(PySocketSockObject *s, PyObject *args)
        }
 
        /* Allocate a new string. */
-       buf = PyString_FromStringAndSize((char *) 0, recvlen);
+       buf = PyBytes_FromStringAndSize((char *) 0, recvlen);
        if (buf == NULL)
                return NULL;
 
        /* Call the guts */
-       outlen = sock_recv_guts(s, PyString_AS_STRING(buf), recvlen, flags);
+       outlen = sock_recv_guts(s, PyBytes_AS_STRING(buf), recvlen, flags);
        if (outlen < 0) {
                /* An error occurred, release the string and return an
                   error. */
@@ -2354,7 +2286,7 @@ sock_recv(PySocketSockObject *s, PyObject *args)
        if (outlen != recvlen) {
                /* We did not read as many bytes as we anticipated, resize the
                   string if possible and be succesful. */
-               if (_PyString_Resize(&buf, outlen) < 0)
+               if (PyBytes_Resize(buf, outlen) < 0)
                        /* Oopsy, not so succesful after all. */
                        return NULL;
        }
@@ -2513,11 +2445,11 @@ sock_recvfrom(PySocketSockObject *s, PyObject *args)
                return NULL;
        }
 
-       buf = PyString_FromStringAndSize((char *) 0, recvlen);
+       buf = PyBytes_FromStringAndSize((char *) 0, recvlen);
        if (buf == NULL)
                return NULL;
 
-       outlen = sock_recvfrom_guts(s, PyString_AS_STRING(buf),
+       outlen = sock_recvfrom_guts(s, PyBytes_AS_STRING(buf),
                                    recvlen, flags, &addr);
        if (outlen < 0) {
                goto finally;
@@ -2526,7 +2458,7 @@ sock_recvfrom(PySocketSockObject *s, PyObject *args)
        if (outlen != recvlen) {
                /* We did not read as many bytes as we anticipated, resize the
                   string if possible and be succesful. */
-               if (_PyString_Resize(&buf, outlen) < 0)
+               if (PyBytes_Resize(buf, outlen) < 0)
                        /* Oopsy, not so succesful after all. */
                        goto finally;
        }
@@ -2788,10 +2720,6 @@ static PyMethodDef sock_methods[] = {
                          getsockopt_doc},
        {"listen",        (PyCFunction)sock_listen, METH_O,
                          listen_doc},
-#ifndef NO_DUP
-       {"makefile",      (PyCFunction)sock_makefile, METH_VARARGS,
-                         makefile_doc},
-#endif
        {"recv",          (PyCFunction)sock_recv, METH_VARARGS,
                          recv_doc},
        {"recv_into",     (PyCFunction)sock_recv_into, METH_VARARGS | METH_KEYWORDS,
@@ -2861,7 +2789,7 @@ sock_repr(PySocketSockObject *s)
 #endif
        PyOS_snprintf(
                buf, sizeof(buf),
-               "<socket object, fd=%ld, family=%d, type=%d, protocol=%d>",
+               "<socket object, fd=%ld, family=%d, type=%d, proto=%d>",
                (long)s->sock_fd, s->sock_family,
                s->sock_type,
                s->sock_proto);
@@ -2893,27 +2821,35 @@ static int
 sock_initobj(PyObject *self, PyObject *args, PyObject *kwds)
 {
        PySocketSockObject *s = (PySocketSockObject *)self;
-       SOCKET_T fd;
+       PyObject *fdobj = NULL;
+       SOCKET_T fd = INVALID_SOCKET;
        int family = AF_INET, type = SOCK_STREAM, proto = 0;
-       static char *keywords[] = {"family", "type", "proto", 0};
+       static char *keywords[] = {"family", "type", "proto", "fileno", 0};
 
        if (!PyArg_ParseTupleAndKeywords(args, kwds,
-                                        "|iii:socket", keywords,
-                                        &family, &type, &proto))
+                                        "|iiiO:socket", keywords,
+                                        &family, &type, &proto, &fdobj))
                return -1;
 
-       Py_BEGIN_ALLOW_THREADS
-       fd = socket(family, type, proto);
-       Py_END_ALLOW_THREADS
+       if (fdobj != NULL) {
+               fd = PyLong_AsLongLong(fdobj);
+               if (fd == (SOCKET_T)(-1) && PyErr_Occurred())
+                       return -1;
+               if (fd == INVALID_SOCKET) {
+                       PyErr_SetString(PyExc_ValueError,
+                                       "can't use invalid socket value");
+                       return -1;
+               }
+       }
+       else {
+               Py_BEGIN_ALLOW_THREADS
+               fd = socket(family, type, proto);
+               Py_END_ALLOW_THREADS
 
-#ifdef MS_WINDOWS
-       if (fd == INVALID_SOCKET)
-#else
-       if (fd < 0)
-#endif
-       {
-               set_error();
-               return -1;
+               if (fd == INVALID_SOCKET) {
+                       set_error();
+                       return -1;
+               }
        }
        init_sockobject(s, fd, family, type, proto);
 
@@ -3462,39 +3398,6 @@ AF_UNIX if defined on the platform; otherwise, the default is AF_INET.");
 #endif /* HAVE_SOCKETPAIR */
 
 
-#ifndef NO_DUP
-/* Create a socket object from a numeric file description.
-   Useful e.g. if stdin is a socket.
-   Additional arguments as for socket(). */
-
-/*ARGSUSED*/
-static PyObject *
-socket_fromfd(PyObject *self, PyObject *args)
-{
-       PySocketSockObject *s;
-       SOCKET_T fd;
-       int family, type, proto = 0;
-       if (!PyArg_ParseTuple(args, "iii|i:fromfd",
-                             &fd, &family, &type, &proto))
-               return NULL;
-       /* Dup the fd so it and the socket can be closed independently */
-       fd = dup(fd);
-       if (fd < 0)
-               return set_error();
-       s = new_sockobject(fd, family, type, proto);
-       return (PyObject *) s;
-}
-
-PyDoc_STRVAR(fromfd_doc,
-"fromfd(fd, family, type[, proto]) -> socket object\n\
-\n\
-Create a socket object from a duplicate of the given\n\
-file descriptor.\n\
-The remaining arguments are the same as for socket().");
-
-#endif /* NO_DUP */
-
-
 static PyObject *
 socket_ntohs(PyObject *self, PyObject *args)
 {
@@ -3613,7 +3516,7 @@ Convert a 32-bit integer from host to network byte order.");
 /* socket.inet_aton() and socket.inet_ntoa() functions. */
 
 PyDoc_STRVAR(inet_aton_doc,
-"inet_aton(string) -> packed 32-bit IP representation\n\
+"inet_aton(string) -> bytes giving packed 32-bit IP representation\n\
 \n\
 Convert an IP address in string format (123.45.67.89) to the 32-bit packed\n\
 binary format used in low-level network functions.");
@@ -3644,7 +3547,7 @@ socket_inet_aton(PyObject *self, PyObject *args)
     if (inet_aton != NULL) {
 #endif
        if (inet_aton(ip_addr, &buf))
-               return PyString_FromStringAndSize((char *)(&buf),
+               return PyBytes_FromStringAndSize((char *)(&buf),
                                                  sizeof(buf));
 
        PyErr_SetString(socket_error,
@@ -3673,8 +3576,8 @@ socket_inet_aton(PyObject *self, PyObject *args)
                        return NULL;
                }
        }
-       return PyString_FromStringAndSize((char *) &packed_addr,
-                                         sizeof(packed_addr));
+       return PyBytes_FromStringAndSize((char *) &packed_addr,
+                                        sizeof(packed_addr));
 
 #ifdef USE_INET_ATON_WEAKLINK
    }
@@ -4077,10 +3980,6 @@ static PyMethodDef socket_methods[] = {
         METH_VARARGS, getservbyport_doc},
        {"getprotobyname",      socket_getprotobyname,
         METH_VARARGS, getprotobyname_doc},
-#ifndef NO_DUP
-       {"fromfd",              socket_fromfd,
-        METH_VARARGS, fromfd_doc},
-#endif
 #ifdef HAVE_SOCKETPAIR
        {"socketpair",          socket_socketpair,
         METH_VARARGS, socketpair_doc},
@@ -4229,14 +4128,11 @@ PySocketModule_APIObject PySocketModuleAPI =
 /* Initialize the _socket module.
 
    This module is actually called "_socket", and there's a wrapper
-   "socket.py" which implements some additional functionality.  On some
-   platforms (e.g. Windows and OS/2), socket.py also implements a
-   wrapper for the socket type that provides missing functionality such
-   as makefile(), dup() and fromfd().  The import of "_socket" may fail
-   with an ImportError exception if os-specific initialization fails.
-   On Windows, this does WINSOCK initialization.  When WINSOCK is
-   initialized succesfully, a call to WSACleanup() is scheduled to be
-   made at exit time.
+   "socket.py" which implements some additional functionality.
+   The import of "_socket" may fail with an ImportError exception if
+   os-specific initialization fails.  On Windows, this does WINSOCK
+   initialization.  When WINSOCK is initialized succesfully, a call to
+   WSACleanup() is scheduled to be made at exit time.
 */
 
 PyDoc_STRVAR(socket_doc,