diff -r 3156dd82df2d Doc/library/socket.rst --- a/Doc/library/socket.rst Wed Jun 10 15:44:18 2015 -0700 +++ b/Doc/library/socket.rst Thu Jun 11 15:15:26 2015 -0400 @@ -111,6 +111,20 @@ .. XXX document them! +.. versionadded:: 3.5 + Linux-only support for IUCV is also available using the :const:`AF_IUCV` + address family on s390x. IUCV is a non-IP based network protocol designed + for virtual-machine to virtual-machine communication. Addresses are represented + by a tuple. The form of the tuple is + ``(node, userid, name)``, where: + + - *node* is the name of the z/VM system upon which the partner is running. Currenty, + this is ignored and only intra-z/VM communication is supported by the kernel. + - *userid* is the name of the virtual machine to communicate with. If left as blanks, + then it defaults to the virtual machine in which the program is running. + - *name* is the name of the application end point running within the virtual machine. + Multiple applications may be running and using `AF_IUCV`. + For IPv4 addresses, two special forms are accepted instead of a host address: the empty string represents :const:`INADDR_ANY`, and the string ``''`` represents :const:`INADDR_BROADCAST`. This behavior is not diff -r 3156dd82df2d Lib/plat-linux/IN.py --- a/Lib/plat-linux/IN.py Wed Jun 10 15:44:18 2015 -0700 +++ b/Lib/plat-linux/IN.py Thu Jun 11 15:15:26 2015 -0400 @@ -385,7 +385,8 @@ PF_PPPOX = 24 PF_WANPIPE = 25 PF_BLUETOOTH = 31 -PF_MAX = 32 +PF_IUCV = 32 +PF_MAX = 33 AF_UNSPEC = PF_UNSPEC AF_LOCAL = PF_LOCAL AF_UNIX = PF_UNIX @@ -415,6 +416,7 @@ AF_PPPOX = PF_PPPOX AF_WANPIPE = PF_WANPIPE AF_BLUETOOTH = PF_BLUETOOTH +AF_IUCV = PF_IUCV AF_MAX = PF_MAX SOL_RAW = 255 SOL_DECNET = 261 diff -r 3156dd82df2d Lib/test/test_socket.py --- a/Lib/test/test_socket.py Wed Jun 10 15:44:18 2015 -0700 +++ b/Lib/test/test_socket.py Thu Jun 11 15:15:26 2015 -0400 @@ -5280,6 +5280,69 @@ def meth_from_sock(self, sock): return getattr(sock, "_sendfile_use_sendfile") +def isIUCVAvailable(): + """Check if this platform supports IUCV + + """ + if not hasattr(socket, "AF_IUCV"): + return False + if not os.path.isfile("/proc/modules"): + return False + with open("/proc/modules") as f: + for line in f: + if line.startswith("af_iucv "): + return True + return False + +def getIUCVTarget(): + """Extract my z/VM user id from /proc/sysinfo + + """ + with open("/proc/sysinfo") as f: + for line in f: + if line.startswith("VM00 Name:"): + return line[22:].strip() + +@unittest.skipUnless(isIUCVAvailable(), + "Platform does not support AF_IUCV - ignoring") +class IUCVThreadableTest(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_IUCV, socket.SOCK_STREAM) + self.srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + userid = getIUCVTarget() + srvaddr = ("", userid, "SELF") + self.srv.bind(srvaddr) + self.srv.listen(5) + self.serverExplicitReady() + self.conn, self.connaddr = self.srv.accept() + self.addCleanup(self.conn.close) + self.addCleanup(self.srv.close) + + 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_IUCV, socket.SOCK_STREAM) + userid = getIUCVTarget() + addr = ("", userid, "SELF") + 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, @@ -5335,6 +5398,7 @@ SendfileUsingSendTest, SendfileUsingSendfileTest, ]) + tests.extend([IUCVThreadableTest]) thread_info = support.threading_setup() support.run_unittest(*tests) diff -r 3156dd82df2d Modules/socketmodule.c --- a/Modules/socketmodule.c Wed Jun 10 15:44:18 2015 -0700 +++ b/Modules/socketmodule.c Thu Jun 11 15:15:26 2015 -0400 @@ -7,8 +7,8 @@ Limitations: - Only AF_INET, AF_INET6 and AF_UNIX address families are supported in a - portable manner, though AF_PACKET, AF_NETLINK and AF_TIPC are supported - under Linux. + portable manner, though AF_PACKET, AF_NETLINK, AF_TIPC, and AF_IUCV 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). @@ -74,6 +74,11 @@ v2 is the ref v3 is ignored +- an AF_IUCV address is expressed as + (node, user, name) + - node: Name of z/VM system (default NULL) [1-8 char] + - user: User ID to connect to on that node [1-8 char] + - name: : Name of application end point running within user [1-8 char] Local naming conventions: @@ -264,6 +269,10 @@ #define PySocket_BUILDING_SOCKET #include "socketmodule.h" +#ifdef AF_IUCV +#include +#endif + /* Addressing includes */ #ifndef MS_WINDOWS @@ -1121,6 +1130,17 @@ } #endif +#ifdef AF_IUCV +/* Support routine to strip trailing blanks for a string */ +static __inline__ void +strip(char *var, size_t lVar) +{ + int i; + + for (i = lVar - 2; (isspace(var[i]) && (i >= 0)); i--); + var[++i] = 0; +} +#endif /* Create an object representing the given socket address, suitable for passing it back to bind(), connect() etc. @@ -1347,6 +1367,25 @@ } #endif + +#ifdef AF_IUCV + case AF_IUCV : + { + struct sockaddr_iucv *a = (struct sockaddr_iucv *) addr; + char node[9], user[9], name[9]; + + node[8] = user[8] = name[8] = 0; + memcpy(node, a->siucv_nodeid, sizeof(a->siucv_nodeid)); + memcpy(user, a->siucv_user_id, sizeof(a->siucv_user_id)); + memcpy(name, a->siucv_name, sizeof(a->siucv_name)); + strip(node, sizeof(node)); + strip(user, sizeof(user)); + strip(name, sizeof(name)); + + return Py_BuildValue("sss", &node, &user, &name); + } +#endif + /* More cases here... */ default: @@ -1910,6 +1949,7 @@ return 1; } #endif + default: PyErr_SetString(PyExc_OSError, "getsockaddrarg: unsupported PF_SYSTEM protocol"); @@ -1917,6 +1957,60 @@ } #endif +#ifdef AF_IUCV + case AF_IUCV: + { + char *node, *user, *name; +#ifdef PY_SSIZE_T_CLEAN + Py_ssize_t lNode, lUser, lName; +#else + int lNode, lUser, lName; +#endif + struct sockaddr_iucv *addr; + + if (!PyTuple_Check(args)) { + PyErr_Format( + PyExc_TypeError, + "getsockaddrarg: " + "AF_IUCV address must be tuple, not %.500s", + Py_TYPE(args)->tp_name); + return 0; + } + + if (!PyArg_ParseTuple(args, "s#s#s#", + &node, &lNode, + &user, &lUser, + &name, &lName)) + return 0; + + addr = (struct sockaddr_iucv *) addr_ret; + memset(addr, 0, sizeof(struct sockaddr_iucv)); + lNode = MIN(lNode, sizeof(addr->siucv_nodeid)); + lUser = MIN(lUser, sizeof(addr->siucv_user_id)); + lName = MIN(lName, sizeof(addr->siucv_name)); + + addr->siucv_family = AF_IUCV; + memset(addr->siucv_nodeid, ' ', sizeof(addr->siucv_nodeid)); + memset(addr->siucv_user_id, ' ', sizeof(addr->siucv_user_id)); + memset(addr->siucv_name, ' ', sizeof(addr->siucv_name)); + memcpy(addr->siucv_nodeid, node, lNode); + memcpy(addr->siucv_user_id, user, lUser); + memcpy(addr->siucv_name, name, lName); + if (addr->siucv_user_id[0] == ' ') { + PyErr_SetString(PyExc_ValueError, "Missing z/VM user name"); + return 0; + } + if (addr->siucv_name[0] == ' ') { + PyErr_SetString(PyExc_ValueError, "Missing application name"); + return 0; + } + + *len_ret = sizeof(*addr); + + return 1; + } +#endif + /* More cases here... */ default: @@ -2038,6 +2132,14 @@ } #endif +#ifdef AF_IUCV + case AF_IUCV: + { + *len_ret = sizeof (struct sockaddr_iucv); + return 1; + } +#endif + /* More cases here... */ default: @@ -6385,6 +6487,10 @@ PyModule_AddIntMacro(m, TIPC_TOP_SRV); #endif +#ifdef AF_IUCV + PyModule_AddIntConstant(m, "AF_IUCV", AF_IUCV); +#endif + /* Socket types */ PyModule_AddIntMacro(m, SOCK_STREAM); PyModule_AddIntMacro(m, SOCK_DGRAM);