Skip to content

Commit ca87487

Browse files
committed
Add clearer error messages to setsockopt
1 parent e3d4e74 commit ca87487

File tree

2 files changed

+53
-17
lines changed

2 files changed

+53
-17
lines changed

Lib/test/test_socket.py

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

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

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):
1570+
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, None)
1571+
1572+
msg = "setsockopt() argument 3 must be NoneType, not int"
1573+
with self.assertRaises(TypeError, msg=msg):
1574+
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1, 2)
1575+
15631576
def testSendAfterClose(self):
15641577
# testing send() after close() with timeout
15651578
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:

Modules/socketmodule.c

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3332,24 +3332,41 @@ sock_setsockopt(PyObject *self, PyObject *args)
33323332
{
33333333
PySocketSockObject *s = _PySocketSockObject_CAST(self);
33343334

3335+
Py_ssize_t arglen;
33353336
int level;
33363337
int optname;
33373338
int res;
3338-
Py_buffer optval;
3339+
Py_buffer buffer;
33393340
int flag;
33403341
unsigned int optlen;
3341-
PyObject *type;
3342+
PyObject *optval;
33423343

3343-
if (!PyArg_ParseTuple(args, "iiO|I:setsockopt",
3344-
&level, &optname, &type, &optlen)) {
3345-
return NULL;
3344+
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;
33463363
}
33473364

33483365
#ifdef AF_VSOCK
33493366
if (s->sock_family == AF_VSOCK) {
33503367
uint64_t vflag; // Must be set width of 64 bits
33513368
/* setsockopt(level, opt, flag) */
3352-
if (!PyArg_Parse(type, "K", &vflag)) {
3369+
if (!PyArg_Parse(optval, "K", &vflag)) {
33533370
return NULL;
33543371
}
33553372
// level should always be set to AF_VSOCK
@@ -3360,8 +3377,8 @@ sock_setsockopt(PyObject *self, PyObject *args)
33603377
#endif
33613378

33623379
/* setsockopt(level, opt, flag) */
3363-
if (PyIndex_Check(type)) {
3364-
if (!PyArg_Parse(type, "i", &flag)) {
3380+
if (PyIndex_Check(optval)) {
3381+
if (!PyArg_Parse(optval, "i", &flag)) {
33653382
return NULL;
33663383
}
33673384
#ifdef MS_WINDOWS
@@ -3381,32 +3398,38 @@ sock_setsockopt(PyObject *self, PyObject *args)
33813398
}
33823399

33833400
/* setsockopt(level, opt, None, flag) */
3384-
if (type == Py_None) {
3401+
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+
}
33853408
assert(sizeof(socklen_t) >= sizeof(unsigned int));
33863409
res = setsockopt(get_sock_fd(s), level, optname,
33873410
NULL, (socklen_t)optlen);
33883411
goto done;
33893412
}
33903413

33913414
/* setsockopt(level, opt, buffer) */
3392-
if (PyObject_CheckBuffer(type)) {
3393-
if (!PyArg_Parse(type, "y*", &optval)) {
3415+
if (PyObject_CheckBuffer(optval)) {
3416+
if (!PyArg_Parse(optval, "y*", &buffer)) {
33943417
return NULL;
33953418
}
33963419
#ifdef MS_WINDOWS
3397-
if (optval.len > INT_MAX) {
3398-
PyBuffer_Release(&optval);
3420+
if (buffer.len > INT_MAX) {
3421+
PyBuffer_Release(&buffer);
33993422
PyErr_Format(PyExc_OverflowError,
34003423
"socket option is larger than %i bytes",
34013424
INT_MAX);
34023425
return NULL;
34033426
}
34043427
res = setsockopt(get_sock_fd(s), level, optname,
3405-
optval.buf, (int)optval.len);
3428+
buffer.buf, (int)buffer.len);
34063429
#else
3407-
res = setsockopt(get_sock_fd(s), level, optname, optval.buf, optval.len);
3430+
res = setsockopt(get_sock_fd(s), level, optname, buffer.buf, buffer.len);
34083431
#endif
3409-
PyBuffer_Release(&optval);
3432+
PyBuffer_Release(&buffer);
34103433
goto done;
34113434
}
34123435

0 commit comments

Comments
 (0)