summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>2007-05-21 23:13:11 (GMT)
committerGuido van Rossum <guido@python.org>2007-05-21 23:13:11 (GMT)
commit7d0a8264ff29fe8963bb1cc67debc03e7c728a98 (patch)
treebb50e8fb32745b01279619826cb5bb30f2ccac12
parent88effc1251c295b0e70961b587fe0de63bf10754 (diff)
downloadcpython-7d0a8264ff29fe8963bb1cc67debc03e7c728a98.zip
cpython-7d0a8264ff29fe8963bb1cc67debc03e7c728a98.tar.gz
cpython-7d0a8264ff29fe8963bb1cc67debc03e7c728a98.tar.bz2
Sockets facelift. APIs that could return binary data (e.g. aton() and
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.)
-rw-r--r--Lib/io.py54
-rw-r--r--Lib/socket.py395
-rw-r--r--Lib/test/test_socket.py55
-rw-r--r--Lib/urllib2.py4
-rw-r--r--Modules/socketmodule.c208
5 files changed, 200 insertions, 516 deletions
diff --git a/Lib/io.py b/Lib/io.py
index 5f503c2..9cbc11c 100644
--- 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.
diff --git a/Lib/socket.py b/Lib/socket.py
index 8dd2383..03cdc65 100644
--- a/Lib/socket.py
+++ b/Lib/socket.py
@@ -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.
diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py
index 350aded..5158378 100644
--- a/Lib/test/test_socket.py
+++ b/Lib/test/test_socket.py
@@ -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,
diff --git a/Lib/urllib2.py b/Lib/urllib2.py
index 284c921..4127485 100644
--- a/Lib/urllib2.py
+++ b/Lib/urllib2.py
@@ -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())
diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c
index 71eafe6..eca29dd 100644
--- a/Modules/socketmodule.c
+++ b/Modules/socketmodule.c
@@ -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,