diff options
Diffstat (limited to 'Modules/socketmodule.c')
-rw-r--r-- | Modules/socketmodule.c | 224 |
1 files changed, 138 insertions, 86 deletions
diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 262abe8..bb99bde 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -161,7 +161,8 @@ shutdown(how) -- shut down traffic in one or both directions\n\ (this includes the getaddrinfo emulation) protect access with a lock. */ #if defined(WITH_THREAD) && (defined(__APPLE__) || \ (defined(__FreeBSD__) && __FreeBSD_version+0 < 503000) || \ - defined(__OpenBSD__) || defined(__NetBSD__) || !defined(HAVE_GETADDRINFO)) + defined(__OpenBSD__) || defined(__NetBSD__) || \ + defined(__VMS) || !defined(HAVE_GETADDRINFO)) #define USE_GETADDRINFO_LOCK #endif @@ -186,15 +187,8 @@ shutdown(how) -- shut down traffic in one or both directions\n\ #endif #if defined(__VMS) -#if ! defined(_SOCKADDR_LEN) -# ifdef getaddrinfo -# undef getaddrinfo -# endif -# include "TCPIP_IOCTL_ROUTINE" -#else # include <ioctl.h> #endif -#endif #if defined(PYOS_OS2) # define INCL_DOS @@ -234,7 +228,9 @@ shutdown(how) -- shut down traffic in one or both directions\n\ #endif /* Generic includes */ +#ifdef HAVE_SYS_TYPES_H #include <sys/types.h> +#endif /* Generic socket object definitions and includes */ #define PySocket_BUILDING_SOCKET @@ -270,7 +266,9 @@ int h_errno; /* not used */ #else /* MS_WINDOWS includes */ -# include <fcntl.h> +# ifdef HAVE_FCNTL_H +# include <fcntl.h> +# endif #endif @@ -290,7 +288,7 @@ int h_errno; /* not used */ * _SS_ALIGNSIZE is defined in sys/socket.h by 6.5.21, * for example, but not by 6.5.10. */ -#elif defined(_MSC_VER) && _MSC_VER>1200 +#elif defined(_MSC_VER) && _MSC_VER>1201 /* Do not include addrinfo.h for MSVC7 or greater. 'addrinfo' and * EAI_* constants are defined in (the already included) ws2tcpip.h. */ @@ -359,11 +357,6 @@ const char *inet_ntop(int af, const void *src, char *dst, socklen_t size); #define SOCKETCLOSE close #endif -#ifdef __VMS -/* TCP/IP Services for VMS uses a maximum send/revc buffer length of 65535 */ -#define SEGMENT_SIZE 65535 -#endif - #if defined(HAVE_BLUETOOTH_H) || defined(HAVE_BLUETOOTH_BLUETOOTH_H) #define USE_BLUETOOTH 1 #if defined(__FreeBSD__) @@ -374,6 +367,14 @@ const char *inet_ntop(int af, const void *src, char *dst, socklen_t size); #define _BT_SOCKADDR_MEMB(s, proto) &((s)->sock_addr) #define _BT_L2_MEMB(sa, memb) ((sa)->l2cap_##memb) #define _BT_RC_MEMB(sa, memb) ((sa)->rfcomm_##memb) +#elif defined(__NetBSD__) +#define sockaddr_l2 sockaddr_bt +#define sockaddr_rc sockaddr_bt +#define sockaddr_sco sockaddr_bt +#define _BT_SOCKADDR_MEMB(s, proto) &((s)->sock_addr) +#define _BT_L2_MEMB(sa, memb) ((sa)->bt_##memb) +#define _BT_RC_MEMB(sa, memb) ((sa)->bt_##memb) +#define _BT_SCO_MEMB(sa, memb) ((sa)->bt_##memb) #else #define _BT_SOCKADDR_MEMB(s, proto) (&((s)->sock_addr).bt_##proto) #define _BT_L2_MEMB(sa, memb) ((sa)->l2_##memb) @@ -382,6 +383,11 @@ const char *inet_ntop(int af, const void *src, char *dst, socklen_t size); #endif #endif +#ifdef __VMS +/* TCP/IP Services for VMS uses a maximum send/recv buffer length */ +#define SEGMENT_SIZE (32 * 1024 -1) +#endif + /* * Constants for getnameinfo() */ @@ -413,14 +419,24 @@ static int taskwindow; there has to be a circular reference. */ static PyTypeObject sock_type; -/* Can we call select() with this socket without a buffer overrun? */ +#if defined(HAVE_POLL_H) +#include <poll.h> +#elif defined(HAVE_SYS_POLL_H) +#include <sys/poll.h> +#endif + #ifdef Py_SOCKET_FD_CAN_BE_GE_FD_SETSIZE /* Platform can select file descriptors beyond FD_SETSIZE */ #define IS_SELECTABLE(s) 1 +#elif defined(HAVE_POLL) +/* Instead of select(), we'll use poll() since poll() works on any fd. */ +#define IS_SELECTABLE(s) 1 +/* Can we call select() with this socket without a buffer overrun? */ #else /* POSIX says selecting file descriptors beyond FD_SETSIZE - has undefined behaviour. */ -#define IS_SELECTABLE(s) ((s)->sock_fd < FD_SETSIZE) + has undefined behaviour. If there's no timeout left, we don't have to + call select, so it's a safe, little white lie. */ +#define IS_SELECTABLE(s) ((s)->sock_fd < FD_SETSIZE || s->sock_timeout <= 0.0) #endif static PyObject* @@ -616,6 +632,30 @@ set_gaierror(int error) return NULL; } +#ifdef __VMS +/* Function to send in segments */ +static int +sendsegmented(int sock_fd, char *buf, int len, int flags) +{ + int n = 0; + int remaining = len; + + while (remaining > 0) { + unsigned int segment; + + segment = (remaining >= SEGMENT_SIZE ? SEGMENT_SIZE : remaining); + n = send(sock_fd, buf, segment, flags); + if (n < 0) { + return n; + } + remaining -= segment; + buf += segment; + } /* end while */ + + return len; +} +#endif + /* Function to perform the setting of socket blocking mode internally. block = (1 | 0). */ static int @@ -640,8 +680,8 @@ internal_setblocking(PySocketSockObject *s, int block) ioctl(s->sock_fd, FIONBIO, (caddr_t)&block, sizeof(block)); #elif defined(__VMS) block = !block; - ioctl(s->sock_fd, FIONBIO, (char *)&block); -#else /* !PYOS_OS2 && !_VMS */ + ioctl(s->sock_fd, FIONBIO, (unsigned int *)&block); +#else /* !PYOS_OS2 && !__VMS */ delay_flag = fcntl(s->sock_fd, F_GETFL, 0); if (block) delay_flag &= (~O_NONBLOCK); @@ -664,16 +704,14 @@ internal_setblocking(PySocketSockObject *s, int block) return 1; } -/* Do a select() on the socket, if necessary (sock_timeout > 0). +/* Do a select()/poll() on the socket, if necessary (sock_timeout > 0). The argument writing indicates the direction. This does not raise an exception; we'll let our caller do that after they've reacquired the interpreter lock. - Returns 1 on timeout, 0 otherwise. */ + Returns 1 on timeout, -1 on error, 0 otherwise. */ static int internal_select(PySocketSockObject *s, int writing) { - fd_set fds; - struct timeval tv; int n; /* Nothing to do unless we're in timeout mode (not non-blocking) */ @@ -684,17 +722,40 @@ internal_select(PySocketSockObject *s, int writing) if (s->sock_fd < 0) return 0; - /* Construct the arguments to select */ - tv.tv_sec = (int)s->sock_timeout; - tv.tv_usec = (int)((s->sock_timeout - tv.tv_sec) * 1e6); - FD_ZERO(&fds); - FD_SET(s->sock_fd, &fds); + /* Prefer poll, if available, since you can poll() any fd + * which can't be done with select(). */ +#ifdef HAVE_POLL + { + struct pollfd pollfd; + int timeout; - /* See if the socket is ready */ - if (writing) - n = select(s->sock_fd+1, NULL, &fds, NULL, &tv); - else - n = select(s->sock_fd+1, &fds, NULL, NULL, &tv); + pollfd.fd = s->sock_fd; + pollfd.events = writing ? POLLOUT : POLLIN; + + /* s->sock_timeout is in seconds, timeout in ms */ + timeout = (int)(s->sock_timeout * 1000 + 0.5); + n = poll(&pollfd, 1, timeout); + } +#else + { + /* Construct the arguments to select */ + fd_set fds; + struct timeval tv; + tv.tv_sec = (int)s->sock_timeout; + tv.tv_usec = (int)((s->sock_timeout - tv.tv_sec) * 1e6); + FD_ZERO(&fds); + FD_SET(s->sock_fd, &fds); + + /* See if the socket is ready */ + if (writing) + n = select(s->sock_fd+1, NULL, &fds, NULL, &tv); + else + n = select(s->sock_fd+1, &fds, NULL, NULL, &tv); + } +#endif + + if (n < 0) + return -1; if (n == 0) return 1; return 0; @@ -1494,7 +1555,7 @@ sock_accept(PySocketSockObject *s) &addrlen); Py_END_ALLOW_THREADS - if (timeout) { + if (timeout == 1) { PyErr_SetString(socket_timeout, "timed out"); return NULL; } @@ -1721,6 +1782,8 @@ sock_getsockopt(PySocketSockObject *s, PyObject *args) return PyInt_FromLong(flag); } #ifdef __VMS + /* socklen_t is unsigned so no negative test is needed, + test buflen == 0 is previously done */ if (buflen > 1024) { #else if (buflen <= 0 || buflen > 1024) { @@ -1863,9 +1926,15 @@ internal_connect(PySocketSockObject *s, struct sockaddr *addr, int addrlen, if (s->sock_timeout > 0.0) { if (res < 0 && errno == EINPROGRESS && IS_SELECTABLE(s)) { timeout = internal_select(s, 1); - res = connect(s->sock_fd, addr, addrlen); - if (res < 0 && errno == EISCONN) - res = 0; + if (timeout == 0) { + res = connect(s->sock_fd, addr, addrlen); + if (res < 0 && errno == EISCONN) + res = 0; + } + else if (timeout == -1) + res = errno; /* had error */ + else + res = EWOULDBLOCK; /* timed out */ } } @@ -1895,7 +1964,7 @@ sock_connect(PySocketSockObject *s, PyObject *addro) res = internal_connect(s, addr, addrlen, &timeout); Py_END_ALLOW_THREADS - if (timeout) { + if (timeout == 1) { PyErr_SetString(socket_timeout, "timed out"); return NULL; } @@ -1929,6 +1998,13 @@ sock_connect_ex(PySocketSockObject *s, PyObject *addro) res = internal_connect(s, addr, addrlen, &timeout); Py_END_ALLOW_THREADS + /* Signals are not errors (though they may raise exceptions). Adapted + from PyErr_SetFromErrnoWithFilenameObject(). */ +#ifdef EINTR + if (res == EINTR && PyErr_CheckSignals()) + return NULL; +#endif + return PyInt_FromLong((long) res); } @@ -2149,10 +2225,10 @@ The mode and buffersize arguments are as for the built-in open() function."); static ssize_t sock_recv_guts(PySocketSockObject *s, char* cbuf, int len, int flags) { - ssize_t outlen = 0; + ssize_t outlen = -1; int timeout; #ifdef __VMS - int remaining, nread; + int remaining; char *read_buf; #endif @@ -2168,7 +2244,7 @@ sock_recv_guts(PySocketSockObject *s, char* cbuf, int len, int flags) outlen = recv(s->sock_fd, cbuf, len, flags); Py_END_ALLOW_THREADS - if (timeout) { + if (timeout == 1) { PyErr_SetString(socket_timeout, "timed out"); return -1; } @@ -2183,6 +2259,7 @@ sock_recv_guts(PySocketSockObject *s, char* cbuf, int len, int flags) remaining = len; while (remaining != 0) { unsigned int segment; + int nread = -1; segment = remaining /SEGMENT_SIZE; if (segment != 0) { @@ -2198,7 +2275,7 @@ sock_recv_guts(PySocketSockObject *s, char* cbuf, int len, int flags) nread = recv(s->sock_fd, read_buf, segment, flags); Py_END_ALLOW_THREADS - if (timeout) { + if (timeout == 1) { PyErr_SetString(socket_timeout, "timed out"); return -1; } @@ -2247,7 +2324,7 @@ sock_recv(PySocketSockObject *s, PyObject *args) /* Call the guts */ outlen = sock_recv_guts(s, PyString_AS_STRING(buf), recvlen, flags); if (outlen < 0) { - /* An error occured, release the string and return an + /* An error occurred, release the string and return an error. */ Py_DECREF(buf); return NULL; @@ -2346,7 +2423,7 @@ sock_recvfrom_guts(PySocketSockObject *s, char* cbuf, int len, int flags, { sock_addr_t addrbuf; int timeout; - ssize_t n = 0; + ssize_t n = -1; socklen_t addrlen; *addr = NULL; @@ -2378,7 +2455,7 @@ sock_recvfrom_guts(PySocketSockObject *s, char* cbuf, int len, int flags, } Py_END_ALLOW_THREADS - if (timeout) { + if (timeout == 1) { PyErr_SetString(socket_timeout, "timed out"); return -1; } @@ -2493,10 +2570,7 @@ static PyObject * sock_send(PySocketSockObject *s, PyObject *args) { char *buf; - int len, n = 0, flags = 0, timeout; -#ifdef __VMS - int send_length; -#endif + int len, n = -1, flags = 0, timeout; if (!PyArg_ParseTuple(args, "s#|i:send", &buf, &len, &flags)) return NULL; @@ -2504,49 +2578,22 @@ sock_send(PySocketSockObject *s, PyObject *args) if (!IS_SELECTABLE(s)) return select_error(); -#ifndef __VMS Py_BEGIN_ALLOW_THREADS timeout = internal_select(s, 1); if (!timeout) +#ifdef __VMS + n = sendsegmented(s->sock_fd, buf, len, flags); +#else n = send(s->sock_fd, buf, len, flags); +#endif Py_END_ALLOW_THREADS - if (timeout) { + if (timeout == 1) { PyErr_SetString(socket_timeout, "timed out"); return NULL; } if (n < 0) return s->errorhandler(); -#else - /* Divide packet into smaller segments for */ - /* TCP/IP Services for OpenVMS */ - send_length = len; - while (send_length != 0) { - unsigned int segment; - - segment = send_length / SEGMENT_SIZE; - if (segment != 0) { - segment = SEGMENT_SIZE; - } - else { - segment = send_length; - } - Py_BEGIN_ALLOW_THREADS - timeout = internal_select(s, 1); - if (!timeout) - n = send(s->sock_fd, buf, segment, flags); - Py_END_ALLOW_THREADS - if (timeout) { - PyErr_SetString(socket_timeout, "timed out"); - return NULL; - } - if (n < 0) { - return s->errorhandler(); - } - send_length -= segment; - buf += segment; - } /* end while */ -#endif /* !__VMS */ return PyInt_FromLong((long)n); } @@ -2564,7 +2611,7 @@ static PyObject * sock_sendall(PySocketSockObject *s, PyObject *args) { char *buf; - int len, n = 0, flags = 0, timeout; + int len, n = -1, flags = 0, timeout; if (!PyArg_ParseTuple(args, "s#|i:sendall", &buf, &len, &flags)) return NULL; @@ -2575,9 +2622,14 @@ sock_sendall(PySocketSockObject *s, PyObject *args) Py_BEGIN_ALLOW_THREADS do { timeout = internal_select(s, 1); + n = -1; if (timeout) break; +#ifdef __VMS + n = sendsegmented(s->sock_fd, buf, len, flags); +#else n = send(s->sock_fd, buf, len, flags); +#endif if (n < 0) break; buf += n; @@ -2585,7 +2637,7 @@ sock_sendall(PySocketSockObject *s, PyObject *args) } while (len > 0); Py_END_ALLOW_THREADS - if (timeout) { + if (timeout == 1) { PyErr_SetString(socket_timeout, "timed out"); return NULL; } @@ -2613,7 +2665,7 @@ sock_sendto(PySocketSockObject *s, PyObject *args) PyObject *addro; char *buf; struct sockaddr *addr; - int addrlen, len, n = 0, flags, timeout; + int addrlen, len, n = -1, flags, timeout; flags = 0; if (!PyArg_ParseTuple(args, "s#O:sendto", &buf, &len, &addro)) { @@ -2635,7 +2687,7 @@ sock_sendto(PySocketSockObject *s, PyObject *args) n = sendto(s->sock_fd, buf, len, flags, addr, addrlen); Py_END_ALLOW_THREADS - if (timeout) { + if (timeout == 1) { PyErr_SetString(socket_timeout, "timed out"); return NULL; } |