From 331708b226db74e745ef9972f9d4177348e4399d Mon Sep 17 00:00:00 2001 From: Dave Cole Date: Mon, 9 Aug 2004 04:51:41 +0000 Subject: Patch #1003700: Add socketpair function to socket module. --- Doc/lib/libsocket.tex | 8 +++++++ Lib/socket.py | 1 + Lib/test/test_socket.py | 43 ++++++++++++++++++++++++++++++++++ Misc/NEWS | 2 ++ Modules/socketmodule.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++ configure.in | 11 +++++++++ pyconfig.h.in | 3 +++ 7 files changed, 130 insertions(+) diff --git a/Doc/lib/libsocket.tex b/Doc/lib/libsocket.tex index f78ad2f..06d2645 100644 --- a/Doc/lib/libsocket.tex +++ b/Doc/lib/libsocket.tex @@ -303,6 +303,14 @@ success, a new \class{SSLObject} is returned. \warning{This does not do any certificate verification!} \end{funcdesc} +\begin{funcdesc}{socketpair}{\optional{family\optional{, type\optional{, proto}}}} +Build a pair of connected socket objects using the given address +family, socket type and protocol number. Address family, socket type +and protocol number are as for the \function{socket()} function above. +Availability: \UNIX. +\versionadded{2.3} +\end{funcdesc} + \begin{funcdesc}{fromfd}{fd, family, type\optional{, proto}} Build a socket object from an existing file descriptor (an integer as returned by a file object's \method{fileno()} method). Address family, diff --git a/Lib/socket.py b/Lib/socket.py index e97ce59..f96a146 100644 --- a/Lib/socket.py +++ b/Lib/socket.py @@ -10,6 +10,7 @@ socket are available as methods of the socket object. Functions: socket() -- create a new socket object +socketpair() -- create a pair of new socket objects [*] fromfd() -- create a socket object from an open file descriptor [*] gethostname() -- return the current hostname gethostbyname() -- map a hostname to its IP number diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index adeca56..2dc34aa 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -187,6 +187,28 @@ class SocketConnectedTest(ThreadedTCPSocketTest): self.serv_conn = None ThreadedTCPSocketTest.clientTearDown(self) +class SocketPairTest(unittest.TestCase, ThreadableTest): + + def __init__(self, methodName='runTest'): + unittest.TestCase.__init__(self, methodName=methodName) + ThreadableTest.__init__(self) + + def setUp(self): + self.serv, self.cli = socket.socketpair() + + def tearDown(self): + self.serv.close() + self.serv = None + + def clientSetUp(self): + pass + + def clientTearDown(self): + self.cli.close() + self.cli = None + ThreadableTest.clientTearDown(self) + + ####################################################################### ## Begin Tests @@ -541,6 +563,25 @@ class BasicUDPTest(ThreadedUDPSocketTest): def _testRecvFrom(self): self.cli.sendto(MSG, 0, (HOST, PORT)) +class BasicSocketPairTest(SocketPairTest): + + def __init__(self, methodName='runTest'): + SocketPairTest.__init__(self, methodName=methodName) + + def testRecv(self): + msg = self.serv.recv(1024) + self.assertEqual(msg, MSG) + + def _testRecv(self): + self.cli.send(MSG) + + def testSend(self): + self.serv.send(MSG) + + def _testSend(self): + msg = self.cli.recv(1024) + self.assertEqual(msg, MSG) + class NonBlockingTCPTests(ThreadedTCPSocketTest): def __init__(self, methodName='runTest'): @@ -786,6 +827,8 @@ def test_main(): LineBufferedFileObjectClassTestCase, SmallBufferedFileObjectClassTestCase ]) + if hasattr(socket, "socketpair"): + tests.append(BasicSocketPairTest) test_support.run_unittest(*tests) if __name__ == "__main__": diff --git a/Misc/NEWS b/Misc/NEWS index f3e51c6..f3ed638 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -24,6 +24,8 @@ Core and builtins Extension modules ----------------- +- Added socket.socketpair(). + Library ------- diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 30159d2..f06e253 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -28,6 +28,7 @@ Module interface: - socket.getservbyname(servicename[, protocolname]) --> port number - socket.getservbyport(portnumber[, protocolname]) --> service name - socket.socket([family[, type [, proto]]]) --> new socket object +- socket.socketpair([family[, type [, proto]]]) --> (socket, socket) - socket.ntohs(16 bit value) --> new int object - socket.ntohl(32 bit value) --> new int object - socket.htons(16 bit value) --> new int object @@ -3009,6 +3010,63 @@ PyDoc_STRVAR(getprotobyname_doc, Return the protocol number for the named protocol. (Rarely used.)"); +#ifdef HAVE_SOCKETPAIR +/* Create a pair of sockets using the socketpair() function. + Arguments as for socket(). */ + +/*ARGSUSED*/ +static PyObject * +socket_socketpair(PyObject *self, PyObject *args) +{ + PySocketSockObject *s0 = NULL, *s1 = NULL; + SOCKET_T sv[2]; + int family, type = SOCK_STREAM, proto = 0; + PyObject *res = NULL; + +#if defined(AF_UNIX) + family = AF_UNIX; +#else + family = AF_INET; +#endif + if (!PyArg_ParseTuple(args, "|iii:socketpair", + &family, &type, &proto)) + return NULL; + /* Create a pair of socket fds */ + if (socketpair(family, type, proto, sv) < 0) + return set_error(); +#ifdef SIGPIPE + (void) signal(SIGPIPE, SIG_IGN); +#endif + s0 = new_sockobject(sv[0], family, type, proto); + if (s0 == NULL) + goto finally; + s1 = new_sockobject(sv[1], family, type, proto); + if (s1 == NULL) + goto finally; + res = PyTuple_Pack(2, s0, s1); + +finally: + if (res == NULL) { + if (s0 == NULL) + SOCKETCLOSE(sv[0]); + if (s1 == NULL) + SOCKETCLOSE(sv[1]); + } + Py_XDECREF(s0); + Py_XDECREF(s1); + return res; +} + +PyDoc_STRVAR(socketpair_doc, +"socketpair([family[, type[, proto]]]) -> (socket object, socket object)\n\ +\n\ +Create a pair of socket objects from the sockets returned by the platform\n\ +socketpair() function.\n\ +The arguments are the same as for socket()."); + +#endif /* HAVE_SOCKETPAIR */ + + #ifndef NO_DUP /* Create a socket object from a numeric file description. Useful e.g. if stdin is a socket. @@ -3608,6 +3666,10 @@ static PyMethodDef socket_methods[] = { {"fromfd", socket_fromfd, METH_VARARGS, fromfd_doc}, #endif +#ifdef HAVE_SOCKETPAIR + {"socketpair", socket_socketpair, + METH_VARARGS, socketpair_doc}, +#endif {"ntohs", socket_ntohs, METH_VARARGS, ntohs_doc}, {"ntohl", socket_ntohl, diff --git a/configure.in b/configure.in index f73d1ce..fbd436b 100644 --- a/configure.in +++ b/configure.in @@ -2468,6 +2468,17 @@ int foo(int x, ...) { ]) AC_MSG_RESULT($works) +# check for socketpair +AC_MSG_CHECKING(for socketpair) +AC_TRY_COMPILE([ +#include +#include +], void *x=socketpair, + AC_DEFINE(HAVE_SOCKETPAIR, 1, Define if you have the 'socketpair' function.) + AC_MSG_RESULT(yes), + AC_MSG_RESULT(no) +) + # check if sockaddr has sa_len member AC_MSG_CHECKING(if sockaddr has sa_len member) AC_TRY_COMPILE([#include diff --git a/pyconfig.h.in b/pyconfig.h.in index 5e1a43c..19227e0 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -428,6 +428,9 @@ /* Define to 1 if you have the `snprintf' function. */ #undef HAVE_SNPRINTF +/* Define to 1 if you have the `socketpair' function. */ +#undef HAVE_SOCKETPAIR + /* Define if sockaddr has sa_len member */ #undef HAVE_SOCKADDR_SA_LEN -- cgit v0.12