[PATCH] Teach Python 2.5.1 to grok SSM multicast APIs

Alexander Botero-Lowry alex at foxybanana.com
Tue Apr 8 02:14:31 UTC 2008


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 at freebsd.org mailing list
> http://lists.freebsd.org/mailman/listinfo/freebsd-python
> To unsubscribe, send any mail to "freebsd-python-unsubscribe at freebsd.org"



More information about the freebsd-python mailing list