summaryrefslogtreecommitdiffstats
path: root/Modules/socketmodule.c
diff options
context:
space:
mode:
Diffstat (limited to 'Modules/socketmodule.c')
-rw-r--r--Modules/socketmodule.c224
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;
}