*** python.orig/dist/src/Modules/socketmodule.c Sat Apr 27 14:44:31 2002 --- python/python/dist/src/Modules/socketmodule.c Wed Jun 5 16:21:03 2002 *************** *** 66,71 **** --- 66,73 ---- - s.sendall(string [,flags]) # tries to send everything in a loop - s.sendto(string, [flags,] sockaddr) --> nbytes - s.setblocking(0 | 1) --> None + - s.settimeout (None | int | float | long) -> None # Argument in secs + - s.gettimeout () -> None or floating secs - s.setsockopt(level, optname, value) --> None - s.shutdown(how) --> None - repr(s) --> "" *************** *** 104,110 **** # endif #endif ! #if !defined(HAVE_GETHOSTBYNAME_R) && defined(WITH_THREAD) && !defined(MS_WINDOWS) # define USE_GETHOSTBYNAME_LOCK #endif --- 106,113 ---- # endif #endif ! #if !defined(HAVE_GETHOSTBYNAME_R) && defined(WITH_THREAD) \ ! && !defined(MS_WINDOWS) # define USE_GETHOSTBYNAME_LOCK #endif *************** *** 232,237 **** --- 235,244 ---- /* XXX There's a problem here: *static* functions are not supposed to have a Py prefix (or use CapitalizedWords). Later... */ + /* Global variable holding the reference to the select module for use + * in implementing socket timeouts. */ + static PyObject *PySelectModule; + /* Global variable holding the exception type for errors detected by this module (but not argument type or memory errors, etc.). */ *************** *** 421,426 **** --- 428,545 ---- return NULL; } + /* For timeout errors */ + static PyObject * + timeout_err(void) + { + PyObject *v; + + #ifdef MS_WINDOWS + v = Py_BuildValue("(is)", WSAETIMEDOUT, "Socket operation timed out"); + #else + v = Py_BuildValue("(is)", ETIMEDOUT, "Socket operation timed out"); + #endif + + if (v != NULL) { + PyErr_SetObject(PySocket_Error, v); + Py_DECREF(v); + } + + return NULL; + } + + /* Function to perfrom the setting of socket blocking mode + * internally. block = (1 | 0). + */ + static int + internal_setblocking(PySocketSockObject *s, int block) + { + #ifndef RISCOS + #ifndef MS_WINDOWS + int delay_flag; + #endif + #endif + + Py_BEGIN_ALLOW_THREADS + #ifdef __BEOS__ + block = !block; + setsockopt( s->sock_fd, SOL_SOCKET, SO_NONBLOCK, + (void *)(&block), sizeof( int ) ); + #else + #ifndef RISCOS + #ifndef MS_WINDOWS + #if defined(PYOS_OS2) && !defined(PYCC_GCC) + block = !block; + ioctl(s->sock_fd, FIONBIO, (caddr_t)&block, sizeof(block)); + #else /* !PYOS_OS2 */ + delay_flag = fcntl(s->sock_fd, F_GETFL, 0); + if (block) + delay_flag &= (~O_NDELAY); + else + delay_flag |= O_NDELAY; + fcntl(s->sock_fd, F_SETFL, delay_flag); + #endif /* !PYOS_OS2 */ + #else /* MS_WINDOWS */ + block = !block; + ioctlsocket(s->sock_fd, FIONBIO, (u_long*)&block); + #endif /* MS_WINDOWS */ + #endif /* __BEOS__ */ + #endif /* RISCOS */ + Py_END_ALLOW_THREADS + + /* Since these don't return anything */ + return 1; + } + + /* For access to the select module to poll the socket for timeout + * functionality. If direction is: 1 poll as read, 0, poll as + * write + */ + static int + internal_select(PySocketSockObject *s, int direction) + { + PyObject *empty, *sock_list, *sel_res; + int count = 0; + + /* Construct the arguments to select */ + empty = PyList_New(0); + + sock_list = PyList_New(0); + if (PyList_Append(sock_list, (PyObject *)s) < 0) + return -1; + + Py_INCREF(s->sock_timeout); + + /* Now poll to see if the socket is ready */ + sel_res = PyObject_CallMethod(PySelectModule, "select", "OOOO", + direction ? empty : sock_list, + direction ? sock_list : empty, + empty, + s->sock_timeout); + + Py_DECREF(empty); + Py_DECREF(sock_list); + Py_DECREF(s->sock_timeout); + + if (sel_res == NULL) + return -1; + + /* Determine if we were polled */ + sock_list = PySequence_GetItem(sel_res, direction ? 1 : 0); + count = PySequence_Count(sock_list, (PyObject *)s); + + Py_DECREF(sock_list); + Py_DECREF(sel_res); + + /* Set the error if the timeout has elapsed, i.e, we were not + * polled. + */ + if (count == 0) + timeout_err (); + + return count; + } + /* Initialize a new socket object. */ static void *************** *** 434,439 **** --- 553,564 ---- s->sock_family = family; s->sock_type = type; s->sock_proto = proto; + s->sock_blocking = 1; /* Start in blocking mode */ + + /* Assign a timeout of none */ + Py_INCREF(Py_None); + s->sock_timeout = Py_None; + s->errorhandler = &PySocket_Err; #ifdef RISCOS if(taskwindow) { *************** *** 861,869 **** --- 986,1028 ---- if (!getsockaddrlen(s, &addrlen)) return NULL; memset(addrbuf, 0, addrlen); + + errno = 0; /* Reset indicator for use with timeout behavior */ + Py_BEGIN_ALLOW_THREADS newfd = accept(s->sock_fd, (struct sockaddr *) addrbuf, &addrlen); Py_END_ALLOW_THREADS + + if (s->sock_timeout != Py_None) { + #ifdef MS_WINDOWS + if (newfd == INVALID_SOCKET) + if (!s->sock_blocking) + return s->errorhandler(); + /* Check if we have a true failure for a blocking socket */ + if (errno != WSAEWOULDBLOCK) + return s->errorhandler(); + #else + if (newfd < 0) { + if (!s->sock_blocking) + return s->errorhandler(); + /* Check if we have a true failure for a blocking socket */ + if (errno != EAGAIN && errno != EWOULDBLOCK) + return s->errorhandler(); + } + #endif + + /* try waiting the timeout period */ + if (internal_select(s, 0) <= 0) + return NULL; + + Py_BEGIN_ALLOW_THREADS + newfd = accept(s->sock_fd, (struct sockaddr *) addrbuf, &addrlen); + Py_END_ALLOW_THREADS + } + + /* At this point, we really have an error, whether using timeout + * behavior or regular socket behavior + */ #ifdef MS_WINDOWS if (newfd == INVALID_SOCKET) #else *************** *** 877,894 **** s->sock_family, s->sock_type, s->sock_proto); if (sock == NULL) { SOCKETCLOSE(newfd); goto finally; } addr = makesockaddr(s->sock_fd, (struct sockaddr *)addrbuf, ! addrlen); if (addr == NULL) goto finally; res = Py_BuildValue("OO", sock, addr); ! finally: Py_XDECREF(sock); Py_XDECREF(addr); return res; --- 1036,1054 ---- s->sock_family, s->sock_type, s->sock_proto); + if (sock == NULL) { SOCKETCLOSE(newfd); goto finally; } addr = makesockaddr(s->sock_fd, (struct sockaddr *)addrbuf, ! addrlen); if (addr == NULL) goto finally; res = Py_BuildValue("OO", sock, addr); ! finally: Py_XDECREF(sock); Py_XDECREF(addr); return res; *************** *** 901,947 **** connection, and the address of the client. For IP sockets, the address\n\ info is a pair (hostaddr, port)."; - /* s.setblocking(1 | 0) method */ static PyObject * PySocketSock_setblocking(PySocketSockObject *s, PyObject *arg) { int block; ! #ifndef RISCOS ! #ifndef MS_WINDOWS ! int delay_flag; ! #endif ! #endif block = PyInt_AsLong(arg); if (block == -1 && PyErr_Occurred()) return NULL; ! Py_BEGIN_ALLOW_THREADS ! #ifdef __BEOS__ ! block = !block; ! setsockopt( s->sock_fd, SOL_SOCKET, SO_NONBLOCK, ! (void *)(&block), sizeof( int ) ); ! #else ! #ifndef RISCOS ! #ifndef MS_WINDOWS ! #if defined(PYOS_OS2) && !defined(PYCC_GCC) ! block = !block; ! ioctl(s->sock_fd, FIONBIO, (caddr_t)&block, sizeof(block)); ! #else /* !PYOS_OS2 */ ! delay_flag = fcntl (s->sock_fd, F_GETFL, 0); ! if (block) ! delay_flag &= (~O_NDELAY); ! else ! delay_flag |= O_NDELAY; ! fcntl (s->sock_fd, F_SETFL, delay_flag); ! #endif /* !PYOS_OS2 */ ! #else /* MS_WINDOWS */ ! block = !block; ! ioctlsocket(s->sock_fd, FIONBIO, (u_long*)&block); ! #endif /* MS_WINDOWS */ ! #endif /* __BEOS__ */ ! #endif /* RISCOS */ ! Py_END_ALLOW_THREADS Py_INCREF(Py_None); return Py_None; --- 1061,1084 ---- connection, and the address of the client. For IP sockets, the address\n\ info is a pair (hostaddr, port)."; /* s.setblocking(1 | 0) method */ static PyObject * PySocketSock_setblocking(PySocketSockObject *s, PyObject *arg) { int block; ! block = PyInt_AsLong(arg); if (block == -1 && PyErr_Occurred()) return NULL; ! ! s->sock_blocking = block; ! ! /* If we're not using timeouts, actually set the blocking to give ! * old python behavior. ! */ ! if (s->sock_timeout == Py_None) ! internal_setblocking (s, block); Py_INCREF(Py_None); return Py_None; *************** *** 953,958 **** --- 1090,1160 ---- Set the socket to blocking (flag is true) or non-blocking (false).\n\ This uses the FIONBIO ioctl with the O_NDELAY flag."; + /* s.settimeout (float | int | long) method. + * Causes an exception to be raised when the integer number of seconds + * has elapsed when performing a blocking socket operation. + */ + static PyObject * + PySocketSock_settimeout(PySocketSockObject *s, PyObject *arg) + { + double value = 0.0; + + if (! (arg == Py_None || + ((PyFloat_Check(arg) || PyInt_Check(arg) || PyLong_Check (arg)) && + (value = PyFloat_AsDouble(arg)) >= 0.0))) { + PyErr_SetString(PyExc_TypeError, "Invalid timeout value"); + return NULL; + } + + Py_DECREF(s->sock_timeout); + s->sock_timeout = (arg == Py_None) ? Py_None : PyFloat_FromDouble(value); + + /* The semantics of setting socket timeouts are: + * If you set_timeout(int/float/long != None): + * The actual socket gets put in non-blocking mode and the select is + * used to control timeouts. + * Else If you set_timeout(None): + * The old behavior is used AND automatically, the socket is set + * to blocking mode. That means that someone who was doing non-blocking + * stuff before, sets a timeout, and then unsets one, will have to do + * a set_blocking call again if he wants non-blocking stuff. This makes + * sense 'cause timeout stuff is blocking by nature. + */ + if (s->sock_timeout != Py_None) + internal_setblocking(s, 0); + else + internal_setblocking(s, 1); + s->sock_blocking = 1; + + Py_INCREF(Py_None); + return Py_None; + } + + static char settimeout_doc[] = + "settimeout(seconds)\n\ + \n\ + Set a timeout on blocking socket operations. 'seconds' can be a floating,\n\ + integer, or long number of seconds, or the None value. Socket operations\n\ + will raise an exception if the timeout period has elapsed before the\n\ + operation has completed. Setting a timeout of None disables timeouts\n\ + on socket operations."; + + /* s.gettimeout () method. + * Returns the timeout associated with a socket. + */ + static PyObject * + PySocketSock_gettimeout(PySocketSockObject *s) + { + Py_INCREF(s->sock_timeout); + return s->sock_timeout; + } + + static char gettimeout_doc[] = + "gettimeout()\n\ + \n\ + Returns the timeout in floating seconds associated with socket \n\ + operations. A timeout of None indicates that timeouts on socket \n\ + operations are disabled."; #ifdef RISCOS /* s.sleeptaskw(1 | 0) method */ *************** *** 960,975 **** static PyObject * PySocketSock_sleeptaskw(PySocketSockObject *s,PyObject *args) { ! int block; ! int delay_flag; ! if (!PyArg_Parse(args, "i", &block)) ! return NULL; ! Py_BEGIN_ALLOW_THREADS ! socketioctl(s->sock_fd, 0x80046679, (u_long*)&block); ! Py_END_ALLOW_THREADS ! Py_INCREF(Py_None); ! return Py_None; } static char sleeptaskw_doc[] = "sleeptaskw(flag)\n\ --- 1162,1177 ---- static PyObject * PySocketSock_sleeptaskw(PySocketSockObject *s,PyObject *args) { ! int block; ! int delay_flag; ! if (!PyArg_Parse(args, "i", &block)) ! return NULL; ! Py_BEGIN_ALLOW_THREADS ! socketioctl(s->sock_fd, 0x80046679, (u_long*)&block); ! Py_END_ALLOW_THREADS ! Py_INCREF(Py_None); ! return Py_None; } static char sleeptaskw_doc[] = "sleeptaskw(flag)\n\ *************** *** 1142,1152 **** --- 1344,1393 ---- if (!getsockaddrarg(s, addro, &addr, &addrlen)) return NULL; + + errno = 0; /* Reset the err indicator for use with timeouts */ + Py_BEGIN_ALLOW_THREADS res = connect(s->sock_fd, addr, addrlen); Py_END_ALLOW_THREADS + + if (s->sock_timeout != Py_None) { + if (res < 0) { + /* Return if we're already connected */ + #ifdef MS_WINDOWS + if (errno == WSAEINVAL || errno == WSAEISCONN) + #else + if (errno == EISCONN) + #endif + goto connected; + + /* Check if we have an error */ + if (!s->sock_blocking) + return s->errorhandler (); + /* Check if we have a true failure for a blocking socket */ + #ifdef MS_WINDOWS + if (errno != WSAEWOULDBLOCK) + #else + if (errno != EINPROGRESS && errno != EALREADY && + errno != EWOULDBLOCK) + #endif + return s->errorhandler(); + } + + /* Check if we're ready for the connect via select */ + if (internal_select(s, 1) <= 0) + return NULL; + + /* Complete the connection now */ + Py_BEGIN_ALLOW_THREADS + res = connect(s->sock_fd, addr, addrlen); + Py_END_ALLOW_THREADS + } + if (res < 0) return s->errorhandler(); + + connected: Py_INCREF(Py_None); return Py_None; } *************** *** 1169,1177 **** --- 1410,1455 ---- if (!getsockaddrarg(s, addro, &addr, &addrlen)) return NULL; + + errno = 0; /* Reset the err indicator for use with timeouts */ + Py_BEGIN_ALLOW_THREADS res = connect(s->sock_fd, addr, addrlen); Py_END_ALLOW_THREADS + + if (s->sock_timeout != Py_None) { + if (res < 0) { + /* Return if we're already connected */ + #ifdef MS_WINDOWS + if (errno == WSAEINVAL || errno == WSAEISCONN) + #else + if (errno == EISCONN) + #endif + goto conex_finally; + + /* Check if we have an error */ + if (!s->sock_blocking) + goto conex_finally; + /* Check if we have a true failure for a blocking socket */ + #ifdef MS_WINDOWS + if (errno != WSAEWOULDBLOCK) + #else + if (errno != EINPROGRESS && errno != EALREADY && + errno != EWOULDBLOCK) + #endif + goto conex_finally; + } + + /* Check if we're ready for the connect via select */ + if (internal_select(s, 1) <= 0) + return NULL; + + /* Complete the connection now */ + Py_BEGIN_ALLOW_THREADS + res = connect(s->sock_fd, addr, addrlen); + Py_END_ALLOW_THREADS + } + if (res != 0) { #ifdef MS_WINDOWS res = WSAGetLastError(); *************** *** 1179,1184 **** --- 1457,1464 ---- res = errno; #endif } + + conex_finally: return PyInt_FromLong((long) res); } *************** *** 1385,1403 **** { int len, n, flags = 0; PyObject *buf; if (!PyArg_ParseTuple(args, "i|i:recv", &len, &flags)) return NULL; ! if (len < 0) { PyErr_SetString(PyExc_ValueError, "negative buffersize in connect"); return NULL; } buf = PyString_FromStringAndSize((char *) 0, len); if (buf == NULL) return NULL; Py_BEGIN_ALLOW_THREADS n = recv(s->sock_fd, PyString_AS_STRING(buf), len, flags); Py_END_ALLOW_THREADS if (n < 0) { Py_DECREF(buf); return s->errorhandler(); --- 1665,1695 ---- { int len, n, flags = 0; PyObject *buf; + if (!PyArg_ParseTuple(args, "i|i:recv", &len, &flags)) return NULL; ! ! if (len < 0) { PyErr_SetString(PyExc_ValueError, "negative buffersize in connect"); return NULL; } + buf = PyString_FromStringAndSize((char *) 0, len); if (buf == NULL) return NULL; + + if (s->sock_timeout != Py_None) { + if (s->sock_blocking) { + if (internal_select(s, 0) <= 0) + return NULL; + } + } + Py_BEGIN_ALLOW_THREADS n = recv(s->sock_fd, PyString_AS_STRING(buf), len, flags); Py_END_ALLOW_THREADS + if (n < 0) { Py_DECREF(buf); return s->errorhandler(); *************** *** 1425,1440 **** PyObject *buf = NULL; PyObject *addr = NULL; PyObject *ret = NULL; - int len, n, flags = 0; socklen_t addrlen; if (!PyArg_ParseTuple(args, "i|i:recvfrom", &len, &flags)) return NULL; if (!getsockaddrlen(s, &addrlen)) return NULL; buf = PyString_FromStringAndSize((char *) 0, len); if (buf == NULL) return NULL; Py_BEGIN_ALLOW_THREADS memset(addrbuf, 0, addrlen); n = recvfrom(s->sock_fd, PyString_AS_STRING(buf), len, flags, --- 1717,1741 ---- PyObject *buf = NULL; PyObject *addr = NULL; PyObject *ret = NULL; int len, n, flags = 0; socklen_t addrlen; + if (!PyArg_ParseTuple(args, "i|i:recvfrom", &len, &flags)) return NULL; + if (!getsockaddrlen(s, &addrlen)) return NULL; buf = PyString_FromStringAndSize((char *) 0, len); if (buf == NULL) return NULL; + + if (s->sock_timeout != Py_None) { + if (s->sock_blocking) { + if (internal_select(s, 0) <= 0) + return NULL; + } + } + Py_BEGIN_ALLOW_THREADS memset(addrbuf, 0, addrlen); n = recvfrom(s->sock_fd, PyString_AS_STRING(buf), len, flags, *************** *** 1449,1466 **** #endif ); Py_END_ALLOW_THREADS if (n < 0) { Py_DECREF(buf); return s->errorhandler(); } if (n != len && _PyString_Resize(&buf, n) < 0) return NULL; ! if (!(addr = makesockaddr(s->sock_fd, (struct sockaddr *)addrbuf, addrlen))) goto finally; ret = Py_BuildValue("OO", buf, addr); ! finally: Py_XDECREF(addr); Py_XDECREF(buf); return ret; --- 1750,1771 ---- #endif ); Py_END_ALLOW_THREADS + if (n < 0) { Py_DECREF(buf); return s->errorhandler(); } + if (n != len && _PyString_Resize(&buf, n) < 0) return NULL; ! if (!(addr = makesockaddr(s->sock_fd, (struct sockaddr *)addrbuf, ! addrlen))) goto finally; ret = Py_BuildValue("OO", buf, addr); ! ! finally: Py_XDECREF(addr); Py_XDECREF(buf); return ret; *************** *** 1471,1477 **** \n\ Like recv(buffersize, flags) but also return the sender's address info."; - /* s.send(data [,flags]) method */ static PyObject * --- 1776,1781 ---- *************** *** 1479,1489 **** --- 1783,1803 ---- { char *buf; int len, n, flags = 0; + if (!PyArg_ParseTuple(args, "s#|i:send", &buf, &len, &flags)) return NULL; + + if (s->sock_timeout != Py_None) { + if (s->sock_blocking) { + if (internal_select(s, 1) <= 0) + return NULL; + } + } + Py_BEGIN_ALLOW_THREADS n = send(s->sock_fd, buf, len, flags); Py_END_ALLOW_THREADS + if (n < 0) return s->errorhandler(); return PyInt_FromLong((long)n); *************** *** 1504,1511 **** --- 1818,1834 ---- { char *buf; int len, n, flags = 0; + if (!PyArg_ParseTuple(args, "s#|i:sendall", &buf, &len, &flags)) return NULL; + + if (s->sock_timeout != Py_None) { + if (s->sock_blocking) { + if (internal_select(s, 1) < 0) + return NULL; + } + } + Py_BEGIN_ALLOW_THREADS do { n = send(s->sock_fd, buf, len, flags); *************** *** 1515,1522 **** --- 1838,1847 ---- len -= n; } while (len > 0); Py_END_ALLOW_THREADS + if (n < 0) return s->errorhandler(); + Py_INCREF(Py_None); return Py_None; } *************** *** 1539,1544 **** --- 1864,1870 ---- char *buf; struct sockaddr *addr; int addrlen, len, n, flags; + flags = 0; if (!PyArg_ParseTuple(args, "s#O:sendto", &buf, &len, &addro)) { PyErr_Clear(); *************** *** 1546,1556 **** --- 1872,1892 ---- &buf, &len, &flags, &addro)) return NULL; } + if (!getsockaddrarg(s, addro, &addr, &addrlen)) return NULL; + + if (s->sock_timeout != Py_None) { + if (s->sock_blocking) { + if (internal_select(s, 1) <= 0) + return NULL; + } + } + Py_BEGIN_ALLOW_THREADS n = sendto(s->sock_fd, buf, len, flags, addr, addrlen); Py_END_ALLOW_THREADS + if (n < 0) return s->errorhandler(); return PyInt_FromLong((long)n); *************** *** 1635,1640 **** --- 1971,1980 ---- sendto_doc}, {"setblocking", (PyCFunction)PySocketSock_setblocking, METH_O, setblocking_doc}, + {"settimeout", (PyCFunction)PySocketSock_settimeout, METH_O, + settimeout_doc}, + {"gettimeout", (PyCFunction)PySocketSock_gettimeout, METH_NOARGS, + gettimeout_doc}, {"setsockopt", (PyCFunction)PySocketSock_setsockopt, METH_VARARGS, setsockopt_doc}, {"shutdown", (PyCFunction)PySocketSock_shutdown, METH_O, *************** *** 1711,1719 **** --- 2051,2061 ---- "|iii:socket", keywords, &family, &type, &proto)) return -1; + Py_BEGIN_ALLOW_THREADS fd = socket(family, type, proto); Py_END_ALLOW_THREADS + #ifdef MS_WINDOWS if (fd == INVALID_SOCKET) #else *************** *** 1729,1735 **** --- 2071,2079 ---- #ifdef SIGPIPE (void) signal(SIGPIPE, SIG_IGN); #endif + return 0; + } *************** *** 1883,1888 **** --- 2227,2233 ---- #endif return NULL; } + if (h->h_addrtype != af) { #ifdef HAVE_STRERROR /* Let's get real error message to return */ *************** *** 1893,1927 **** --- 2238,2284 ---- #endif return NULL; } + switch (af) { + case AF_INET: if (alen < sizeof(struct sockaddr_in)) return NULL; break; + #ifdef ENABLE_IPV6 case AF_INET6: if (alen < sizeof(struct sockaddr_in6)) return NULL; break; #endif + } + if ((name_list = PyList_New(0)) == NULL) goto err; + if ((addr_list = PyList_New(0)) == NULL) goto err; + for (pch = h->h_aliases; *pch != NULL; pch++) { int status; tmp = PyString_FromString(*pch); if (tmp == NULL) goto err; + status = PyList_Append(name_list, tmp); Py_DECREF(tmp); + if (status) goto err; } + for (pch = h->h_addr_list; *pch != NULL; pch++) { int status; + switch (af) { + case AF_INET: { struct sockaddr_in sin; *************** *** 1932,1941 **** --- 2289,2300 ---- #endif memcpy(&sin.sin_addr, *pch, sizeof(sin.sin_addr)); tmp = makeipaddr((struct sockaddr *)&sin, sizeof(sin)); + if (pch == h->h_addr_list && alen >= sizeof(sin)) memcpy((char *) addr, &sin, sizeof(sin)); break; } + #ifdef ENABLE_IPV6 case AF_INET6: { *************** *** 1948,1971 **** --- 2307,2337 ---- memcpy(&sin6.sin6_addr, *pch, sizeof(sin6.sin6_addr)); tmp = makeipaddr((struct sockaddr *)&sin6, sizeof(sin6)); + if (pch == h->h_addr_list && alen >= sizeof(sin6)) memcpy((char *) addr, &sin6, sizeof(sin6)); break; } #endif + default: /* can't happen */ PyErr_SetString(PySocket_Error, "unsupported address family"); return NULL; } + if (tmp == NULL) goto err; + status = PyList_Append(addr_list, tmp); Py_DECREF(tmp); + if (status) goto err; } + rtn_tuple = Py_BuildValue("sOO", h->h_name, name_list, addr_list); + err: Py_XDECREF(name_list); Py_XDECREF(addr_list); *************** *** 2020,2029 **** h = gethostbyname(name); #endif /* HAVE_GETHOSTBYNAME_R */ Py_END_ALLOW_THREADS ! /* Some C libraries would require addr.__ss_family instead of addr.ss_family. ! Therefore, we cast the sockaddr_storage into sockaddr to access sa_family. */ sa = (struct sockaddr*)&addr; ! ret = gethost_common(h, (struct sockaddr *)&addr, sizeof(addr), sa->sa_family); #ifdef USE_GETHOSTBYNAME_LOCK PyThread_release_lock(gethostbyname_lock); #endif --- 2386,2399 ---- h = gethostbyname(name); #endif /* HAVE_GETHOSTBYNAME_R */ Py_END_ALLOW_THREADS ! /* Some C libraries would require addr.__ss_family instead of ! * addr.ss_family. ! * Therefore, we cast the sockaddr_storage into sockaddr to ! * access sa_family. ! */ sa = (struct sockaddr*)&addr; ! ret = gethost_common(h, (struct sockaddr *)&addr, sizeof(addr), ! sa->sa_family); #ifdef USE_GETHOSTBYNAME_LOCK PyThread_release_lock(gethostbyname_lock); #endif *************** *** 2737,2742 **** --- 3107,3116 ---- if (PyModule_AddObject(m, PySocket_CAPI_NAME, PyCObject_FromVoidPtr((void *)&PySocketModuleAPI, NULL) ) != 0) + return; + + /* Import in the select module for implementing timeout functionality */ + if ((PySelectModule = PyImport_ImportModule("select")) == NULL) return; /* Address families (we only support AF_INET and AF_UNIX) */ *** python.orig/dist/src/Modules/socketmodule.h Fri Mar 1 03:31:07 2002 --- python/python/dist/src/Modules/socketmodule.h Mon Jun 3 11:13:38 2002 *************** *** 83,88 **** --- 83,91 ---- PyObject *(*errorhandler)(void); /* Error handler; checks errno, returns NULL and sets a Python exception */ + int sock_blocking; /* Flag indicated whether the socket is + * in blocking mode */ + PyObject *sock_timeout; /* Operation timeout value */ } PySocketSockObject; /* --- C API ----------------------------------------------------*/ *** python.orig/dist/src/Lib/socket.py Sat Feb 16 23:25:24 2002 --- python/python/dist/src/Lib/socket.py Wed Jun 5 15:33:35 2002 *************** *** 134,140 **** _socketmethods = ( 'bind', 'connect', 'connect_ex', 'fileno', 'listen', 'getpeername', 'getsockname', 'getsockopt', 'setsockopt', ! 'recv', 'recvfrom', 'send', 'sendall', 'sendto', 'setblocking', 'shutdown') class _socketobject: --- 134,141 ---- _socketmethods = ( 'bind', 'connect', 'connect_ex', 'fileno', 'listen', 'getpeername', 'getsockname', 'getsockopt', 'setsockopt', ! 'recv', 'recvfrom', 'send', 'sendall', 'sendto', 'setblocking', ! 'settimeout', 'gettimeout', 'shutdown') class _socketobject: *************** *** 168,261 **** class _fileobject: ! def __init__(self, sock, mode, bufsize): self._sock = sock self._mode = mode ! if bufsize < 0: bufsize = 512 ! self._rbufsize = max(1, bufsize) self._wbufsize = bufsize ! self._wbuf = self._rbuf = "" def close(self): try: if self._sock: self.flush() finally: ! self._sock = 0 def __del__(self): self.close() def flush(self): if self._wbuf: ! self._sock.sendall(self._wbuf) ! self._wbuf = "" ! def fileno(self): return self._sock.fileno() def write(self, data): ! self._wbuf = self._wbuf + data if self._wbufsize == 1: if '\n' in data: ! self.flush() ! else: ! if len(self._wbuf) >= self._wbufsize: ! self.flush() def writelines(self, list): filter(self._sock.sendall, list) self.flush() ! def read(self, n=-1): ! if n >= 0: ! k = len(self._rbuf) ! if n <= k: ! data = self._rbuf[:n] ! self._rbuf = self._rbuf[n:] ! return data ! n = n - k ! L = [self._rbuf] ! self._rbuf = "" ! while n > 0: ! new = self._sock.recv(max(n, self._rbufsize)) ! if not new: break ! k = len(new) ! if k > n: ! L.append(new[:n]) ! self._rbuf = new[n:] ! break ! L.append(new) ! n = n - k ! return "".join(L) ! k = max(512, self._rbufsize) ! L = [self._rbuf] ! self._rbuf = "" ! while 1: ! new = self._sock.recv(k) ! if not new: break ! L.append(new) ! k = min(k*2, 1024**2) ! return "".join(L) ! ! def readline(self, limit=-1): ! data = "" ! i = self._rbuf.find('\n') ! while i < 0 and not (0 < limit <= len(self._rbuf)): ! new = self._sock.recv(self._rbufsize) ! if not new: break ! i = new.find('\n') ! if i >= 0: i = i + len(self._rbuf) ! self._rbuf = self._rbuf + new ! if i < 0: i = len(self._rbuf) ! else: i = i+1 ! if 0 <= limit < len(self._rbuf): i = limit ! data, self._rbuf = self._rbuf[:i], self._rbuf[i:] return data ! def readlines(self, sizehint = 0): total = 0 list = [] while 1: --- 169,276 ---- class _fileobject: + """Implements a file object on top of a regular socket object.""" ! def __init__(self, sock, mode='rb', bufsize=8192): self._sock = sock self._mode = mode ! if bufsize <= 0: bufsize = 512 ! self._rbufsize = bufsize self._wbufsize = bufsize ! self._rbuf = [ ] ! self._wbuf = [ ] def close(self): try: if self._sock: self.flush() finally: ! self._sock = None def __del__(self): self.close() def flush(self): if self._wbuf: ! buffer = ''.join(self._wbuf) ! self._sock.sendall(buffer) ! self._wbuf = [ ] ! def fileno (self): return self._sock.fileno() def write(self, data): ! self._wbuf.append (data) ! # A _wbufsize of 1 means we're doing unbuffered IO. ! # Flush accordingly. if self._wbufsize == 1: if '\n' in data: ! self.flush () ! elif self.__get_wbuf_len() >= self._wbufsize: ! self.flush() def writelines(self, list): filter(self._sock.sendall, list) self.flush() ! def __get_wbuf_len (self): ! buf_len = 0 ! for i in [len(x) for x in self._wbuf]: ! buf_len += i ! return buf_len ! ! def __get_rbuf_len(self): ! buf_len = 0 ! for i in [len(x) for x in self._rbuf]: ! buf_len += i ! return buf_len ! ! def read(self, size=-1): ! buf_len = self.__get_rbuf_len() ! while size < 0 or buf_len < size: ! recv_size = max(self._rbufsize, size - buf_len) ! data = self._sock.recv(recv_size) ! if not data: ! break ! buf_len += len(data) ! self._rbuf.append(data) ! data = ''.join(self._rbuf) ! # Clear the rbuf at the end so we're not affected by ! # an exception during a recv ! self._rbuf = [ ] ! if buf_len > size and size >= 0: ! self._rbuf.append(data[size:]) ! data = data[:size] ! return data ! ! def readline(self, size=-1): ! index = -1 ! buf_len = self.__get_rbuf_len() ! if len (self._rbuf): ! index = min([x.find('\n') for x in self._rbuf]) ! while index < 0 and (size < 0 or buf_len < size): ! recv_size = max(self._rbufsize, size - buf_len) ! data = self._sock.recv(recv_size) ! if not data: ! break ! buf_len += len(data) ! self._rbuf.append(data) ! index = data.find('\n') ! data = ''.join(self._rbuf) ! self._rbuf = [ ] ! index = data.find('\n') ! if index >= 0: ! index += 1 ! elif buf_len > size: ! index = size ! else: ! index = buf_len ! self._rbuf.append(data[index:]) ! data = data[:index] return data ! def readlines(self, sizehint=0): total = 0 list = [] while 1: *** python.orig/dist/src/Lib/test/test_socket.py Sun Dec 9 03:57:46 2001 --- python/python/dist/src/Lib/test/test_socket.py Wed Jun 5 17:55:37 2002 *************** *** 109,114 **** --- 109,115 ---- canfork = hasattr(os, 'fork') try: PORT = 50007 + msg = 'socket test\n' if not canfork or os.fork(): # parent is server s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) *************** *** 133,145 **** f = conn.makefile() if verbose: print 'file obj:', f while 1: ! data = conn.recv(1024) ! if not data: break ! if verbose: ! print 'received:', data ! conn.sendall(data) conn.close() else: try: --- 134,185 ---- f = conn.makefile() if verbose: print 'file obj:', f + data = conn.recv(1024) + if verbose: + print 'received:', data + conn.sendall(data) + + # Perform a few tests on the windows file object + if verbose: + print "Staring _fileobject tests..." + f = socket._fileobject (conn, 'rb', 8192) + first_seg = f.read(7) + second_seg = f.read(5) + if not first_seg == 'socket ' or not second_seg == 'test\n': + print "Error performing read with the python _fileobject class" + os._exit (1) + elif verbose: + print "_fileobject buffered read works" + f.write (data) + f.flush () + + buf = '' while 1: ! char = f.read(1) ! if not char: ! print "Error performing unbuffered read with the python ", \ ! "_fileobject class" ! os._exit (1) ! buf += char ! if buf == msg: ! if verbose: ! print "__fileobject unbuffered read works" break ! if verbose: ! # If we got this far, write() must work as well ! print "__fileobject write works" ! f.write(buf) ! f.flush() ! ! line = f.readline() ! if not line == msg: ! print "Error perferming readline with the python _fileobject class" ! os._exit (1) ! f.write(line) ! f.flush() ! if verbose: ! print "__fileobject readline works" ! conn.close() else: try: *************** *** 149,159 **** if verbose: print 'child connecting' s.connect(("127.0.0.1", PORT)) ! msg = 'socket test' ! s.send(msg) ! data = s.recv(1024) ! if msg != data: ! print 'parent/client mismatch' s.close() finally: os._exit(1) --- 189,206 ---- if verbose: print 'child connecting' s.connect(("127.0.0.1", PORT)) ! ! iteration = 0 ! while 1: ! s.send(msg) ! data = s.recv(12) ! if not data: ! break ! if msg != data: ! print "parent/client mismatch. Failed in %s iteration. Received: [%s]" \ ! %(iteration, data) ! time.sleep (1) ! iteration += 1 s.close() finally: os._exit(1) *** python.orig/dist/src/Doc/lib/libsocket.tex Sat Dec 22 14:07:58 2001 --- python/python/dist/src/Doc/lib/libsocket.tex Mon Jun 3 10:08:39 2002 *************** *** 514,519 **** --- 514,542 ---- block until they can proceed. \end{methoddesc} + \begin{methoddesc}[socket]{settimeout}{value} + Set a timeout on blocking socket operations. Value can be any numeric value + or \var{None}. Socket operations will raise an \exception{error} exception + if the timeout period \var{value} has elapsed before the operation has + completed. Setting a timeout of \var{None} disables timeouts on socket + operations. + \end{methoddesc} + + \begin{methoddesc}[socket]{gettimeout}{} + Returns the timeout in floating seconds associated with socket operations. + A timeout of None indicates that timeouts on socket operations are + disabled. + \end{methoddesc} + + Some notes on the interaction between socket blocking and timeouts: + socket blocking mode takes precendence over timeouts. If a socket + if set to non-blocking mode, then timeouts set on sockets are never + don't mean anything. The timeout value associated with the socket + can still be set via settimeout and its value retrieved via gettimeout, + but the timeout is never enforced (i.e, an exception will never be + thrown). Otherwise, if the socket is in blocking mode, setting the + timeout will raise an exception as expected. + \begin{methoddesc}[socket]{setsockopt}{level, optname, value} Set the value of the given socket option (see the \UNIX{} manual page \manpage{setsockopt}{2}). The needed symbolic constants are defined in