mirror of
https://github.com/python/cpython.git
synced 2025-12-31 04:23:37 +00:00
gh-107545: Fix misleading setsockopt() error messages (GH-107546)
This commit is contained in:
parent
7f416c8674
commit
a50822ff94
3 changed files with 98 additions and 31 deletions
|
|
@ -1538,6 +1538,40 @@ def testSetSockOpt(self):
|
|||
reuse = sock.getsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR)
|
||||
self.assertFalse(reuse == 0, "failed to set reuse mode")
|
||||
|
||||
def test_setsockopt_errors(self):
|
||||
# See issue #107546.
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.addCleanup(sock.close)
|
||||
|
||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # No error expected.
|
||||
|
||||
with self.assertRaises(OverflowError):
|
||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 2 ** 100)
|
||||
|
||||
with self.assertRaises(OverflowError):
|
||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, - 2 ** 100)
|
||||
|
||||
with self.assertRaises(OverflowError):
|
||||
sock.setsockopt(socket.SOL_SOCKET, 2 ** 100, 1)
|
||||
|
||||
with self.assertRaises(OverflowError):
|
||||
sock.setsockopt(2 ** 100, socket.SO_REUSEADDR, 1)
|
||||
|
||||
with self.assertRaisesRegex(TypeError, "socket option should be int, bytes-like object or None"):
|
||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, dict())
|
||||
|
||||
with self.assertRaisesRegex(TypeError, "requires 4 arguments when the third argument is None"):
|
||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, None)
|
||||
|
||||
with self.assertRaisesRegex(TypeError, "only takes 4 arguments when the third argument is None"):
|
||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1, 2)
|
||||
|
||||
with self.assertRaisesRegex(TypeError, "takes at least 3 arguments"):
|
||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR)
|
||||
|
||||
with self.assertRaisesRegex(TypeError, "takes at most 4 arguments"):
|
||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1, 2, 3)
|
||||
|
||||
def testSendAfterClose(self):
|
||||
# testing send() after close() with timeout
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
Improve the error messages that may be raised by
|
||||
:meth:`~socket.socket.setsockopt`.
|
||||
|
|
@ -3332,32 +3332,59 @@ sock_setsockopt(PyObject *self, PyObject *args)
|
|||
{
|
||||
PySocketSockObject *s = _PySocketSockObject_CAST(self);
|
||||
|
||||
Py_ssize_t arglen;
|
||||
int level;
|
||||
int optname;
|
||||
int res;
|
||||
Py_buffer optval;
|
||||
Py_buffer buffer;
|
||||
int flag;
|
||||
unsigned int optlen;
|
||||
PyObject *none;
|
||||
PyObject *optval;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "iiO|I:setsockopt",
|
||||
&level, &optname, &optval, &optlen))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
arglen = PyTuple_Size(args);
|
||||
if (arglen == 3 && optval == Py_None) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"setsockopt() requires 4 arguments when the third argument is None",
|
||||
arglen);
|
||||
return NULL;
|
||||
}
|
||||
if (arglen == 4 && optval != Py_None) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"setsockopt() only takes 4 arguments when the third argument is None (got %T)",
|
||||
optval);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef AF_VSOCK
|
||||
if (s->sock_family == AF_VSOCK) {
|
||||
if (!PyIndex_Check(optval)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"setsockopt() argument 3 for AF_VSOCK must be an int (got %T)",
|
||||
optval);
|
||||
}
|
||||
uint64_t vflag; // Must be set width of 64 bits
|
||||
/* setsockopt(level, opt, flag) */
|
||||
if (PyArg_ParseTuple(args, "iiK:setsockopt",
|
||||
&level, &optname, &vflag)) {
|
||||
// level should always be set to AF_VSOCK
|
||||
res = setsockopt(get_sock_fd(s), level, optname,
|
||||
(void*)&vflag, sizeof vflag);
|
||||
goto done;
|
||||
if (!PyArg_Parse(optval, "K", &vflag)) {
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
// level should always be set to AF_VSOCK
|
||||
res = setsockopt(get_sock_fd(s), level, optname,
|
||||
(void*)&vflag, sizeof vflag);
|
||||
goto done;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* setsockopt(level, opt, flag) */
|
||||
if (PyArg_ParseTuple(args, "iii:setsockopt",
|
||||
&level, &optname, &flag)) {
|
||||
if (PyIndex_Check(optval)) {
|
||||
if (!PyArg_Parse(optval, "i", &flag)) {
|
||||
return NULL;
|
||||
}
|
||||
#ifdef MS_WINDOWS
|
||||
if (optname == SIO_TCP_SET_ACK_FREQUENCY) {
|
||||
DWORD dummy;
|
||||
|
|
@ -3374,36 +3401,40 @@ sock_setsockopt(PyObject *self, PyObject *args)
|
|||
goto done;
|
||||
}
|
||||
|
||||
PyErr_Clear();
|
||||
/* setsockopt(level, opt, None, flag) */
|
||||
if (PyArg_ParseTuple(args, "iiO!I:setsockopt",
|
||||
&level, &optname, Py_TYPE(Py_None), &none, &optlen)) {
|
||||
/* setsockopt(level, opt, None, optlen) */
|
||||
if (optval == Py_None) {
|
||||
assert(sizeof(socklen_t) >= sizeof(unsigned int));
|
||||
res = setsockopt(get_sock_fd(s), level, optname,
|
||||
NULL, (socklen_t)optlen);
|
||||
goto done;
|
||||
}
|
||||
|
||||
PyErr_Clear();
|
||||
/* setsockopt(level, opt, buffer) */
|
||||
if (!PyArg_ParseTuple(args, "iiy*:setsockopt",
|
||||
&level, &optname, &optval))
|
||||
return NULL;
|
||||
|
||||
if (PyObject_CheckBuffer(optval)) {
|
||||
if (!PyArg_Parse(optval, "y*", &buffer)) {
|
||||
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(get_sock_fd(s), level, optname,
|
||||
optval.buf, (int)optval.len);
|
||||
if (buffer.len > INT_MAX) {
|
||||
PyBuffer_Release(&buffer);
|
||||
PyErr_Format(PyExc_OverflowError,
|
||||
"socket option is larger than %i bytes",
|
||||
INT_MAX);
|
||||
return NULL;
|
||||
}
|
||||
res = setsockopt(get_sock_fd(s), level, optname,
|
||||
buffer.buf, (int)buffer.len);
|
||||
#else
|
||||
res = setsockopt(get_sock_fd(s), level, optname, optval.buf, optval.len);
|
||||
res = setsockopt(get_sock_fd(s), level, optname, buffer.buf, buffer.len);
|
||||
#endif
|
||||
PyBuffer_Release(&optval);
|
||||
PyBuffer_Release(&buffer);
|
||||
goto done;
|
||||
}
|
||||
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"socket option should be int, bytes-like object or None (got %T)",
|
||||
optval);
|
||||
return NULL;
|
||||
|
||||
done:
|
||||
if (res < 0) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue