[PATCH] Teach Python 2.5.1 to grok SSM multicast APIs

Bruce M Simpson bms at incunabulum.net
Mon Apr 7 20:23:46 UTC 2008


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
-------------- next part --------------
--- 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);


More information about the freebsd-python mailing list