--- Python-2.5.1/configure.in.orig 2008-04-07 20:44:21.000000000 +0100 +++ Python-2.5.1/configure.in 2008-04-07 20:47:50.000000000 +0100 @@ -2267,12 +2267,15 @@ AC_CHECK_FUNCS(alarm bind_textdomain_codeset chown clock confstr ctermid \ execv fork fpathconf ftime ftruncate \ gai_strerror getgroups getlogin getloadavg getpeername getpgid getpid \ - getpriority getpwent getspnam getspent getsid getwd \ + getpriority getpwent getspnam getspent getsid \ + getsourcefilter \ + getwd \ kill killpg lchown lstat mkfifo mknod mktime \ mremap nice pathconf pause plock poll pthread_init \ putenv readlink realpath \ select setegid seteuid setgid \ setlocale setregid setreuid setsid setpgid setpgrp setuid setvbuf snprintf \ + setsourcefilter \ sigaction siginterrupt sigrelse strftime \ sysconf tcgetpgrp tcsetpgrp tempnam timegm times tmpfile tmpnam tmpnam_r \ truncate uname unsetenv utimes waitpid wait3 wait4 wcscoll _getpty) --- Python-2.5.1/Modules/socketmodule.c.orig 2008-04-07 18:04:28.000000000 +0100 +++ Python-2.5.1/Modules/socketmodule.c 2008-04-07 20:50:02.000000000 +0100 @@ -100,6 +100,7 @@ getpeername() -- return remote address [*]\n\ getsockname() -- return local address\n\ getsockopt(level, optname[, buflen]) -- get socket options\n\ +getsourcefilter(ifindex, group) -- get multicast source filter list\n\ gettimeout() -- return timeout or None\n\ listen(n) -- start listening for incoming connections\n\ makefile([mode, [bufsize]]) -- return a file object for the socket [*]\n\ @@ -113,6 +114,8 @@ sendto(data[, flags], addr) -- send data to a given address\n\ setblocking(0 | 1) -- set or clear the blocking I/O flag\n\ setsockopt(level, optname, value) -- set socket options\n\ +setsourcefilter(ifindex, group, mode, sources) -- set multicast source\n\ + filter list\n\ settimeout(None | float) -- set or clear the timeout\n\ shutdown(how) -- shut down traffic in one or both directions\n\ \n\ @@ -1807,6 +1810,191 @@ If a nonzero buffersize argument is given, the return value is a\n\ string of that length; otherwise it is an integer."); +/* s.setsourcefilter() method. + set the multicast source filters on s, for the interface index and + group provided, to the given mode and source list. + */ + +static PyObject * +sock_setsourcefilter(PySocketSockObject *s, PyObject *args) +{ +#ifndef HAVE_SETSOURCEFILTER + /* We have no SSM socket support. */ + PyErr_SetString(socket_error, "setsourcefilter not supported"); + return NULL; +#else + unsigned int ifindex; + PyObject* gaddro; + unsigned int fmode; + PyObject* slisto; + sock_addr_t gaddrbuf; + int gaddrlen; + unsigned int numsrc; + void *srcvec; + int res; + + if (!PyArg_ParseTuple(args, "IOIO!:setsourcefilter", + &ifindex, &gaddro, &fmode, + &PyList_Type, &slisto)) + return NULL; + + if (!getsockaddrarg(s, gaddro, SAS2SA(&gaddrbuf), &gaddrlen)) + return NULL; + + srcvec = NULL; + numsrc = PyList_Size(slisto); + if (numsrc > 0) { + PyObject* saddro; + sock_addr_t saddrbuf; + int saddrlen; + struct sockaddr_storage *ssp; + int i; + + srcvec = PyMem_Malloc(numsrc * + sizeof(struct sockaddr_storage)); + if (srcvec == NULL) + return PyErr_NoMemory(); + + ssp = (struct sockaddr_storage *)srcvec; + for (i = 0; i < numsrc; i++) { + saddro = PyList_GetItem(slisto, i); + if (!getsockaddrarg(s, saddro, SAS2SA(&saddrbuf), + &saddrlen)) { + PyMem_Free(srcvec); + return NULL; + } + /* + * sock_addr_t is not guaranteed to be padded + * to sizeof(struct sockaddr_storage), so zero fill + * before copying. + */ + memset(ssp, 0, sizeof(struct sockaddr_storage)); + memcpy(ssp, &saddrbuf, saddrlen); + ssp++; + } + } + res = setsourcefilter(s->sock_fd, ifindex, + SAS2SA(&gaddrbuf), gaddrlen, + fmode, numsrc, srcvec); + if (srcvec != NULL) + PyMem_Free(srcvec); + if (res == -1) + return s->errorhandler(); + + Py_INCREF(Py_None); + return Py_None; +#endif /* HAVE_SETSOURCEFILTER */ +} + +PyDoc_STRVAR(setsourcefilter_doc, +"setsourcefilter(ifindex, group, fmode, [sources])\n\ +\n\ +Set the multicast filter mode and source list on the socket,\n\ +for its membership of the group on the interface with index ifindex.\n\ +The source list may be empty. If the socket is not a member of group,\n\ +a socket.error exception will be raised.\n\ +All supplied addresses must match the address family of the socket.\n\ +To filter IPv4 sources from IPv6 sockets, you must pass the IPv6\n\ +mapped address."); + +/* s.getsourcefilter() method. + get the multicast source filters on s, for the interface index and + group provided. returns a 2-tuple consisting of current filter mode + (integer), and a list of socket addresses. */ + +static PyObject * +sock_getsourcefilter(PySocketSockObject *s, PyObject *args) +{ +#ifndef HAVE_GETSOURCEFILTER + /* We have no SSM socket support. */ + PyErr_SetString(socket_error, "getsourcefilter not supported"); + return NULL; +#else + unsigned int ifindex; + PyObject* gaddro; + sock_addr_t gaddrbuf; + int gaddrlen; + int res; + unsigned int fmode; + unsigned int numsrc; + PyObject* slisto; + PyObject* ret; + + if (!PyArg_ParseTuple(args, "IO:getsourcefilter", + &ifindex, &gaddro)) + return NULL; + + if (!getsockaddrarg(s, gaddro, SAS2SA(&gaddrbuf), &gaddrlen)) + return NULL; + + res = getsourcefilter(s->sock_fd, ifindex, + SAS2SA(&gaddrbuf), gaddrlen, + &fmode, &numsrc, NULL); + if (res == -1) + return s->errorhandler(); + /* + * If there is a source list set on this socket, + * retrieve it. Otherwise we will just return the filter + * mode and an empty list as a tuple. + */ + if (numsrc == 0) { + /* + * Deal with empty lists upfront to make backing out of + * allocations easier. + */ + slisto = PyList_New(0); + } else { + int i; + void *srcvec; + struct sockaddr_storage *ssp; + PyObject* saddro; + + srcvec = PyMem_Malloc(numsrc * + sizeof(struct sockaddr_storage)); + if (srcvec == NULL) + return PyErr_NoMemory(); + + res = getsourcefilter(s->sock_fd, ifindex, + SAS2SA(&gaddrbuf), gaddrlen, + &fmode, &numsrc, srcvec); + if (res == -1) { + PyMem_Free(srcvec); + return s->errorhandler(); + } + /* + * Convert C array of sockaddr_storage to Python + * list of sockaddrs. + */ + slisto = PyList_New(numsrc); + if (slisto == NULL) { + PyMem_Free(srcvec); + return PyErr_NoMemory(); + } + ssp = (struct sockaddr_storage *)srcvec; + for (i = 0; i < numsrc; i++, ssp++) { + saddro = makesockaddr(s->sock_fd, SAS2SA(ssp), + sizeof(*ssp), s->sock_proto); + PyList_SET_ITEM(slisto, i, saddro); + } + PyMem_Free(srcvec); + } + + /* + * Construct the return tuple (fmode, [sources...]). + */ + ret = Py_BuildValue("(IO)", fmode, slisto); + Py_DECREF(slisto); + return ret; +#endif /* HAVE_GETSOURCEFILTER */ +} + +PyDoc_STRVAR(getsourcefilter_doc, +"getsourcefilter(ifindex, group) -> (fmode, sources)\n\ +\n\ +Get the multicast filter mode and source list on the socket,\n\ +for its membership of the group on the interface with index ifindex.\n\ +If the socket is not a member of group, a socket.error exception will\n\ +be raised."); /* s.bind(sockaddr) method */ @@ -2786,6 +2974,12 @@ gettimeout_doc}, {"setsockopt", (PyCFunction)sock_setsockopt, METH_VARARGS, setsockopt_doc}, + {"getsourcefilter", + (PyCFunction)sock_getsourcefilter, METH_VARARGS, + getsourcefilter_doc}, + {"setsourcefilter", + (PyCFunction)sock_setsourcefilter, METH_VARARGS, + setsourcefilter_doc}, {"shutdown", (PyCFunction)sock_shutdown, METH_O, shutdown_doc}, #ifdef RISCOS @@ -4801,6 +4995,53 @@ PyModule_AddIntConstant(m, "IP_MAX_MEMBERSHIPS", IP_MAX_MEMBERSHIPS); #endif + /* RFC 3678 additions to the BSD sockets multicast API. */ +#ifdef IP_ADD_SOURCE_MEMBERSHIP + PyModule_AddIntConstant(m, "IP_ADD_SOURCE_MEMBERSHIP", + IP_ADD_SOURCE_MEMBERSHIP); +#endif +#ifdef IP_DROP_SOURCE_MEMBERSHIP + PyModule_AddIntConstant(m, "IP_DROP_SOURCE_MEMBERSHIP", + IP_DROP_SOURCE_MEMBERSHIP); +#endif +#ifdef IP_BLOCK_SOURCE + PyModule_AddIntConstant(m, "IP_BLOCK_SOURCE", IP_BLOCK_SOURCE); +#endif +#ifdef IP_UNBLOCK_SOURCE + PyModule_AddIntConstant(m, "IP_UNBLOCK_SOURCE", IP_UNBLOCK_SOURCE); +#endif +#ifdef MCAST_JOIN_GROUP + PyModule_AddIntConstant(m, "MCAST_JOIN_GROUP", MCAST_JOIN_GROUP); +#endif +#ifdef MCAST_LEAVE_GROUP + PyModule_AddIntConstant(m, "MCAST_LEAVE_GROUP", MCAST_LEAVE_GROUP); +#endif +#ifdef MCAST_JOIN_SOURCE_GROUP + PyModule_AddIntConstant(m, "MCAST_JOIN_SOURCE_GROUP", + MCAST_JOIN_SOURCE_GROUP); +#endif +#ifdef MCAST_LEAVE_SOURCE_GROUP + PyModule_AddIntConstant(m, "MCAST_LEAVE_SOURCE_GROUP", + MCAST_LEAVE_SOURCE_GROUP); +#endif +#ifdef MCAST_BLOCK_SOURCE + PyModule_AddIntConstant(m, "MCAST_BLOCK_SOURCE", MCAST_BLOCK_SOURCE); +#endif +#ifdef MCAST_UNBLOCK_SOURCE + PyModule_AddIntConstant(m, "MCAST_UNBLOCK_SOURCE", + MCAST_UNBLOCK_SOURCE); +#endif +#ifdef MCAST_EXCLUDE + PyModule_AddIntConstant(m, "MCAST_EXCLUDE", MCAST_EXCLUDE); +#endif +#ifdef MCAST_INCLUDE + PyModule_AddIntConstant(m, "MCAST_INCLUDE", MCAST_INCLUDE); +#endif +#ifdef IP_MAX_SOURCE_FILTER + PyModule_AddIntConstant(m, "IP_MAX_SOURCE_FILTER", + IP_MAX_SOURCE_FILTER); +#endif + /* IPv6 [gs]etsockopt options, defined in RFC2553 */ #ifdef IPV6_JOIN_GROUP PyModule_AddIntConstant(m, "IPV6_JOIN_GROUP", IPV6_JOIN_GROUP);