Issue #1646: Make socket support TIPC. The socket module now has support
for TIPC under Linux, see http://tipc.sf.net/ for more information.
Thanks to Alberto Bertogli for the patch
diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst
index 40e6d19..0e3aa19 100644
--- a/Doc/library/socket.rst
+++ b/Doc/library/socket.rst
@@ -66,6 +66,27 @@
 .. versionadded:: 2.5
    AF_NETLINK sockets are represented as  pairs ``pid, groups``.
 
+.. versionadded:: 2.6
+   Linux-only support for TIPC is also available using the :const:`AF_TIPC`
+   address family. TIPC is an open, non-IP based networked protocol designed
+   for use in clustered computer environments.  Addresses are represented by a
+   tuple, and the fields depend on the address type. The general tuple form is
+   ``(addr_type, v1, v2, v3 [, scope])``, where:
+
+     - *addr_type* is one of TIPC_ADDR_NAMESEQ, TIPC_ADDR_NAME, or
+       TIPC_ADDR_ID.
+     - *scope* is one of TIPC_ZONE_SCOPE, TIPC_CLUSTER_SCOPE, and
+       TIPC_NODE_SCOPE.
+     - If *addr_type* is TIPC_ADDR_NAME, then *v1* is the server type, *v2* is
+       the port identifier, and *v3* should be 0.
+
+       If *addr_type* is TIPC_ADDR_NAMESEQ, then *v1* is the server type, *v2*
+       is the lower port number, and *v3* is the upper port number.
+
+       If *addr_type* is TIPC_ADDR_ID, then *v1* is the node, *v2* is the
+       reference, and *v3* should be set to 0.
+
+
 All errors raise exceptions.  The normal exceptions for invalid argument types
 and out-of-memory conditions can be raised; errors related to socket or address
 semantics raise the error :exc:`socket.error`.
@@ -169,6 +190,12 @@
    
    .. versionadded:: 2.6
 
+.. data:: TIPC_*
+
+   TIPC related constants, matching the ones exported by the C socket API. See
+   the TIPC documentation for more information.
+
+   .. versionadded:: 2.6
 
 .. data:: has_ipv6
 
diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py
index 8f69a40..45f0434 100644
--- a/Lib/test/test_socket.py
+++ b/Lib/test/test_socket.py
@@ -1084,6 +1084,85 @@
         buf = buffer(MSG)
         self.serv_conn.send(buf)
 
+
+TIPC_STYPE = 2000
+TIPC_LOWER = 200
+TIPC_UPPER = 210
+
+def isTipcAvailable():
+    """Check if the TIPC module is loaded
+
+    The TIPC module is not loaded automatically on Ubuntu and probably
+    other Linux distros.
+    """
+    if not hasattr(socket, "AF_TIPC"):
+        return False
+    if not os.path.isfile("/proc/modules"):
+        return False
+    with open("/proc/modules") as f:
+        for line in f:
+            if line.startswith("tipc "):
+                return True
+    if test_support.debug:
+        print "TIPC module is not loaded, please 'sudo modprobe tipc'"
+    return False
+
+class TIPCTest (unittest.TestCase):
+    def testRDM(self):
+        srv = socket.socket(socket.AF_TIPC, socket.SOCK_RDM)
+        cli = socket.socket(socket.AF_TIPC, socket.SOCK_RDM)
+
+        srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+        srvaddr = (socket.TIPC_ADDR_NAMESEQ, TIPC_STYPE,
+                TIPC_LOWER, TIPC_UPPER)
+        srv.bind(srvaddr)
+
+        sendaddr = (socket.TIPC_ADDR_NAME, TIPC_STYPE,
+                TIPC_LOWER + (TIPC_UPPER - TIPC_LOWER) / 2, 0)
+        cli.sendto(MSG, sendaddr)
+
+        msg, recvaddr = srv.recvfrom(1024)
+
+        self.assertEqual(cli.getsockname(), recvaddr)
+        self.assertEqual(msg, MSG)
+
+
+class TIPCThreadableTest (unittest.TestCase, ThreadableTest):
+    def __init__(self, methodName = 'runTest'):
+        unittest.TestCase.__init__(self, methodName = methodName)
+        ThreadableTest.__init__(self)
+
+    def setUp(self):
+        self.srv = socket.socket(socket.AF_TIPC, socket.SOCK_STREAM)
+        self.srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+        srvaddr = (socket.TIPC_ADDR_NAMESEQ, TIPC_STYPE,
+                TIPC_LOWER, TIPC_UPPER)
+        self.srv.bind(srvaddr)
+        self.srv.listen(5)
+        self.serverExplicitReady()
+        self.conn, self.connaddr = self.srv.accept()
+
+    def clientSetUp(self):
+        # The is a hittable race between serverExplicitReady() and the
+        # accept() call; sleep a little while to avoid it, otherwise
+        # we could get an exception
+        time.sleep(0.1)
+        self.cli = socket.socket(socket.AF_TIPC, socket.SOCK_STREAM)
+        addr = (socket.TIPC_ADDR_NAME, TIPC_STYPE,
+                TIPC_LOWER + (TIPC_UPPER - TIPC_LOWER) / 2, 0)
+        self.cli.connect(addr)
+        self.cliaddr = self.cli.getsockname()
+
+    def testStream(self):
+        msg = self.conn.recv(1024)
+        self.assertEqual(msg, MSG)
+        self.assertEqual(self.cliaddr, self.connaddr)
+
+    def _testStream(self):
+        self.cli.send(MSG)
+        self.cli.close()
+
+
 def test_main():
     tests = [GeneralModuleTests, BasicTCPTest, TCPCloserTest, TCPTimeoutTest,
              TestExceptions, BufferIOTest, BasicTCPTest2]
@@ -1105,6 +1184,9 @@
         tests.append(BasicSocketPairTest)
     if sys.platform == 'linux2':
         tests.append(TestLinuxAbstractNamespace)
+    if isTipcAvailable():
+        tests.append(TIPCTest)
+    tests.append(TIPCThreadableTest)
 
     thread_info = test_support.threading_setup()
     test_support.run_unittest(*tests)
diff --git a/Misc/NEWS b/Misc/NEWS
index 4732113..3896dd8 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -342,6 +342,8 @@
 Library
 -------
 
+- Issue #1646: Make socket support the TIPC protocol.
+
 - Bug #1742: return os.curdir from os.path.relpath() if both arguments are
   equal instead of raising an exception.
 
@@ -927,6 +929,9 @@
 Extension Modules
 -----------------
 
+- Issue #1646: Make socket support TIPC. The socket module now has support
+  for TIPC under Linux, see http://tipc.sf.net/ for more information.
+
 - Added interface for Windows' WSAIoctl to socket object and added an example
   for a simple network sniffer.
 
diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c
index c30f1b3..e3f81db 100644
--- a/Modules/socketmodule.c
+++ b/Modules/socketmodule.c
@@ -7,7 +7,8 @@
 Limitations:
 
 - Only AF_INET, AF_INET6 and AF_UNIX address families are supported in a
-  portable manner, though AF_PACKET and AF_NETLINK are supported under Linux.
+  portable manner, though AF_PACKET, AF_NETLINK and AF_TIPC are supported
+  under Linux.
 - No read/write operations (use sendall/recv or makefile instead).
 - Additional restrictions apply on some non-Unix platforms (compensated
   for by socket.py).
@@ -52,6 +53,25 @@
   the Ethernet protocol number to be received. For example:
   ("eth0",0x1234).  Optional 3rd,4th,5th elements in the tuple
   specify packet-type and ha-type/addr.
+- an AF_TIPC socket address is expressed as
+ (addr_type, v1, v2, v3 [, scope]); where addr_type can be one of:
+	TIPC_ADDR_NAMESEQ, TIPC_ADDR_NAME, and TIPC_ADDR_ID;
+  and scope can be one of:
+	TIPC_ZONE_SCOPE, TIPC_CLUSTER_SCOPE, and TIPC_NODE_SCOPE.
+  The meaning of v1, v2 and v3 depends on the value of addr_type:
+	if addr_type is TIPC_ADDR_NAME:
+		v1 is the server type
+		v2 is the port identifier
+		v3 is ignored
+	if addr_type is TIPC_ADDR_NAMESEQ:
+		v1 is the server type
+		v2 is the lower port number
+		v3 is the upper port number
+	if addr_type is TIPC_ADDR_ID:
+		v1 is the node
+		v2 is the ref
+		v3 is ignored
+
 
 Local naming conventions:
 
@@ -1094,6 +1114,39 @@
 	}
 #endif
 
+#ifdef HAVE_LINUX_TIPC_H
+	case AF_TIPC:
+	{
+		struct sockaddr_tipc *a = (struct sockaddr_tipc *) addr;
+		if (a->addrtype == TIPC_ADDR_NAMESEQ) {
+			return Py_BuildValue("IIIII",
+					a->addrtype,
+					a->addr.nameseq.type,
+					a->addr.nameseq.lower,
+					a->addr.nameseq.upper,
+					a->scope);
+		} else if (a->addrtype == TIPC_ADDR_NAME) {
+			return Py_BuildValue("IIIII",
+					a->addrtype,
+					a->addr.name.name.type,
+					a->addr.name.name.instance,
+					a->addr.name.name.instance,
+					a->scope);
+		} else if (a->addrtype == TIPC_ADDR_ID) {
+			return Py_BuildValue("IIIII",
+					a->addrtype,
+					a->addr.id.node,
+					a->addr.id.ref,
+					0,
+					a->scope);
+		} else {
+			PyErr_SetString(PyExc_TypeError,
+					"Invalid address type");
+			return NULL;
+		}
+	}
+#endif
+
 	/* More cases here... */
 
 	default:
@@ -1379,6 +1432,56 @@
 	}
 #endif
 
+#ifdef HAVE_LINUX_TIPC_H
+	case AF_TIPC:
+	{
+		unsigned int atype, v1, v2, v3;
+		unsigned int scope = TIPC_CLUSTER_SCOPE;
+		struct sockaddr_tipc *addr;
+
+		if (!PyTuple_Check(args)) {
+			PyErr_Format(
+				PyExc_TypeError,
+				"getsockaddrarg: "
+				"AF_TIPC address must be tuple, not %.500s",
+				Py_TYPE(args)->tp_name);
+			return 0;
+		}
+
+		if (!PyArg_ParseTuple(args,
+					"IIII|I;Invalid TIPC address format",
+					&atype, &v1, &v2, &v3, &scope))
+			return 0;
+
+		addr = (struct sockaddr_tipc *) addr_ret;
+		memset(addr, 0, sizeof(struct sockaddr_tipc));
+
+		addr->family = AF_TIPC;
+		addr->scope = scope;
+		addr->addrtype = atype;
+
+		if (atype == TIPC_ADDR_NAMESEQ) {
+			addr->addr.nameseq.type = v1;
+			addr->addr.nameseq.lower = v2;
+			addr->addr.nameseq.upper = v3;
+		} else if (atype == TIPC_ADDR_NAME) {
+			addr->addr.name.name.type = v1;
+			addr->addr.name.name.instance = v2;
+		} else if (atype == TIPC_ADDR_ID) {
+			addr->addr.id.node = v1;
+			addr->addr.id.ref = v2;
+		} else {
+			/* Shouldn't happen */
+			PyErr_SetString(PyExc_TypeError, "Invalid address type");
+			return 0;
+		}
+
+		*len_ret = sizeof(*addr);
+
+		return 1;
+	}
+#endif
+
 	/* More cases here... */
 
 	default:
@@ -1464,6 +1567,14 @@
 	}
 #endif
 
+#ifdef HAVE_LINUX_TIPC_H
+	case AF_TIPC:
+	{
+		*len_ret = sizeof (struct sockaddr_tipc);
+		return 1;
+	}
+#endif
+
 	/* More cases here... */
 
 	default:
@@ -4448,6 +4559,47 @@
 	PyModule_AddIntConstant(m, "PACKET_FASTROUTE", PACKET_FASTROUTE);
 #endif
 
+#ifdef HAVE_LINUX_TIPC_H
+	PyModule_AddIntConstant(m, "AF_TIPC", AF_TIPC);
+
+	/* for addresses */
+	PyModule_AddIntConstant(m, "TIPC_ADDR_NAMESEQ", TIPC_ADDR_NAMESEQ);
+	PyModule_AddIntConstant(m, "TIPC_ADDR_NAME", TIPC_ADDR_NAME);
+	PyModule_AddIntConstant(m, "TIPC_ADDR_ID", TIPC_ADDR_ID);
+
+	PyModule_AddIntConstant(m, "TIPC_ZONE_SCOPE", TIPC_ZONE_SCOPE);
+	PyModule_AddIntConstant(m, "TIPC_CLUSTER_SCOPE", TIPC_CLUSTER_SCOPE);
+	PyModule_AddIntConstant(m, "TIPC_NODE_SCOPE", TIPC_NODE_SCOPE);
+
+	/* for setsockopt() */
+	PyModule_AddIntConstant(m, "SOL_TIPC", SOL_TIPC);
+	PyModule_AddIntConstant(m, "TIPC_IMPORTANCE", TIPC_IMPORTANCE);
+	PyModule_AddIntConstant(m, "TIPC_SRC_DROPPABLE", TIPC_SRC_DROPPABLE);
+	PyModule_AddIntConstant(m, "TIPC_DEST_DROPPABLE",
+			TIPC_DEST_DROPPABLE);
+	PyModule_AddIntConstant(m, "TIPC_CONN_TIMEOUT", TIPC_CONN_TIMEOUT);
+
+	PyModule_AddIntConstant(m, "TIPC_LOW_IMPORTANCE",
+			TIPC_LOW_IMPORTANCE);
+	PyModule_AddIntConstant(m, "TIPC_MEDIUM_IMPORTANCE",
+			TIPC_MEDIUM_IMPORTANCE);
+	PyModule_AddIntConstant(m, "TIPC_HIGH_IMPORTANCE",
+			TIPC_HIGH_IMPORTANCE);
+	PyModule_AddIntConstant(m, "TIPC_CRITICAL_IMPORTANCE",
+			TIPC_CRITICAL_IMPORTANCE);
+
+	/* for subscriptions */
+	PyModule_AddIntConstant(m, "TIPC_SUB_PORTS", TIPC_SUB_PORTS);
+	PyModule_AddIntConstant(m, "TIPC_SUB_SERVICE", TIPC_SUB_SERVICE);
+	PyModule_AddIntConstant(m, "TIPC_SUB_CANCEL", TIPC_SUB_CANCEL);
+	PyModule_AddIntConstant(m, "TIPC_WAIT_FOREVER", TIPC_WAIT_FOREVER);
+	PyModule_AddIntConstant(m, "TIPC_PUBLISHED", TIPC_PUBLISHED);
+	PyModule_AddIntConstant(m, "TIPC_WITHDRAWN", TIPC_WITHDRAWN);
+	PyModule_AddIntConstant(m, "TIPC_SUBSCR_TIMEOUT", TIPC_SUBSCR_TIMEOUT);
+	PyModule_AddIntConstant(m, "TIPC_CFG_SRV", TIPC_CFG_SRV);
+	PyModule_AddIntConstant(m, "TIPC_TOP_SRV", TIPC_TOP_SRV);
+#endif
+
 	/* Socket types */
 	PyModule_AddIntConstant(m, "SOCK_STREAM", SOCK_STREAM);
 	PyModule_AddIntConstant(m, "SOCK_DGRAM", SOCK_DGRAM);
diff --git a/Modules/socketmodule.h b/Modules/socketmodule.h
index 95bc233..285c1fe 100644
--- a/Modules/socketmodule.h
+++ b/Modules/socketmodule.h
@@ -60,6 +60,10 @@
 # include <netpacket/packet.h>
 #endif
 
+#ifdef HAVE_LINUX_TIPC_H
+# include <linux/tipc.h>
+#endif
+
 #ifndef Py__SOCKET_H
 #define Py__SOCKET_H
 #ifdef __cplusplus
diff --git a/configure b/configure
index fb79c06..5929c23 100755
--- a/configure
+++ b/configure
@@ -1,5 +1,5 @@
 #! /bin/sh
-# From configure.in Revision: 59558 .
+# From configure.in Revision: 59611 .
 # Guess values for system-dependent variables and create Makefiles.
 # Generated by GNU Autoconf 2.61 for python 2.6.
 #
@@ -5417,6 +5417,7 @@
 
 
 
+
 for ac_header in asm/types.h conio.h curses.h direct.h dlfcn.h errno.h \
 fcntl.h grp.h \
 io.h langinfo.h libintl.h ncurses.h poll.h process.h pthread.h \
@@ -5428,7 +5429,7 @@
 sys/time.h \
 sys/times.h sys/types.h sys/un.h sys/utsname.h sys/wait.h pty.h libutil.h \
 sys/resource.h netpacket/packet.h sysexits.h bluetooth.h \
-bluetooth/bluetooth.h
+bluetooth/bluetooth.h linux/tipc.h
 do
 as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
 if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
diff --git a/configure.in b/configure.in
index cdf1366..2ff6244 100644
--- a/configure.in
+++ b/configure.in
@@ -1107,7 +1107,7 @@
 sys/time.h \
 sys/times.h sys/types.h sys/un.h sys/utsname.h sys/wait.h pty.h libutil.h \
 sys/resource.h netpacket/packet.h sysexits.h bluetooth.h \
-bluetooth/bluetooth.h)
+bluetooth/bluetooth.h linux/tipc.h)
 AC_HEADER_DIRENT
 AC_HEADER_MAJOR
 
diff --git a/pyconfig.h.in b/pyconfig.h.in
index 26197fb..ef04c12 100644
--- a/pyconfig.h.in
+++ b/pyconfig.h.in
@@ -354,6 +354,9 @@
 /* Define to 1 if you have the <linux/netlink.h> header file. */
 #undef HAVE_LINUX_NETLINK_H
 
+/* Define to 1 if you have the <linux/tipc.h> header file. */
+#undef HAVE_LINUX_TIPC_H
+
 /* Define this if you have the type long long. */
 #undef HAVE_LONG_LONG
 
@@ -1040,4 +1043,3 @@
 
 #endif /*Py_PYCONFIG_H*/
 
-