Patch #1544279: Improve thread-safety of the socket module by moving

the sock_addr_t storage out of the socket object.
Will backport to 2.5.
This commit is contained in:
Martin v. Löwis 2006-12-03 11:23:45 +00:00
parent 8609da9b17
commit 046c4d13be
3 changed files with 48 additions and 53 deletions

View File

@ -240,6 +240,9 @@ Library
Extension Modules
-----------------
- Patch #1544279: Improve thread-safety of the socket module by moving
the sock_addr_t storage out of the socket object.
- Speed up function calls into the math module.
- Bug #1588217: don't parse "= " as a soft line break in binascii's

View File

@ -364,19 +364,16 @@ const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
#define BTPROTO_RFCOMM BLUETOOTH_PROTO_RFCOMM
#define sockaddr_l2 sockaddr_l2cap
#define sockaddr_rc sockaddr_rfcomm
#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)
#define _BT_RC_MEMB(sa, memb) ((sa)->rc_##memb)
#define _BT_SCO_MEMB(sa, memb) ((sa)->sco_##memb)
@ -388,6 +385,8 @@ const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
#define SEGMENT_SIZE (32 * 1024 -1)
#endif
#define SAS2SA(x) ((struct sockaddr *)(x))
/*
* Constants for getnameinfo()
*/
@ -1174,7 +1173,7 @@ makesockaddr(int sockfd, struct sockaddr *addr, int addrlen, int proto)
static int
getsockaddrarg(PySocketSockObject *s, PyObject *args,
struct sockaddr **addr_ret, int *len_ret)
struct sockaddr *addr_ret, int *len_ret)
{
switch (s->sock_family) {
@ -1184,9 +1183,10 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
struct sockaddr_un* addr;
char *path;
int len;
addr = (struct sockaddr_un*)&(s->sock_addr).un;
if (!PyArg_Parse(args, "t#", &path, &len))
return 0;
addr = (struct sockaddr_un*)addr_ret;
#ifdef linux
if (len > 0 && path[0] == 0) {
/* Linux abstract namespace extension */
@ -1209,7 +1209,6 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
}
addr->sun_family = s->sock_family;
memcpy(addr->sun_path, path, len);
*addr_ret = (struct sockaddr *) addr;
#if defined(PYOS_OS2)
*len_ret = sizeof(*addr);
#else
@ -1224,7 +1223,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
{
struct sockaddr_nl* addr;
int pid, groups;
addr = (struct sockaddr_nl *)&(s->sock_addr).nl;
addr = (struct sockaddr_nl *)addr_ret;
if (!PyTuple_Check(args)) {
PyErr_Format(
PyExc_TypeError,
@ -1238,7 +1237,6 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
addr->nl_family = AF_NETLINK;
addr->nl_pid = pid;
addr->nl_groups = groups;
*addr_ret = (struct sockaddr *) addr;
*len_ret = sizeof(*addr);
return 1;
}
@ -1249,7 +1247,6 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
struct sockaddr_in* addr;
char *host;
int port, result;
addr=(struct sockaddr_in*)&(s->sock_addr).in;
if (!PyTuple_Check(args)) {
PyErr_Format(
PyExc_TypeError,
@ -1261,6 +1258,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
if (!PyArg_ParseTuple(args, "eti:getsockaddrarg",
"idna", &host, &port))
return 0;
addr=(struct sockaddr_in*)addr_ret;
result = setipaddr(host, (struct sockaddr *)addr,
sizeof(*addr), AF_INET);
PyMem_Free(host);
@ -1268,7 +1266,6 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
return 0;
addr->sin_family = AF_INET;
addr->sin_port = htons((short)port);
*addr_ret = (struct sockaddr *) addr;
*len_ret = sizeof *addr;
return 1;
}
@ -1279,7 +1276,6 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
struct sockaddr_in6* addr;
char *host;
int port, flowinfo, scope_id, result;
addr = (struct sockaddr_in6*)&(s->sock_addr).in6;
flowinfo = scope_id = 0;
if (!PyTuple_Check(args)) {
PyErr_Format(
@ -1294,6 +1290,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
&scope_id)) {
return 0;
}
addr = (struct sockaddr_in6*)addr_ret;
result = setipaddr(host, (struct sockaddr *)addr,
sizeof(*addr), AF_INET6);
PyMem_Free(host);
@ -1303,7 +1300,6 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
addr->sin6_port = htons((short)port);
addr->sin6_flowinfo = flowinfo;
addr->sin6_scope_id = scope_id;
*addr_ret = (struct sockaddr *) addr;
*len_ret = sizeof *addr;
return 1;
}
@ -1315,9 +1311,10 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
switch (s->sock_proto) {
case BTPROTO_L2CAP:
{
struct sockaddr_l2 *addr = (struct sockaddr_l2 *) _BT_SOCKADDR_MEMB(s, l2);
struct sockaddr_l2 *addr;
char *straddr;
addr = (struct sockaddr_l2 *)addr_ret;
_BT_L2_MEMB(addr, family) = AF_BLUETOOTH;
if (!PyArg_ParseTuple(args, "si", &straddr,
&_BT_L2_MEMB(addr, psm))) {
@ -1328,15 +1325,15 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
if (setbdaddr(straddr, &_BT_L2_MEMB(addr, bdaddr)) < 0)
return 0;
*addr_ret = (struct sockaddr *) addr;
*len_ret = sizeof *addr;
return 1;
}
case BTPROTO_RFCOMM:
{
struct sockaddr_rc *addr = (struct sockaddr_rc *) _BT_SOCKADDR_MEMB(s, rc);
struct sockaddr_rc *addr;
char *straddr;
addr = (struct sockaddr_rc *)addr_ret;
_BT_RC_MEMB(addr, family) = AF_BLUETOOTH;
if (!PyArg_ParseTuple(args, "si", &straddr,
&_BT_RC_MEMB(addr, channel))) {
@ -1347,16 +1344,16 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
if (setbdaddr(straddr, &_BT_RC_MEMB(addr, bdaddr)) < 0)
return 0;
*addr_ret = (struct sockaddr *) addr;
*len_ret = sizeof *addr;
return 1;
}
#if !defined(__FreeBSD__)
case BTPROTO_SCO:
{
struct sockaddr_sco *addr = (struct sockaddr_sco *) _BT_SOCKADDR_MEMB(s, sco);
struct sockaddr_sco *addr;
char *straddr;
addr = (struct sockaddr_sco *)addr_ret;
_BT_SCO_MEMB(addr, family) = AF_BLUETOOTH;
straddr = PyString_AsString(args);
if (straddr == NULL) {
@ -1367,7 +1364,6 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
if (setbdaddr(straddr, &_BT_SCO_MEMB(addr, bdaddr)) < 0)
return 0;
*addr_ret = (struct sockaddr *) addr;
*len_ret = sizeof *addr;
return 1;
}
@ -1409,22 +1405,21 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
s->errorhandler();
return 0;
}
addr = &(s->sock_addr.ll);
addr->sll_family = AF_PACKET;
addr->sll_protocol = htons((short)protoNumber);
addr->sll_ifindex = ifr.ifr_ifindex;
addr->sll_pkttype = pkttype;
addr->sll_hatype = hatype;
if (halen > 8) {
PyErr_SetString(PyExc_ValueError,
"Hardware address must be 8 bytes or less");
return 0;
}
addr = (struct sockaddr_ll*)addr_ret;
addr->sll_family = AF_PACKET;
addr->sll_protocol = htons((short)protoNumber);
addr->sll_ifindex = ifr.ifr_ifindex;
addr->sll_pkttype = pkttype;
addr->sll_hatype = hatype;
if (halen != 0) {
memcpy(&addr->sll_addr, haddr, halen);
}
addr->sll_halen = halen;
*addr_ret = (struct sockaddr *) addr;
*len_ret = sizeof *addr;
return 1;
}
@ -1551,8 +1546,7 @@ sock_accept(PySocketSockObject *s)
Py_BEGIN_ALLOW_THREADS
timeout = internal_select(s, 0);
if (!timeout)
newfd = accept(s->sock_fd, (struct sockaddr *) &addrbuf,
&addrlen);
newfd = accept(s->sock_fd, SAS2SA(&addrbuf), &addrlen);
Py_END_ALLOW_THREADS
if (timeout == 1) {
@ -1578,7 +1572,7 @@ sock_accept(PySocketSockObject *s)
SOCKETCLOSE(newfd);
goto finally;
}
addr = makesockaddr(s->sock_fd, (struct sockaddr *) &addrbuf,
addr = makesockaddr(s->sock_fd, SAS2SA(&addrbuf),
addrlen, s->sock_proto);
if (addr == NULL)
goto finally;
@ -1819,14 +1813,14 @@ string of that length; otherwise it is an integer.");
static PyObject *
sock_bind(PySocketSockObject *s, PyObject *addro)
{
struct sockaddr *addr;
sock_addr_t addrbuf;
int addrlen;
int res;
if (!getsockaddrarg(s, addro, &addr, &addrlen))
if (!getsockaddrarg(s, addro, SAS2SA(&addrbuf), &addrlen))
return NULL;
Py_BEGIN_ALLOW_THREADS
res = bind(s->sock_fd, addr, addrlen);
res = bind(s->sock_fd, SAS2SA(&addrbuf), addrlen);
Py_END_ALLOW_THREADS
if (res < 0)
return s->errorhandler();
@ -1952,16 +1946,16 @@ internal_connect(PySocketSockObject *s, struct sockaddr *addr, int addrlen,
static PyObject *
sock_connect(PySocketSockObject *s, PyObject *addro)
{
struct sockaddr *addr;
sock_addr_t addrbuf;
int addrlen;
int res;
int timeout;
if (!getsockaddrarg(s, addro, &addr, &addrlen))
if (!getsockaddrarg(s, addro, SAS2SA(&addrbuf), &addrlen))
return NULL;
Py_BEGIN_ALLOW_THREADS
res = internal_connect(s, addr, addrlen, &timeout);
res = internal_connect(s, SAS2SA(&addrbuf), addrlen, &timeout);
Py_END_ALLOW_THREADS
if (timeout == 1) {
@ -1986,16 +1980,16 @@ is a pair (host, port).");
static PyObject *
sock_connect_ex(PySocketSockObject *s, PyObject *addro)
{
struct sockaddr *addr;
sock_addr_t addrbuf;
int addrlen;
int res;
int timeout;
if (!getsockaddrarg(s, addro, &addr, &addrlen))
if (!getsockaddrarg(s, addro, SAS2SA(&addrbuf), &addrlen))
return NULL;
Py_BEGIN_ALLOW_THREADS
res = internal_connect(s, addr, addrlen, &timeout);
res = internal_connect(s, SAS2SA(&addrbuf), addrlen, &timeout);
Py_END_ALLOW_THREADS
/* Signals are not errors (though they may raise exceptions). Adapted
@ -2075,11 +2069,11 @@ sock_getsockname(PySocketSockObject *s)
return NULL;
memset(&addrbuf, 0, addrlen);
Py_BEGIN_ALLOW_THREADS
res = getsockname(s->sock_fd, (struct sockaddr *) &addrbuf, &addrlen);
res = getsockname(s->sock_fd, SAS2SA(&addrbuf), &addrlen);
Py_END_ALLOW_THREADS
if (res < 0)
return s->errorhandler();
return makesockaddr(s->sock_fd, (struct sockaddr *) &addrbuf, addrlen,
return makesockaddr(s->sock_fd, SAS2SA(&addrbuf), addrlen,
s->sock_proto);
}
@ -2104,11 +2098,11 @@ sock_getpeername(PySocketSockObject *s)
return NULL;
memset(&addrbuf, 0, addrlen);
Py_BEGIN_ALLOW_THREADS
res = getpeername(s->sock_fd, (struct sockaddr *) &addrbuf, &addrlen);
res = getpeername(s->sock_fd, SAS2SA(&addrbuf), &addrlen);
Py_END_ALLOW_THREADS
if (res < 0)
return s->errorhandler();
return makesockaddr(s->sock_fd, (struct sockaddr *) &addrbuf, addrlen,
return makesockaddr(s->sock_fd, SAS2SA(&addrbuf), addrlen,
s->sock_proto);
}
@ -2443,14 +2437,14 @@ sock_recvfrom_guts(PySocketSockObject *s, char* cbuf, int len, int flags,
#ifndef MS_WINDOWS
#if defined(PYOS_OS2) && !defined(PYCC_GCC)
n = recvfrom(s->sock_fd, cbuf, len, flags,
(struct sockaddr *) &addrbuf, &addrlen);
SAS2SA(&addrbuf), &addrlen);
#else
n = recvfrom(s->sock_fd, cbuf, len, flags,
(void *) &addrbuf, &addrlen);
#endif
#else
n = recvfrom(s->sock_fd, cbuf, len, flags,
(struct sockaddr *) &addrbuf, &addrlen);
SAS2SA(&addrbuf), &addrlen);
#endif
}
Py_END_ALLOW_THREADS
@ -2464,7 +2458,7 @@ sock_recvfrom_guts(PySocketSockObject *s, char* cbuf, int len, int flags,
return -1;
}
if (!(*addr = makesockaddr(s->sock_fd, (struct sockaddr *) &addrbuf,
if (!(*addr = makesockaddr(s->sock_fd, SAS2SA(&addrbuf),
addrlen, s->sock_proto)))
return -1;
@ -2664,7 +2658,7 @@ sock_sendto(PySocketSockObject *s, PyObject *args)
{
PyObject *addro;
char *buf;
struct sockaddr *addr;
sock_addr_t addrbuf;
int addrlen, len, n = -1, flags, timeout;
flags = 0;
@ -2675,16 +2669,16 @@ sock_sendto(PySocketSockObject *s, PyObject *args)
return NULL;
}
if (!getsockaddrarg(s, addro, &addr, &addrlen))
return NULL;
if (!IS_SELECTABLE(s))
return select_error();
if (!getsockaddrarg(s, addro, SAS2SA(&addrbuf), &addrlen))
return NULL;
Py_BEGIN_ALLOW_THREADS
timeout = internal_select(s, 1);
if (!timeout)
n = sendto(s->sock_fd, buf, len, flags, addr, addrlen);
n = sendto(s->sock_fd, buf, len, flags, SAS2SA(&addrbuf), addrlen);
Py_END_ALLOW_THREADS
if (timeout == 1) {
@ -2973,10 +2967,9 @@ socket_gethostbyname(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "s:gethostbyname", &name))
return NULL;
if (setipaddr(name, (struct sockaddr *)&addrbuf, sizeof(addrbuf), AF_INET) < 0)
if (setipaddr(name, SAS2SA(&addrbuf), sizeof(addrbuf), AF_INET) < 0)
return NULL;
return makeipaddr((struct sockaddr *)&addrbuf,
sizeof(struct sockaddr_in));
return makeipaddr(SAS2SA(&addrbuf), sizeof(struct sockaddr_in));
}
PyDoc_STRVAR(gethostbyname_doc,

View File

@ -114,7 +114,6 @@ typedef struct {
int sock_family; /* Address family, e.g., AF_INET */
int sock_type; /* Socket type, e.g., SOCK_STREAM */
int sock_proto; /* Protocol type, usually 0 */
sock_addr_t sock_addr; /* Socket address */
PyObject *(*errorhandler)(void); /* Error handler; checks
errno, returns NULL and
sets a Python exception */