# define USE_GETHOSTBYNAME_LOCK
#endif
-#ifdef USE_GETHOSTBYNAME_LOCK
+/* On systems on which getaddrinfo() is believed to not be thread-safe,
+ protect access with a lock. */
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || \
+ defined(__NetBSD__)
+#define USE_GETADDRINFO_LOCK
+#endif
+
+#ifdef USE_GETADDRINFO_LOCK
+#define ACQUIRE_GETADDRINFO_LOCK PyThread_acquire_lock(netdb_lock, 1);
+#define RELEASE_GETADDRINFO_LOCK PyThread_release_lock(netdb_lock);
+#else
+#define ACQUIRE_GETADDRINFO_LOCK
+#define RELEASE_GETADDRINFO_LOCK
+#endif
+
+#if defined(USE_GETHOSTBYNAME_LOCK) || defined(USE_GETADDRINFO_LOCK)
# include "pythread.h"
#endif
/* Lock to allow python interpreter to continue, but only allow one
- thread to be in gethostbyname */
-#ifdef USE_GETHOSTBYNAME_LOCK
-PyThread_type_lock gethostbyname_lock;
+ thread to be in gethostbyname or getaddrinfo */
+#if defined(USE_GETHOSTBYNAME_LOCK) || defined(USE_GETADDRINFO_LOCK)
+PyThread_type_lock netdb_lock;
#endif
hints.ai_family = af;
hints.ai_socktype = SOCK_DGRAM; /*dummy*/
hints.ai_flags = AI_PASSIVE;
+ Py_BEGIN_ALLOW_THREADS
+ ACQUIRE_GETADDRINFO_LOCK
error = getaddrinfo(NULL, "0", &hints, &res);
+ Py_END_ALLOW_THREADS
+ /* We assume that those thread-unsafe getaddrinfo() versions
+ *are* safe regarding their return value, ie. that a
+ subsequent call to getaddrinfo() does not destroy the
+ outcome of the first call. */
+ RELEASE_GETADDRINFO_LOCK
if (error) {
set_gaierror(error);
return -1;
}
memset(&hints, 0, sizeof(hints));
hints.ai_family = af;
+ Py_BEGIN_ALLOW_THREADS
+ ACQUIRE_GETADDRINFO_LOCK
error = getaddrinfo(name, NULL, &hints, &res);
#if defined(__digital__) && defined(__unix__)
if (error == EAI_NONAME && af == AF_UNSPEC) {
error = getaddrinfo(name, NULL, &hints, &res);
}
#endif
+ Py_END_ALLOW_THREADS
+ RELEASE_GETADDRINFO_LOCK /* see comment in setipaddr() */
if (error) {
set_gaierror(error);
return -1;
#endif
#else /* not HAVE_GETHOSTBYNAME_R */
#ifdef USE_GETHOSTBYNAME_LOCK
- PyThread_acquire_lock(gethostbyname_lock, 1);
+ PyThread_acquire_lock(netdb_lock, 1);
#endif
h = gethostbyname(name);
#endif /* HAVE_GETHOSTBYNAME_R */
ret = gethost_common(h, (struct sockaddr *)&addr, sizeof(addr),
sa->sa_family);
#ifdef USE_GETHOSTBYNAME_LOCK
- PyThread_release_lock(gethostbyname_lock);
+ PyThread_release_lock(netdb_lock);
#endif
return ret;
}
#endif
#else /* not HAVE_GETHOSTBYNAME_R */
#ifdef USE_GETHOSTBYNAME_LOCK
- PyThread_acquire_lock(gethostbyname_lock, 1);
+ PyThread_acquire_lock(netdb_lock, 1);
#endif
h = gethostbyaddr(ap, al, af);
#endif /* HAVE_GETHOSTBYNAME_R */
Py_END_ALLOW_THREADS
ret = gethost_common(h, (struct sockaddr *)&addr, sizeof(addr), af);
#ifdef USE_GETHOSTBYNAME_LOCK
- PyThread_release_lock(gethostbyname_lock);
+ PyThread_release_lock(netdb_lock);
#endif
return ret;
}
hints.ai_socktype = socktype;
hints.ai_protocol = protocol;
hints.ai_flags = flags;
+ Py_BEGIN_ALLOW_THREADS
+ ACQUIRE_GETADDRINFO_LOCK
error = getaddrinfo(hptr, pptr, &hints, &res0);
+ Py_END_ALLOW_THREADS
+ RELEASE_GETADDRINFO_LOCK /* see comment in setipaddr() */
if (error) {
set_gaierror(error);
return NULL;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM; /* make numeric port happy */
+ Py_BEGIN_ALLOW_THREADS
+ ACQUIRE_GETADDRINFO_LOCK
error = getaddrinfo(hostp, pbuf, &hints, &res);
+ Py_END_ALLOW_THREADS
+ RELEASE_GETADDRINFO_LOCK /* see comment in setipaddr() */
if (error) {
set_gaierror(error);
goto fail;
#endif
/* Initialize gethostbyname lock */
-#ifdef USE_GETHOSTBYNAME_LOCK
- gethostbyname_lock = PyThread_allocate_lock();
+#if defined(USE_GETHOSTBYNAME_LOCK) || defined(USE_GETADDRINFO_LOCK)
+ netdb_lock = PyThread_allocate_lock();
#endif
}