Made SocketType and socket the same thing: a subclassable type whose

constructor acts just like socket() before.  All three arguments have
a sensible default now; socket() is equivalent to
socket(AF_INET, SOCK_STREAM).

One minor issue: the socket() function and the SocketType had
different doc strings; socket.__doc__ gave the signature,
SocketType.__doc__ gave the methods.  I've merged these for now, but
maybe the list of methods is no longer necessary since it can easily
be recovered through socket.__dict__.keys().  The problem with keeping
it is that the total doc string is a bit long (34 lines -- it scrolls
of a standard tty screen).

Another general issue with the socket module is that it's a big mess.
There's pages and pages of random platform #ifdefs, and the naming
conventions are totally wrong: it uses Py prefixes and CapWords for
static functions.  That's a cleanup for another day...  (Also I think
the big starting comment that summarizes the API can go -- it's a
repeat of the docstring.)
This commit is contained in:
Guido van Rossum 2001-10-27 22:20:47 +00:00
parent bd67d6f32c
commit 384ca9c6dd

View file

@ -9,8 +9,8 @@ Limitations:
- only AF_INET, AF_INET6 and AF_UNIX address families are supported in a - only AF_INET, AF_INET6 and AF_UNIX address families are supported in a
portable manner, though AF_PACKET is supported under Linux. portable manner, though AF_PACKET is supported under Linux.
- no read/write operations (use send/recv or makefile instead) - no read/write operations (use sendall/recv or makefile instead)
- additional restrictions apply on Windows - additional restrictions apply on Windows (compensated for by socket.py)
Module interface: Module interface:
@ -77,6 +77,9 @@ Socket methods:
#include "Python.h" #include "Python.h"
/* XXX This is a terrible mess of of platform-dependent preprocessor hacks.
I hope some day someone can clean this up please... */
/* Hacks for gethostbyname_r(). On some non-Linux platforms, the configure /* Hacks for gethostbyname_r(). On some non-Linux platforms, the configure
script doesn't get this right, so we hardcode some platform checks below. script doesn't get this right, so we hardcode some platform checks below.
On the other hand, not all Linux versions agree, so there the settings On the other hand, not all Linux versions agree, so there the settings
@ -267,6 +270,10 @@ typedef int SOCKET_T;
#define SOCKETCLOSE close #define SOCKETCLOSE close
#endif #endif
/* XXX There's a problem here: *static* functions are not supposed to have
a Py prefix (or use CapitalizedWords). Later... */
/* Global variable holding the exception type for errors detected /* Global variable holding the exception type for errors detected
by this module (but not argument type or memory errors, etc.). */ by this module (but not argument type or memory errors, etc.). */
@ -511,21 +518,15 @@ staticforward PyObject *PySSL_SSLread(PySSLObject *self, PyObject *args);
staticforward PyTypeObject PySocketSock_Type; staticforward PyTypeObject PySocketSock_Type;
/* Create a new socket object. /* Initialize a new socket object. */
This just creates the object and initializes it.
If the creation fails, return NULL and set an exception (implicit
in NEWOBJ()). */
static PySocketSockObject * static void
PySocketSock_New(SOCKET_T fd, int family, int type, int proto) init_sockobject(PySocketSockObject *s,
SOCKET_T fd, int family, int type, int proto)
{ {
#ifdef RISCOS #ifdef RISCOS
int block = 1; int block = 1;
#endif #endif
PySocketSockObject *s;
PySocketSock_Type.ob_type = &PyType_Type;
s = PyObject_New(PySocketSockObject, &PySocketSock_Type);
if (s != NULL) {
s->sock_fd = fd; s->sock_fd = fd;
s->sock_family = family; s->sock_family = family;
s->sock_type = type; s->sock_type = type;
@ -535,7 +536,22 @@ PySocketSock_New(SOCKET_T fd, int family, int type, int proto)
socketioctl(s->sock_fd, 0x80046679, (u_long*)&block); socketioctl(s->sock_fd, 0x80046679, (u_long*)&block);
} }
#endif #endif
} }
/* Create a new socket object.
This just creates the object and initializes it.
If the creation fails, return NULL and set an exception (implicit
in NEWOBJ()). */
static PySocketSockObject *
PySocketSock_New(SOCKET_T fd, int family, int type, int proto)
{
PySocketSockObject *s;
s = (PySocketSockObject *)
PyType_GenericNew(&PySocketSock_Type, NULL, NULL);
if (s != NULL)
init_sockobject(s, fd, family, type, proto);
return s; return s;
} }
@ -1720,16 +1736,7 @@ PySocketSock_dealloc(PySocketSockObject *s)
{ {
if (s->sock_fd != -1) if (s->sock_fd != -1)
(void) SOCKETCLOSE(s->sock_fd); (void) SOCKETCLOSE(s->sock_fd);
PyObject_Del(s); s->ob_type->tp_free((PyObject *)s);
}
/* Return a socket object's named attribute. */
static PyObject *
PySocketSock_getattr(PySocketSockObject *s, char *name)
{
return Py_FindMethod(PySocketSock_methods, (PyObject *) s, name);
} }
@ -1754,23 +1761,136 @@ PySocketSock_repr(PySocketSockObject *s)
} }
/* Create a new, uninitialized socket object. */
static PyObject *
PySocketSock_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyObject *new;
new = type->tp_alloc(type, 0);
if (new != NULL)
((PySocketSockObject *)new)->sock_fd = -1;
return new;
}
/* Initialize a new socket object. */
/*ARGSUSED*/
static int
PySocketSock_init(PyObject *self, PyObject *args, PyObject *kwds)
{
PySocketSockObject *s = (PySocketSockObject *)self;
SOCKET_T fd;
int family = AF_INET, type = SOCK_STREAM, proto = 0;
static char *keywords[] = {"family", "type", "proto", 0};
if (!PyArg_ParseTupleAndKeywords(args, kwds,
"|iii:socket", keywords,
&family, &type, &proto))
return -1;
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
{
PySocket_Err();
return -1;
}
init_sockobject(s, fd, family, type, proto);
/* From now on, ignore SIGPIPE and let the error checking
do the work. */
#ifdef SIGPIPE
(void) signal(SIGPIPE, SIG_IGN);
#endif
return 0;
}
/* Type object for socket objects. */ /* Type object for socket objects. */
static char socket_doc[] =
"socket([family[, type[, proto]]]) -> socket object\n\
\n\
Open a socket of the given type. The family argument specifies the\n\
address family; it defaults to AF_INET. The type argument specifies\n\
whether this is a stream (SOCK_STREAM, this is the default)\n\
or datagram (SOCK_DGRAM) socket. The protocol argument defaults to 0,\n\
specifying the default protocol.\n\
\n\
A socket represents one endpoint of a network connection.\n\
\n\
Methods:\n\
\n\
accept() -- accept a connection, returning new socket and client address\n\
bind() -- bind the socket to a local address\n\
close() -- close the socket\n\
connect() -- connect the socket to a remote address\n\
connect_ex() -- connect, return an error code instead of an exception \n\
dup() -- return a new socket object identical to the current one (*)\n\
fileno() -- return underlying file descriptor\n\
getpeername() -- return remote address (*)\n\
getsockname() -- return local address\n\
getsockopt() -- get socket options\n\
listen() -- start listening for incoming connections\n\
makefile() -- return a file object corresponding tot the socket (*)\n\
recv() -- receive data\n\
recvfrom() -- receive data and sender's address\n\
send() -- send data, may not send all of it\n\
sendall() -- send all data\n\
sendto() -- send data to a given address\n\
setblocking() -- set or clear the blocking I/O flag\n\
setsockopt() -- set socket options\n\
shutdown() -- shut down traffic in one or both directions\n\
\n\
(*) not available on all platforms!)";
static PyTypeObject PySocketSock_Type = { static PyTypeObject PySocketSock_Type = {
PyObject_HEAD_INIT(0) /* Must fill in type value later */ PyObject_HEAD_INIT(0) /* Must fill in type value later */
0, 0, /* ob_size */
"socket", "socket.socket", /* tp_name */
sizeof(PySocketSockObject), sizeof(PySocketSockObject), /* tp_basicsize */
0, 0, /* tp_itemsize */
(destructor)PySocketSock_dealloc, /*tp_dealloc*/ (destructor)PySocketSock_dealloc, /* tp_dealloc */
0, /*tp_print*/ 0, /* tp_print */
(getattrfunc)PySocketSock_getattr, /*tp_getattr*/ 0, /* tp_getattr */
0, /*tp_setattr*/ 0, /* tp_setattr */
0, /*tp_compare*/ 0, /* tp_compare */
(reprfunc)PySocketSock_repr, /*tp_repr*/ (reprfunc)PySocketSock_repr, /* tp_repr */
0, /*tp_as_number*/ 0, /* tp_as_number */
0, /*tp_as_sequence*/ 0, /* tp_as_sequence */
0, /*tp_as_mapping*/ 0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
socket_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
PySocketSock_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
PySocketSock_init, /* tp_init */
PyType_GenericAlloc, /* tp_alloc */
PySocketSock_new, /* tp_new */
_PyObject_Del, /* tp_free */
}; };
@ -2149,51 +2269,6 @@ static char getprotobyname_doc[] =
Return the protocol number for the named protocol. (Rarely used.)"; Return the protocol number for the named protocol. (Rarely used.)";
/* Python interface to socket(family, type, proto).
The third (protocol) argument is optional.
Return a new socket object. */
/*ARGSUSED*/
static PyObject *
PySocket_socket(PyObject *self, PyObject *args)
{
PySocketSockObject *s;
SOCKET_T fd;
int family, type, proto = 0;
if (!PyArg_ParseTuple(args, "ii|i:socket", &family, &type, &proto))
return NULL;
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
return PySocket_Err();
s = PySocketSock_New(fd, family, type, proto);
/* If the object can't be created, don't forget to close the
file descriptor again! */
if (s == NULL)
(void) SOCKETCLOSE(fd);
/* From now on, ignore SIGPIPE and let the error checking
do the work. */
#ifdef SIGPIPE
(void) signal(SIGPIPE, SIG_IGN);
#endif
return (PyObject *) s;
}
static char socket_doc[] =
"socket(family, type[, proto]) -> socket object\n\
\n\
Open a socket of the given type. The family argument specifies the\n\
address family; it is normally AF_INET, sometimes AF_UNIX.\n\
The type argument specifies whether this is a stream (SOCK_STREAM)\n\
or datagram (SOCK_DGRAM) socket. The protocol argument defaults to 0,\n\
specifying the default protocol.";
#ifndef NO_DUP #ifndef NO_DUP
/* Create a socket object from a numeric file description. /* Create a socket object from a numeric file description.
Useful e.g. if stdin is a socket. Useful e.g. if stdin is a socket.
@ -2886,8 +2961,6 @@ static PyMethodDef PySocket_methods[] = {
METH_VARARGS, getservbyname_doc}, METH_VARARGS, getservbyname_doc},
{"getprotobyname", PySocket_getprotobyname, {"getprotobyname", PySocket_getprotobyname,
METH_VARARGS,getprotobyname_doc}, METH_VARARGS,getprotobyname_doc},
{"socket", PySocket_socket,
METH_VARARGS, socket_doc},
#ifndef NO_DUP #ifndef NO_DUP
{"fromfd", PySocket_fromfd, {"fromfd", PySocket_fromfd,
METH_VARARGS, fromfd_doc}, METH_VARARGS, fromfd_doc},
@ -3029,33 +3102,6 @@ static char module_doc[] =
"Implementation module for socket operations. See the socket module\n\ "Implementation module for socket operations. See the socket module\n\
for documentation."; for documentation.";
static char sockettype_doc[] =
"A socket represents one endpoint of a network connection.\n\
\n\
Methods:\n\
\n\
accept() -- accept a connection, returning new socket and client address\n\
bind() -- bind the socket to a local address\n\
close() -- close the socket\n\
connect() -- connect the socket to a remote address\n\
connect_ex() -- connect, return an error code instead of an exception \n\
dup() -- return a new socket object identical to the current one (*)\n\
fileno() -- return underlying file descriptor\n\
getpeername() -- return remote address (*)\n\
getsockname() -- return local address\n\
getsockopt() -- get socket options\n\
listen() -- start listening for incoming connections\n\
makefile() -- return a file object corresponding tot the socket (*)\n\
recv() -- receive data\n\
recvfrom() -- receive data and sender's address\n\
send() -- send data\n\
sendto() -- send data to a given address\n\
setblocking() -- set or clear the blocking I/O flag\n\
setsockopt() -- set socket options\n\
shutdown() -- shut down traffic in one or both directions\n\
\n\
(*) not available on all platforms!)";
DL_EXPORT(void) DL_EXPORT(void)
init_socket(void) init_socket(void)
{ {
@ -3076,6 +3122,7 @@ init_socket(void)
#endif /* __TOS_OS2__ */ #endif /* __TOS_OS2__ */
#endif /* MS_WINDOWS */ #endif /* MS_WINDOWS */
#endif /* RISCOS */ #endif /* RISCOS */
PySocketSock_Type.ob_type = &PyType_Type;
#ifdef USE_SSL #ifdef USE_SSL
PySSL_Type.ob_type = &PyType_Type; PySSL_Type.ob_type = &PyType_Type;
#endif #endif
@ -3117,11 +3164,12 @@ init_socket(void)
PyModule_AddIntConstant(m, "SSL_ERROR_SSL", PyModule_AddIntConstant(m, "SSL_ERROR_SSL",
SSL_ERROR_SSL); SSL_ERROR_SSL);
#endif /* USE_SSL */ #endif /* USE_SSL */
PySocketSock_Type.ob_type = &PyType_Type;
PySocketSock_Type.tp_doc = sockettype_doc;
if (PyDict_SetItemString(d, "SocketType", if (PyDict_SetItemString(d, "SocketType",
(PyObject *)&PySocketSock_Type) != 0) (PyObject *)&PySocketSock_Type) != 0)
return; return;
if (PyDict_SetItemString(d, "socket",
(PyObject *)&PySocketSock_Type) != 0)
return;
/* Address families (we only support AF_INET and AF_UNIX) */ /* Address families (we only support AF_INET and AF_UNIX) */
#ifdef AF_UNSPEC #ifdef AF_UNSPEC