Skip to content

Commit 543c20b

Browse files
committed
Simplify error checking implementation for setsockopt
1 parent ca87487 commit 543c20b

File tree

2 files changed

+29
-37
lines changed

2 files changed

+29
-37
lines changed

Lib/test/test_socket.py

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1557,22 +1557,21 @@ def test_setsockopt_errors(self):
15571557
with self.assertRaises(OverflowError):
15581558
sock.setsockopt(2 ** 100, socket.SO_REUSEADDR, 1)
15591559

1560-
msg = "socket option should be should be integer, bytes-like object or None"
1561-
with self.assertRaises(TypeError, msg=msg):
1560+
with self.assertRaisesRegex(TypeError, "socket option should be int, bytes-like object or None"):
15621561
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, dict())
15631562

1564-
msg = "setsockopt() takes 3 or 4 arguments (2 given)"
1565-
with self.assertRaises(TypeError, msg=msg):
1566-
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR)
1567-
1568-
msg = "setsockopt() take 4 arguments when socket option is None (3 given)"
1569-
with self.assertRaises(TypeError, msg=msg):
1563+
with self.assertRaisesRegex(TypeError, "take 4 arguments when socket option is None"):
15701564
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, None)
15711565

1572-
msg = "setsockopt() argument 3 must be NoneType, not int"
1573-
with self.assertRaises(TypeError, msg=msg):
1566+
with self.assertRaisesRegex(TypeError, "argument 3 must be NoneType"):
15741567
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1, 2)
15751568

1569+
with self.assertRaisesRegex(TypeError, "takes at least 3 arguments"):
1570+
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR)
1571+
1572+
with self.assertRaisesRegex(TypeError, "takes at most 4 arguments"):
1573+
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1, 2, 3)
1574+
15761575
def testSendAfterClose(self):
15771576
# testing send() after close() with timeout
15781577
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:

Modules/socketmodule.c

Lines changed: 20 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3341,25 +3341,23 @@ sock_setsockopt(PyObject *self, PyObject *args)
33413341
unsigned int optlen;
33423342
PyObject *optval;
33433343

3344+
if (!PyArg_ParseTuple(args, "iiO|I:setsockopt",
3345+
&level, &optname, &optval, &optlen)) {
3346+
return NULL;
3347+
}
3348+
33443349
arglen = PyTuple_Size(args);
3345-
switch (arglen) {
3346-
case 3:
3347-
if (!PyArg_ParseTuple(args, "iiO:setsockopt",
3348-
&level, &optname, &optval)) {
3349-
return NULL;
3350-
}
3351-
break;
3352-
case 4:
3353-
if (!PyArg_ParseTuple(args, "iiO!I:setsockopt",
3354-
&level, &optname, Py_TYPE(Py_None), &optval, &optlen)) {
3355-
return NULL;
3356-
}
3357-
break;
3358-
default:
3359-
PyErr_Format(PyExc_TypeError,
3360-
"setsockopt() takes 3 or 4 arguments (%zd given)",
3361-
arglen);
3362-
return NULL;
3350+
if (arglen == 3 && optval == Py_None) {
3351+
PyErr_Format(PyExc_TypeError,
3352+
"setsockopt() take 4 arguments when socket option is None (%zd given)",
3353+
arglen);
3354+
return NULL;
3355+
}
3356+
if (arglen == 4 && optval != Py_None) {
3357+
PyErr_Format(PyExc_TypeError,
3358+
"setsockopt() argument 3 must be NoneType, not %s",
3359+
Py_TYPE(optval)->tp_name);
3360+
return NULL;
33633361
}
33643362

33653363
#ifdef AF_VSOCK
@@ -3397,14 +3395,8 @@ sock_setsockopt(PyObject *self, PyObject *args)
33973395
goto done;
33983396
}
33993397

3400-
/* setsockopt(level, opt, None, flag) */
3398+
/* setsockopt(level, opt, None, optlen) */
34013399
if (optval == Py_None) {
3402-
if (arglen != 4) {
3403-
PyErr_Format(PyExc_TypeError,
3404-
"setsockopt() take 4 arguments when socket option is None (%zd given)",
3405-
arglen);
3406-
return NULL;
3407-
}
34083400
assert(sizeof(socklen_t) >= sizeof(unsigned int));
34093401
res = setsockopt(get_sock_fd(s), level, optname,
34103402
NULL, (socklen_t)optlen);
@@ -3425,7 +3417,7 @@ sock_setsockopt(PyObject *self, PyObject *args)
34253417
return NULL;
34263418
}
34273419
res = setsockopt(get_sock_fd(s), level, optname,
3428-
buffer.buf, (int)buffer.len);
3420+
buffer.buf, (int)buffer.len);
34293421
#else
34303422
res = setsockopt(get_sock_fd(s), level, optname, buffer.buf, buffer.len);
34313423
#endif
@@ -3434,7 +3426,8 @@ sock_setsockopt(PyObject *self, PyObject *args)
34343426
}
34353427

34363428
PyErr_Format(PyExc_TypeError,
3437-
"socket option should be integer, bytes-like object or None");
3429+
"socket option should be int, bytes-like object or None (got %s)",
3430+
Py_TYPE(optval)->tp_name);
34383431
return NULL;
34393432

34403433
done:

0 commit comments

Comments
 (0)