Make calls to gethostbyname, gethostbyaddr, getservbyname,
getservbyport, getprotobyname and getprotobynumber thread-safe.
diff --git a/dlls/winsock/socket.c b/dlls/winsock/socket.c
index d4585f8..721e94f 100644
--- a/dlls/winsock/socket.c
+++ b/dlls/winsock/socket.c
@@ -92,6 +92,9 @@
DEFAULT_DEBUG_CHANNEL(winsock);
+/* critical section to protect some non-rentrant net function */
+extern CRITICAL_SECTION csWSgetXXXbyYYY;
+
#define DEBUG_SOCKADDR 0
#define dump_sockaddr(a) \
DPRINTF("sockaddr_in: family %d, address %s, port %d\n", \
@@ -166,7 +169,7 @@
int WSAIOCTL_GetInterfaceName(int intNumber, char *intName);
UINT16 wsaErrno(void);
-UINT16 wsaHerrno(void);
+UINT16 wsaHerrno(int errnr);
static HANDLE _WSHeap = 0;
@@ -2297,20 +2300,46 @@
*/
static WIN_hostent* __ws_gethostbyaddr(const char *addr, int len, int type, int dup_flag)
{
+ WIN_hostent *retval = NULL;
LPWSINFO pwsi = WINSOCK_GetIData();
if( pwsi )
{
struct hostent* host;
- if( (host = gethostbyaddr(addr, len, type)) != NULL )
+#if HAVE_LINUX_GETHOSTBYNAME_R_6
+ char *extrabuf;
+ int ebufsize=1024;
+ struct hostent hostentry;
+ int locerr=ENOBUFS;
+ host = NULL;
+ extrabuf=HeapAlloc(GetProcessHeap(),0,ebufsize) ;
+ while(extrabuf) {
+ int res = gethostbyaddr_r(addr, len, type,
+ &hostentry, extrabuf, ebufsize, &host, &locerr);
+ if( res != ERANGE) break;
+ ebufsize *=2;
+ extrabuf=HeapReAlloc(GetProcessHeap(),0,extrabuf,ebufsize) ;
+ }
+ if (!host) SetLastError((locerr < 0) ? wsaErrno() : wsaHerrno(locerr));
+#else
+ EnterCriticalSection( &csWSgetXXXbyYYY );
+ host = gethostbyaddr(addr, len, type);
+ if (!host) SetLastError((h_errno < 0) ? wsaErrno() : wsaHerrno(h_errno));
+#endif
+ if( host != NULL )
+ {
if( WS_dup_he(pwsi, host, dup_flag) )
- return (WIN_hostent*)(pwsi->he);
+ retval = (WIN_hostent*)(pwsi->he);
else
SetLastError(WSAENOBUFS);
- else
- SetLastError((h_errno < 0) ? wsaErrno() : wsaHerrno());
+ }
+#ifdef HAVE_LINUX_GETHOSTBYNAME_R_6
+ HeapFree(GetProcessHeap(),0,extrabuf);
+#else
+ LeaveCriticalSection( &csWSgetXXXbyYYY );
+#endif
}
- return NULL;
+ return retval;
}
SEGPTR WINAPI WINSOCK_gethostbyaddr16(const char *addr, INT16 len, INT16 type)
@@ -2335,18 +2364,44 @@
*/
static WIN_hostent * __ws_gethostbyname(const char *name, int dup_flag)
{
+ WIN_hostent *retval = NULL;
LPWSINFO pwsi = WINSOCK_GetIData();
if( pwsi )
{
struct hostent* host;
- if( (host = gethostbyname(name)) != NULL )
+#ifdef HAVE_LINUX_GETHOSTBYNAME_R_6
+ char *extrabuf;
+ int ebufsize=1024;
+ struct hostent hostentry;
+ int locerr = ENOBUFS;
+ host = NULL;
+ extrabuf=HeapAlloc(GetProcessHeap(),0,ebufsize) ;
+ while(extrabuf) {
+ int res = gethostbyname_r(name, &hostentry, extrabuf, ebufsize, &host, &locerr);
+ if( res != ERANGE) break;
+ ebufsize *=2;
+ extrabuf=HeapReAlloc(GetProcessHeap(),0,extrabuf,ebufsize) ;
+ }
+ if (!host) SetLastError((locerr < 0) ? wsaErrno() : wsaHerrno(locerr));
+#else
+ EnterCriticalSection( &csWSgetXXXbyYYY );
+ host = gethostbyname(name);
+ if (!host) SetLastError((h_errno < 0) ? wsaErrno() : wsaHerrno(h_errno));
+#endif
+ if( host != NULL )
+ {
if( WS_dup_he(pwsi, host, dup_flag) )
- return (WIN_hostent*)(pwsi->he);
+ retval = (WIN_hostent*)(pwsi->he);
else SetLastError(WSAENOBUFS);
- else SetLastError((h_errno < 0) ? wsaErrno() : wsaHerrno());
+ }
+#ifdef HAVE_LINUX_GETHOSTBYNAME_R_6
+ HeapFree(GetProcessHeap(),0,extrabuf);
+#else
+ LeaveCriticalSection( &csWSgetXXXbyYYY );
+#endif
}
- return NULL;
+ return retval;
}
SEGPTR WINAPI WINSOCK_gethostbyname16(const char *name)
@@ -2369,22 +2424,27 @@
*/
static WIN_protoent* __ws_getprotobyname(const char *name, int dup_flag)
{
+ WIN_protoent* retval = NULL;
LPWSINFO pwsi = WINSOCK_GetIData();
if( pwsi )
{
struct protoent* proto;
+ EnterCriticalSection( &csWSgetXXXbyYYY );
if( (proto = getprotobyname(name)) != NULL )
+ {
if( WS_dup_pe(pwsi, proto, dup_flag) )
- return (WIN_protoent*)(pwsi->pe);
+ retval = (WIN_protoent*)(pwsi->pe);
else SetLastError(WSAENOBUFS);
+ }
else {
MESSAGE("protocol %s not found; You might want to add "
"this to /etc/protocols\n", debugstr_a(name) );
SetLastError(WSANO_DATA);
}
+ LeaveCriticalSection( &csWSgetXXXbyYYY );
} else SetLastError(WSANOTINITIALISED);
- return NULL;
+ return retval;
}
SEGPTR WINAPI WINSOCK_getprotobyname16(const char *name)
@@ -2407,22 +2467,27 @@
*/
static WIN_protoent* __ws_getprotobynumber(int number, int dup_flag)
{
+ WIN_protoent* retval = NULL;
LPWSINFO pwsi = WINSOCK_GetIData();
if( pwsi )
{
struct protoent* proto;
+ EnterCriticalSection( &csWSgetXXXbyYYY );
if( (proto = getprotobynumber(number)) != NULL )
+ {
if( WS_dup_pe(pwsi, proto, dup_flag) )
- return (WIN_protoent*)(pwsi->pe);
+ retval = (WIN_protoent*)(pwsi->pe);
else SetLastError(WSAENOBUFS);
+ }
else {
MESSAGE("protocol number %d not found; You might want to add "
"this to /etc/protocols\n", number );
SetLastError(WSANO_DATA);
}
+ LeaveCriticalSection( &csWSgetXXXbyYYY );
} else SetLastError(WSANOTINITIALISED);
- return NULL;
+ return retval;
}
SEGPTR WINAPI WINSOCK_getprotobynumber16(INT16 number)
@@ -2445,6 +2510,7 @@
*/
static WIN_servent* __ws_getservbyname(const char *name, const char *proto, int dup_flag)
{
+ WIN_servent* retval = NULL;
LPWSINFO pwsi = WINSOCK_GetIData();
if( pwsi )
@@ -2453,22 +2519,26 @@
int i = wsi_strtolo( pwsi, name, proto );
if( i ) {
+ EnterCriticalSection( &csWSgetXXXbyYYY );
serv = getservbyname(pwsi->buffer,
proto ? (pwsi->buffer + i) : NULL);
if( serv != NULL )
+ {
if( WS_dup_se(pwsi, serv, dup_flag) )
- return (WIN_servent*)(pwsi->se);
+ retval = (WIN_servent*)(pwsi->se);
else SetLastError(WSAENOBUFS);
+ }
else {
MESSAGE("service %s protocol %s not found; You might want to add "
"this to /etc/services\n", debugstr_a(pwsi->buffer),
proto ? debugstr_a(pwsi->buffer+i):"*");
SetLastError(WSANO_DATA);
}
+ LeaveCriticalSection( &csWSgetXXXbyYYY );
}
else SetLastError(WSAENOBUFS);
} else SetLastError(WSANOTINITIALISED);
- return NULL;
+ return retval;
}
SEGPTR WINAPI WINSOCK_getservbyname16(const char *name, const char *proto)
@@ -2493,15 +2563,17 @@
*/
static WIN_servent* __ws_getservbyport(int port, const char* proto, int dup_flag)
{
+ WIN_servent* retval = NULL;
LPWSINFO pwsi = WINSOCK_GetIData();
if( pwsi )
{
struct servent* serv;
if (!proto || wsi_strtolo( pwsi, proto, NULL )) {
+ EnterCriticalSection( &csWSgetXXXbyYYY );
if( (serv = getservbyport(port, (proto) ? pwsi->buffer : NULL)) != NULL ) {
if( WS_dup_se(pwsi, serv, dup_flag) )
- return (WIN_servent*)(pwsi->se);
+ retval = (WIN_servent*)(pwsi->se);
else SetLastError(WSAENOBUFS);
}
else {
@@ -2510,10 +2582,11 @@
proto ? debugstr_a(pwsi->buffer) : "*");
SetLastError(WSANO_DATA);
}
+ LeaveCriticalSection( &csWSgetXXXbyYYY );
}
else SetLastError(WSAENOBUFS);
} else SetLastError(WSANOTINITIALISED);
- return NULL;
+ return retval;
}
SEGPTR WINAPI WINSOCK_getservbyport16(INT16 port, const char *proto)
@@ -3231,9 +3304,8 @@
}
}
-UINT16 wsaHerrno(void)
+UINT16 wsaHerrno(int loc_errno)
{
- int loc_errno = h_errno;
WARN("h_errno %d.\n", loc_errno);
@@ -3243,6 +3315,7 @@
case TRY_AGAIN: return WSATRY_AGAIN;
case NO_RECOVERY: return WSANO_RECOVERY;
case NO_DATA: return WSANO_DATA;
+ case ENOBUFS: return WSAENOBUFS;
case 0: return 0;
default: