Since I can't re-open issue 3372, I'm opening a new issue. socket.setsockopt() still sets an optlen of '4' in the setsockopt() system call for options IP_MULTICAST_TTL and IP_MULTICAST_LOOP. On OpenBSD, this causes the kernel to hit an error condition and set errno 22 when these options are set:
socket.error: (22, 'Invalid argument')
According to both FreeBSD and OpenBSD manual pages (see e.g. http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man4/ip.4), these fields are in fact both 8 bit unsigned, and the manuals suggest the following:
u_char ttl; /* range: 0 to 255, default = 1 */
setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl));
The following updated patch for branch "2.7" passes a shorter "optlen" for certain Multicast options, it was tested on OpenBSD, Linux and OSX and was initially proposed by niallo:
diff -r 88de50c1696b Modules/socketmodule.c
--- a/Modules/socketmodule.c Sun Dec 28 18:51:25 2014 +0200
+++ b/Modules/socketmodule.c Mon Dec 29 08:27:24 2014 -0500
@@ -1879,26 +1879,29 @@
static PyObject *
sock_setsockopt(PySocketSockObject *s, PyObject *args)
{
int level;
int optname;
int res;
char *buf;
int buflen;
int flag;
if (PyArg_ParseTuple(args, "iii:setsockopt",
&level, &optname, &flag)) {
+ buflen = sizeof flag;
+ /* Multicast options take shorter arguments */
+ if (optname == IP_MULTICAST_TTL || optname == IP_MULTICAST_LOOP)
+ buflen = sizeof(u_char);
buf = (char *) &flag;
- buflen = sizeof flag;
}
else {
PyErr_Clear();
if (!PyArg_ParseTuple(args, "iis#:setsockopt",
&level, &optname, &buf, &buflen))
return NULL;
}
res = setsockopt(s->sock_fd, level, optname, (void *)buf, buflen);
if (res < 0)
return s->errorhandler();
Py_INCREF(Py_None);
return Py_None;
|