diff --git a/Lib/socket.py b/Lib/socket.py index bd0bfd7db48..c351a91cc2b 100644 --- a/Lib/socket.py +++ b/Lib/socket.py @@ -21,6 +21,8 @@ htons(), htonl() -- convert 16, 32 bit int from host to network byte order inet_aton() -- convert IP addr string (123.45.67.89) to 32-bit packed format inet_ntoa() -- convert 32-bit packed format IP to string (123.45.67.89) ssl() -- secure socket layer support (only available if configured) +socket.getdefaulttimeout() -- get the default timeout value +socket.setdefaulttimeout() -- set the default timeout value [*] not available on all platforms! diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index c9ef5d69958..b9b9db69ead 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -297,6 +297,36 @@ class GeneralModuleTests(unittest.TestCase): except socket.error: pass + def testDefaultTimeout(self): + """Testing default timeout.""" + # The default timeout should initially be None + self.assertEqual(socket.getdefaulttimeout(), None) + s = socket.socket() + self.assertEqual(s.gettimeout(), None) + s.close() + + # Set the default timeout to 10, and see if it propagates + socket.setdefaulttimeout(10) + self.assertEqual(socket.getdefaulttimeout(), 10) + s = socket.socket() + self.assertEqual(s.gettimeout(), 10) + s.close() + + # Reset the default timeout to None, and see if it propagates + socket.setdefaulttimeout(None) + self.assertEqual(socket.getdefaulttimeout(), None) + s = socket.socket() + self.assertEqual(s.gettimeout(), None) + s.close() + + # Check that setting it to an invalid value raises ValueError + self.assertRaises(ValueError, socket.setdefaulttimeout, -1) + + # Check that setting it to an invalid type raises TypeError + self.assertRaises(TypeError, socket.setdefaulttimeout, "spam") + + # XXX The following three don't test module-level functionality... + def testSockName(self): """Testing getsockname().""" sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 5314dcfc213..9a3951681d5 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -35,6 +35,8 @@ Module interface: - socket.AF_INET, socket.SOCK_STREAM, etc.: constants from - socket.inet_aton(IP address) -> 32-bit packed IP representation - socket.inet_ntoa(packed IP) -> IP address string +- socket.getdefaulttimeout() -> None | float +- socket.setdefaulttimeout(None | float) - an Internet socket address is a pair (hostname, port) where hostname can be anything recognized by gethostbyname() (including the dd.dd.dd.dd notation) and port is in host byte order @@ -521,6 +523,8 @@ internal_select(PySocketSockObject *s, int writing) /* Initialize a new socket object. */ +static float defaulttimeout = -1.0; /* Default timeout for new sockets */ + static void init_sockobject(PySocketSockObject *s, SOCKET_T fd, int family, int type, int proto) @@ -532,9 +536,13 @@ init_sockobject(PySocketSockObject *s, s->sock_family = family; s->sock_type = type; s->sock_proto = proto; - s->sock_timeout = -1.0; /* Start without timeout */ + s->sock_timeout = defaulttimeout; s->errorhandler = &set_error; + + if (defaulttimeout >= 0.0) + internal_setblocking(s, 0); + #ifdef RISCOS if (taskwindow) socketioctl(s->sock_fd, 0x80046679, (u_long*)&block); @@ -2725,6 +2733,58 @@ PyDoc_STRVAR(getnameinfo_doc, \n\ Get host and port for a sockaddr."); + +/* Python API to getting and setting the default timeout value. */ + +static PyObject * +socket_getdefaulttimeout(PyObject *self) +{ + if (defaulttimeout < 0.0) { + Py_INCREF(Py_None); + return Py_None; + } + else + return PyFloat_FromDouble(defaulttimeout); +} + +PyDoc_STRVAR(getdefaulttimeout_doc, +"socket.getdefaulttimeout() -> None | float\n\ +\n\ +Returns the default timeout in floating seconds for new socket objects.\n\ +A value of None indicates that new socket objects have no timeout.\n\ +When the socket module is first imported, the default is None."); + +static PyObject * +socket_setdefaulttimeout(PyObject *self, PyObject *arg) +{ + double timeout; + + if (arg == Py_None) + timeout = -1.0; + else { + timeout = PyFloat_AsDouble(arg); + if (timeout < 0.0) { + if (!PyErr_Occurred()) + PyErr_SetString(PyExc_ValueError, + "Timeout value out of range"); + return NULL; + } + } + + defaulttimeout = timeout; + + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(setdefaulttimeout_doc, +"socket.setdefaulttimeout(None | float)\n\ +\n\ +Set the default timeout in floating seconds for new socket objects.\n\ +A value of None indicates that new socket objects have no timeout.\n\ +When the socket module is first imported, the default is None."); + + /* List of functions exported by this module. */ static PyMethodDef socket_methods[] = { @@ -2760,6 +2820,10 @@ static PyMethodDef socket_methods[] = { METH_VARARGS, getaddrinfo_doc}, {"getnameinfo", socket_getnameinfo, METH_VARARGS, getnameinfo_doc}, + {"getdefaulttimeout", socket_getdefaulttimeout, + METH_NOARGS, getdefaulttimeout_doc}, + {"setdefaulttimeout", socket_setdefaulttimeout, + METH_O, setdefaulttimeout_doc}, {NULL, NULL} /* Sentinel */ };