Seems like a good idea to submit these upstream. Alex
On Mon, Apr 07, 2008 at 09:08:13PM +0100, Bruce M Simpson wrote: > For folk who are interested in multicast. > > I haven't tested these other than building them, but I believe they're > correct, and they should be crossplatform. > > cheers > BMS > --- 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); > _______________________________________________ > freebsd-python@freebsd.org mailing list > http://lists.freebsd.org/mailman/listinfo/freebsd-python > To unsubscribe, send any mail to "[EMAIL PROTECTED]" _______________________________________________ freebsd-python@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-python To unsubscribe, send any mail to "[EMAIL PROTECTED]"