mirror of
https://github.com/python/cpython.git
synced 2025-08-03 16:39:00 +00:00
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.)
This commit is contained in:
parent
88effc1251
commit
7d0a8264ff
5 changed files with 200 additions and 516 deletions
|
@ -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,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue