summaryrefslogtreecommitdiffstats
path: root/Modules/socketmodule.c
diff options
context:
space:
mode:
Diffstat (limited to 'Modules/socketmodule.c')
-rw-r--r--Modules/socketmodule.c197
1 files changed, 139 insertions, 58 deletions
diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c
index b34981c..d896cc0 100644
--- a/Modules/socketmodule.c
+++ b/Modules/socketmodule.c
@@ -163,7 +163,11 @@ if_indextoname(index) -- return the corresponding interface name\n\
# include <sys/uio.h>
#endif
-#ifndef WITH_THREAD
+#if !defined(WITH_THREAD)
+# undef HAVE_GETHOSTBYNAME_R
+#endif
+
+#if defined(__ANDROID__) && __ANDROID_API__ < 23
# undef HAVE_GETHOSTBYNAME_R
#endif
@@ -926,7 +930,7 @@ static PyThread_type_lock netdb_lock;
an error occurred; then an exception is raised. */
static int
-setipaddr(char *name, struct sockaddr *addr_ret, size_t addr_ret_size, int af)
+setipaddr(const char *name, struct sockaddr *addr_ret, size_t addr_ret_size, int af)
{
struct addrinfo hints, *res;
int error;
@@ -1107,7 +1111,7 @@ makeipaddr(struct sockaddr *addr, int addrlen)
an error occurred. */
static int
-setbdaddr(char *name, bdaddr_t *bdaddr)
+setbdaddr(const char *name, bdaddr_t *bdaddr)
{
unsigned int b0, b1, b2, b3, b4, b5;
char ch;
@@ -1401,7 +1405,7 @@ static int
idna_converter(PyObject *obj, struct maybe_idna *data)
{
size_t len;
- PyObject *obj2, *obj3;
+ PyObject *obj2;
if (obj == NULL) {
idna_cleanup(data);
return 1;
@@ -1416,31 +1420,27 @@ idna_converter(PyObject *obj, struct maybe_idna *data)
data->buf = PyByteArray_AsString(obj);
len = PyByteArray_Size(obj);
}
- else if (PyUnicode_Check(obj) && PyUnicode_READY(obj) == 0 && PyUnicode_IS_COMPACT_ASCII(obj)) {
- data->buf = PyUnicode_DATA(obj);
- len = PyUnicode_GET_LENGTH(obj);
- }
- else {
- obj2 = PyUnicode_FromObject(obj);
- if (!obj2) {
- PyErr_Format(PyExc_TypeError, "string or unicode text buffer expected, not %s",
- obj->ob_type->tp_name);
- return 0;
- }
- obj3 = PyUnicode_AsEncodedString(obj2, "idna", NULL);
- Py_DECREF(obj2);
- if (!obj3) {
- PyErr_SetString(PyExc_TypeError, "encoding of hostname failed");
- return 0;
+ else if (PyUnicode_Check(obj)) {
+ if (PyUnicode_READY(obj) == 0 && PyUnicode_IS_COMPACT_ASCII(obj)) {
+ data->buf = PyUnicode_DATA(obj);
+ len = PyUnicode_GET_LENGTH(obj);
}
- if (!PyBytes_Check(obj3)) {
- Py_DECREF(obj3);
- PyErr_SetString(PyExc_TypeError, "encoding of hostname failed to return bytes");
- return 0;
+ else {
+ obj2 = PyUnicode_AsEncodedString(obj, "idna", NULL);
+ if (!obj2) {
+ PyErr_SetString(PyExc_TypeError, "encoding of hostname failed");
+ return 0;
+ }
+ assert(PyBytes_Check(obj2));
+ data->obj = obj2;
+ data->buf = PyBytes_AS_STRING(obj2);
+ len = PyBytes_GET_SIZE(obj2);
}
- data->obj = obj3;
- data->buf = PyBytes_AS_STRING(obj3);
- len = PyBytes_GET_SIZE(obj3);
+ }
+ else {
+ PyErr_Format(PyExc_TypeError, "str, bytes or bytearray expected, not %s",
+ obj->ob_type->tp_name);
+ return 0;
}
if (strlen(data->buf) != len) {
Py_CLEAR(data->obj);
@@ -2458,13 +2458,26 @@ sock_setsockopt(PySocketSockObject *s, PyObject *args)
if (!PyArg_ParseTuple(args, "iiy*:setsockopt",
&level, &optname, &optval))
return NULL;
+#ifdef MS_WINDOWS
+ if (optval.len > INT_MAX) {
+ PyBuffer_Release(&optval);
+ PyErr_Format(PyExc_OverflowError,
+ "socket option is larger than %i bytes",
+ INT_MAX);
+ return NULL;
+ }
+ res = setsockopt(s->sock_fd, level, optname,
+ optval.buf, (int)optval.len);
+#else
res = setsockopt(s->sock_fd, level, optname, optval.buf, optval.len);
+#endif
PyBuffer_Release(&optval);
}
- if (res < 0)
+ if (res < 0) {
return s->errorhandler();
- Py_INCREF(Py_None);
- return Py_None;
+ }
+
+ Py_RETURN_NONE;
}
PyDoc_STRVAR(setsockopt_doc,
@@ -2563,17 +2576,22 @@ static PyObject *
sock_close(PySocketSockObject *s)
{
SOCKET_T fd;
+ int res;
- /* We do not want to retry upon EINTR: see http://lwn.net/Articles/576478/
- * and http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
- * for more details.
- */
fd = s->sock_fd;
if (fd != INVALID_SOCKET) {
s->sock_fd = INVALID_SOCKET;
+
+ /* We do not want to retry upon EINTR: see
+ http://lwn.net/Articles/576478/ and
+ http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
+ for more details. */
Py_BEGIN_ALLOW_THREADS
- (void) SOCKETCLOSE(fd);
+ res = SOCKETCLOSE(fd);
Py_END_ALLOW_THREADS
+ if (res < 0) {
+ return s->errorhandler();
+ }
}
Py_INCREF(Py_None);
return Py_None;
@@ -4035,6 +4053,17 @@ sock_ioctl(PySocketSockObject *s, PyObject *arg)
return set_error();
}
return PyLong_FromUnsignedLong(recv); }
+#if defined(SIO_LOOPBACK_FAST_PATH)
+ case SIO_LOOPBACK_FAST_PATH: {
+ unsigned int option;
+ if (!PyArg_ParseTuple(arg, "kI:ioctl", &cmd, &option))
+ return NULL;
+ if (WSAIoctl(s->sock_fd, cmd, &option, sizeof(option),
+ NULL, 0, &recv, NULL, NULL) == SOCKET_ERROR) {
+ return set_error();
+ }
+ return PyLong_FromUnsignedLong(recv); }
+#endif
default:
PyErr_Format(PyExc_ValueError, "invalid ioctl command %d", cmd);
return NULL;
@@ -4045,7 +4074,8 @@ PyDoc_STRVAR(sock_ioctl_doc,
\n\
Control the socket with WSAIoctl syscall. Currently supported 'cmd' values are\n\
SIO_RCVALL: 'option' must be one of the socket.RCVALL_* constants.\n\
-SIO_KEEPALIVE_VALS: 'option' is a tuple of (onoff, timeout, interval).");
+SIO_KEEPALIVE_VALS: 'option' is a tuple of (onoff, timeout, interval).\n\
+SIO_LOOPBACK_FAST_PATH: 'option' is a boolean value, and is disabled by default");
#endif
#if defined(MS_WINDOWS)
@@ -4164,22 +4194,45 @@ static PyGetSetDef sock_getsetlist[] = {
First close the file description. */
static void
-sock_dealloc(PySocketSockObject *s)
+sock_finalize(PySocketSockObject *s)
{
+ SOCKET_T fd;
+ PyObject *error_type, *error_value, *error_traceback;
+
+ /* Save the current exception, if any. */
+ PyErr_Fetch(&error_type, &error_value, &error_traceback);
+
if (s->sock_fd != INVALID_SOCKET) {
- PyObject *exc, *val, *tb;
- Py_ssize_t old_refcount = Py_REFCNT(s);
- ++Py_REFCNT(s);
- PyErr_Fetch(&exc, &val, &tb);
- if (PyErr_WarnFormat(PyExc_ResourceWarning, 1,
- "unclosed %R", s))
+ if (PyErr_ResourceWarning((PyObject *)s, 1, "unclosed %R", s)) {
/* Spurious errors can appear at shutdown */
- if (PyErr_ExceptionMatches(PyExc_Warning))
- PyErr_WriteUnraisable((PyObject *) s);
- PyErr_Restore(exc, val, tb);
- (void) SOCKETCLOSE(s->sock_fd);
- Py_REFCNT(s) = old_refcount;
+ if (PyErr_ExceptionMatches(PyExc_Warning)) {
+ PyErr_WriteUnraisable((PyObject *)s);
+ }
+ }
+
+ /* Only close the socket *after* logging the ResourceWarning warning
+ to allow the logger to call socket methods like
+ socket.getsockname(). If the socket is closed before, socket
+ methods fails with the EBADF error. */
+ fd = s->sock_fd;
+ s->sock_fd = INVALID_SOCKET;
+
+ /* We do not want to retry upon EINTR: see sock_close() */
+ Py_BEGIN_ALLOW_THREADS
+ (void) SOCKETCLOSE(fd);
+ Py_END_ALLOW_THREADS
}
+
+ /* Restore the saved exception. */
+ PyErr_Restore(error_type, error_value, error_traceback);
+}
+
+static void
+sock_dealloc(PySocketSockObject *s)
+{
+ if (PyObject_CallFinalizerFromDealloc((PyObject *)s) < 0)
+ return;
+
Py_TYPE(s)->tp_free((PyObject *)s);
}
@@ -4396,7 +4449,8 @@ static PyTypeObject sock_type = {
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
+ | Py_TPFLAGS_HAVE_FINALIZE, /* tp_flags */
sock_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
@@ -4416,6 +4470,15 @@ static PyTypeObject sock_type = {
PyType_GenericAlloc, /* tp_alloc */
sock_new, /* tp_new */
PyObject_Del, /* tp_free */
+ 0, /* tp_is_gc */
+ 0, /* tp_bases */
+ 0, /* tp_mro */
+ 0, /* tp_cache */
+ 0, /* tp_subclasses */
+ 0, /* tp_weaklist */
+ 0, /* tp_del */
+ 0, /* tp_version_tag */
+ (destructor)sock_finalize, /* tp_finalize */
};
@@ -5451,10 +5514,6 @@ socket_inet_ntop(PyObject *self, PyObject *args)
} else {
return PyUnicode_FromString(retval);
}
-
- /* NOTREACHED */
- PyErr_SetString(PyExc_RuntimeError, "invalid handling of inet_ntop");
- return NULL;
}
#elif defined(MS_WINDOWS)
@@ -6188,9 +6247,6 @@ PyInit__socket(void)
PyModule_AddIntMacro(m, AF_UNSPEC);
#endif
PyModule_AddIntMacro(m, AF_INET);
-#ifdef AF_INET6
- PyModule_AddIntMacro(m, AF_INET6);
-#endif /* AF_INET6 */
#if defined(AF_UNIX)
PyModule_AddIntMacro(m, AF_UNIX);
#endif /* AF_UNIX */
@@ -6439,7 +6495,10 @@ PyInit__socket(void)
PyModule_AddIntMacro(m, SOCK_STREAM);
PyModule_AddIntMacro(m, SOCK_DGRAM);
/* We have incomplete socket support. */
+#ifdef SOCK_RAW
+ /* SOCK_RAW is marked as optional in the POSIX specification */
PyModule_AddIntMacro(m, SOCK_RAW);
+#endif
PyModule_AddIntMacro(m, SOCK_SEQPACKET);
#if defined(SOCK_RDM)
PyModule_AddIntMacro(m, SOCK_RDM);
@@ -6482,9 +6541,11 @@ PyInit__socket(void)
#ifdef SO_OOBINLINE
PyModule_AddIntMacro(m, SO_OOBINLINE);
#endif
+#ifndef __GNU__
#ifdef SO_REUSEPORT
PyModule_AddIntMacro(m, SO_REUSEPORT);
#endif
+#endif
#ifdef SO_SNDBUF
PyModule_AddIntMacro(m, SO_SNDBUF);
#endif
@@ -6521,6 +6582,12 @@ PyInit__socket(void)
#ifdef LOCAL_PEERCRED
PyModule_AddIntMacro(m, LOCAL_PEERCRED);
#endif
+#ifdef SO_PASSSEC
+ PyModule_AddIntMacro(m, SO_PASSSEC);
+#endif
+#ifdef SO_PEERSEC
+ PyModule_AddIntMacro(m, SO_PEERSEC);
+#endif
#ifdef SO_BINDTODEVICE
PyModule_AddIntMacro(m, SO_BINDTODEVICE);
#endif
@@ -6530,6 +6597,12 @@ PyInit__socket(void)
#ifdef SO_MARK
PyModule_AddIntMacro(m, SO_MARK);
#endif
+#ifdef SO_DOMAIN
+ PyModule_AddIntMacro(m, SO_DOMAIN);
+#endif
+#ifdef SO_PROTOCOL
+ PyModule_AddIntMacro(m, SO_PROTOCOL);
+#endif
/* Maximum number of connections for "listen" */
#ifdef SOMAXCONN
@@ -7225,8 +7298,16 @@ PyInit__socket(void)
#ifdef SIO_RCVALL
{
- DWORD codes[] = {SIO_RCVALL, SIO_KEEPALIVE_VALS};
- const char *names[] = {"SIO_RCVALL", "SIO_KEEPALIVE_VALS"};
+ DWORD codes[] = {SIO_RCVALL, SIO_KEEPALIVE_VALS,
+#if defined(SIO_LOOPBACK_FAST_PATH)
+ SIO_LOOPBACK_FAST_PATH
+#endif
+ };
+ const char *names[] = {"SIO_RCVALL", "SIO_KEEPALIVE_VALS",
+#if defined(SIO_LOOPBACK_FAST_PATH)
+ "SIO_LOOPBACK_FAST_PATH"
+#endif
+ };
int i;
for(i = 0; i<Py_ARRAY_LENGTH(codes); ++i) {
PyObject *tmp;