diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -271,6 +271,19 @@ .. versionadded:: 3.3 +.. data:: AF_IRDA + PF_IRDA + SOL_IRLMP + IRLMP_* + + Many constants of these forms, relevant for IrDA sockets, are also defined + in the socket module. + + Availability: Linux, Windows. + + .. versionadded:: 3.3 + + .. data:: SIO_* RCVALL_* @@ -449,15 +462,17 @@ Create a new socket using the given address family, socket type and protocol number. The address family should be :const:`AF_INET` (the default), - :const:`AF_INET6`, :const:`AF_UNIX`, :const:`AF_CAN` or :const:`AF_RDS`. The - socket type should be :const:`SOCK_STREAM` (the default), - :const:`SOCK_DGRAM`, :const:`SOCK_RAW` or perhaps one of the other ``SOCK_`` - constants. The protocol number is usually zero and may be omitted in that - case or :const:`CAN_RAW` in case the address family is :const:`AF_CAN`. + :const:`AF_INET6`, :const:`AF_UNIX`, :const:`AF_CAN` , :const:`AF_RDS` or + :const:`AF_IRDA`. The socket type should be :const:`SOCK_STREAM` (the + default), :const:`SOCK_DGRAM`, :const:`SOCK_RAW` or perhaps one of the other + ``SOCK_`` constants. The protocol number is usually zero and may be omitted + in that case or :const:`CAN_RAW` in case the address family is + :const:`AF_CAN`. .. versionchanged:: 3.3 The AF_CAN family was added. The AF_RDS family was added. + The AF_IRDA family was added. .. function:: socketpair([family[, type[, proto]]]) diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -1007,6 +1007,9 @@ (http://en.wikipedia.org/wiki/Reliable_Datagram_Sockets and http://oss.oracle.com/projects/rds/). +* The :class:`~socket.socket` class now supports the PF_IRDA protocol family + (http://en.wikipedia.org/wiki/IRDA). + ssl --- diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -61,10 +61,23 @@ s.close() return True +def _have_socket_irda(): + """Check whether IrDA sockets are supported on this host.""" + try: + s = socket.socket(socket.PF_IRDA, socket.SOCK_STREAM) + except (AttributeError, socket.error, OSError): + return False + else: + s.close() + return True + + HAVE_SOCKET_CAN = _have_socket_can() HAVE_SOCKET_RDS = _have_socket_rds() +HAVE_SOCKET_IRDA = _have_socket_irda() + # Size in bytes of the int type SIZEOF_INT = array.array("i").itemsize @@ -1481,6 +1494,29 @@ self.assertIn(self.serv, r) +@unittest.skipUnless(HAVE_SOCKET_IRDA, 'IrDA sockets required for this test.') +class BasicIrDATest(unittest.TestCase): + + def testCrucialConstants(self): + socket.AF_IRDA + socket.PF_IRDA + socket.SOL_IRLMP + socket.IRLMP_ENUMDEVICES + socket.IRLMP_IAS_SET + socket.IRLMP_IAS_QUERY + socket.IRLMP_WAITDEVICE + + def testCreateSocket(self): + with socket.socket(socket.PF_IRDA, socket.SOCK_STREAM): + pass + + def testTooLongServiceName(self): + # service name is limited to 24 characters + with socket.socket(socket.PF_IRDA, socket.SOCK_STREAM) as s: + self.assertRaisesRegex(socket.error, 'service name too long', + s.bind, (42, 'x' * 25,)) + + @unittest.skipUnless(thread, 'Threading required for this test.') class BasicTCPTest(SocketConnectedTest): @@ -4782,6 +4818,7 @@ tests.append(TIPCThreadableTest) tests.extend([BasicCANTest, CANTest]) tests.extend([BasicRDSTest, RDSTest]) + tests.append(BasicIrDATest) tests.extend([ CmsgMacroTests, SendmsgUDPTest, diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -1262,6 +1262,16 @@ } #endif +#ifdef AF_IRDA + case AF_IRDA: + { + struct sockaddr_irda *a = (struct sockaddr_irda *)addr; + + return Py_BuildValue("iO&", a->sir_addr, + PyUnicode_DecodeFSDefault, a->sir_name); + } +#endif + /* More cases here... */ default: @@ -1759,6 +1769,47 @@ } #endif +#ifdef HAVE_IRDA_H + case AF_IRDA: + { + struct sockaddr_irda *addr; + int daddr; + PyObject *service; + addr = (struct sockaddr_irda *)addr_ret; + Py_ssize_t len; + + if (!PyArg_ParseTuple(args, "iO&", &daddr, + PyUnicode_FSConverter, &service)) + return 0; + + len = PyBytes_GET_SIZE(service); + + if (len <= 0 || len >= sizeof(addr->sir_name)) { + PyErr_SetString(PyExc_OSError, "AF_IRDA service name too long"); + Py_DECREF(service); + return 0; + } + +#ifdef HAVE_LINUX_IRDA_H + addr->sir_family = AF_IRDA; + addr->sir_lsap_sel = LSAP_ANY; + addr->sir_addr = daddr; + strcpy(addr->sir_name, PyBytes_AS_STRING(service)); +#else /* Windows */ + addr->irdaAddressFamily = AF_IRDA; + addr->irdaDeviceID[0] = (daddr >> 24) & Oxff; + addr->irdaDeviceID[1] = (daddr >> 16) & Oxff; + addr->irdaDeviceID[2] = (daddr >> 8 ) & Oxff; + addr->irdaDeviceID[3] = daddr & Oxff; + strcpy(addr->irdaServiceName, PyBytes_AS_STRING(service)); +#endif + + Py_DECREF(service); + *len_ret = sizeof(*addr); + return 1; + } +#endif + /* More cases here... */ default: @@ -1880,6 +1931,14 @@ } #endif +#ifdef AF_IRDA + case AF_IRDA: + { + *len_ret = sizeof (struct sockaddr_irda); + return 1; + } +#endif + /* More cases here... */ default: @@ -5823,6 +5882,14 @@ PyModule_AddIntConstant(m, "AF_SYSTEM", AF_SYSTEM); #endif +/* Infrared Data Association */ +#ifdef AF_IRDA + PyModule_AddIntConstant(m, "AF_IRDA", AF_IRDA); +#endif +#ifdef PF_IRDA + PyModule_AddIntConstant(m, "PF_IRDA", PF_IRDA); +#endif + #ifdef AF_PACKET PyModule_AddIntMacro(m, AF_PACKET); #endif @@ -5895,6 +5962,15 @@ PyModule_AddIntConstant(m, "TIPC_TOP_SRV", TIPC_TOP_SRV); #endif +/* Infrared Data Association */ +#ifdef HAVE_IRDA_H + PyModule_AddIntConstant(m, "SOL_IRLMP", SOL_IRLMP); + PyModule_AddIntConstant(m, "IRLMP_ENUMDEVICES", IRLMP_ENUMDEVICES); + PyModule_AddIntConstant(m, "IRLMP_IAS_SET", IRLMP_IAS_SET); + PyModule_AddIntConstant(m, "IRLMP_IAS_QUERY", IRLMP_IAS_QUERY); + PyModule_AddIntConstant(m, "IRLMP_WAITDEVICE", IRLMP_WAITDEVICE); +#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 --- a/Modules/socketmodule.h +++ b/Modules/socketmodule.h @@ -87,6 +87,17 @@ #include #endif +#if (defined(MS_WINDOWS) || defined(HAVE_LINUX_IRDA_H)) +#define HAVE_IRDA_H +#ifdef HAVE_LINUX_IRDA_H +#include +#include +#else +#include +#define sockaddr_irda _SOCKADDR_IRDA +#endif +#endif + #ifndef Py__SOCKET_H #define Py__SOCKET_H #ifdef __cplusplus @@ -148,6 +159,9 @@ #ifdef HAVE_SYS_KERN_CONTROL_H struct sockaddr_ctl ctl; #endif +#ifdef HAVE_IRDA_H + struct sockaddr_irda ir; +#endif } sock_addr_t; /* The object holding a socket. It holds some extra information, diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -1404,6 +1404,13 @@ #endif ]) +# On Linux, irda.h requires sys/socket.h +AC_CHECK_HEADERS(linux/irda.h,,,[ +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +]) + # checks for typedefs was_it_defined=no AC_MSG_CHECKING(for clock_t in time.h) diff --git a/pyconfig.h.in b/pyconfig.h.in --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -501,6 +501,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_CAN_RAW_H +/* Define to 1 if you have the header file. */ +#undef HAVE_LINUX_IRDA_H + /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_NETLINK_H