Changed non-reentrant network functions to be reentrant and

thread safe.
This commit is contained in:
crs
2002-10-17 20:56:28 +00:00
parent 11e29ff7eb
commit 586a5a81ab
3 changed files with 475 additions and 71 deletions

View File

@@ -15,6 +15,7 @@
#include "CNetwork.h"
#include "XNetwork.h"
#include "CLog.h"
#include <algorithm>
//
// CNetwork
@@ -29,7 +30,6 @@ int (PASCAL FAR *CNetwork::getpeername)(CNetwork::Socket s, CNetwork::Address FA
int (PASCAL FAR *CNetwork::getsockname)(CNetwork::Socket s, CNetwork::Address FAR *name, CNetwork::AddressLength FAR * namelen);
int (PASCAL FAR *CNetwork::getsockopt)(CNetwork::Socket s, int level, int optname, void FAR * optval, CNetwork::AddressLength FAR *optlen);
unsigned long (PASCAL FAR *CNetwork::inet_addr)(const char FAR * cp);
char FAR * (PASCAL FAR *CNetwork::inet_ntoa)(struct in_addr in);
int (PASCAL FAR *CNetwork::listen)(CNetwork::Socket s, int backlog);
ssize_t (PASCAL FAR *CNetwork::read)(CNetwork::Socket s, void FAR * buf, size_t len);
ssize_t (PASCAL FAR *CNetwork::recv)(CNetwork::Socket s, void FAR * buf, size_t len, int flags);
@@ -41,23 +41,20 @@ int (PASCAL FAR *CNetwork::setsockopt)(CNetwork::Socket s, int level, int optnam
int (PASCAL FAR *CNetwork::shutdown)(CNetwork::Socket s, int how);
CNetwork::Socket (PASCAL FAR *CNetwork::socket)(int af, int type, int protocol);
ssize_t (PASCAL FAR *CNetwork::write)(CNetwork::Socket s, const void FAR * buf, size_t len);
struct hostent FAR * (PASCAL FAR *CNetwork::gethostbyaddr)(const char FAR * addr, int len, int type);
struct hostent FAR * (PASCAL FAR *CNetwork::gethostbyname)(const char FAR * name);
int (PASCAL FAR *CNetwork::gethostname)(char FAR * name, int namelen);
struct servent FAR * (PASCAL FAR *CNetwork::getservbyport)(int port, const char FAR * proto);
struct servent FAR * (PASCAL FAR *CNetwork::getservbyname)(const char FAR * name, const char FAR * proto);
struct protoent FAR * (PASCAL FAR *CNetwork::getprotobynumber)(int proto);
struct protoent FAR * (PASCAL FAR *CNetwork::getprotobyname)(const char FAR * name);
int (PASCAL FAR *CNetwork::getsockerror)(void);
int (PASCAL FAR *CNetwork::gethosterror)(void);
int (PASCAL FAR *CNetwork::setblocking)(CNetwork::Socket s, bool blocking);
int (PASCAL FAR *CNetwork::setnodelay)(CNetwork::Socket s, bool blocking);
#if WINDOWS_LIKE
int (PASCAL FAR *CNetwork::select)(int nfds, fd_set FAR *readfds, fd_set FAR *writefds, fd_set FAR *exceptfds, const struct timeval FAR *timeout);
int (PASCAL FAR *CNetwork::WSACleanup)(void);
int (PASCAL FAR *CNetwork::__WSAFDIsSet)(CNetwork::Socket, fd_set FAR *);
struct hostent FAR * (PASCAL FAR *CNetwork::gethostbyaddr_n)(const char FAR * addr, int len, int type);
struct hostent FAR * (PASCAL FAR *CNetwork::gethostbyname_n)(const char FAR * name);
struct servent FAR * (PASCAL FAR *CNetwork::getservbyport_n)(int port, const char FAR * proto);
struct servent FAR * (PASCAL FAR *CNetwork::getservbyname_n)(const char FAR * name, const char FAR * proto);
struct protoent FAR * (PASCAL FAR *CNetwork::getprotobynumber_n)(int proto);
struct protoent FAR * (PASCAL FAR *CNetwork::getprotobyname_n)(const char FAR * name);
const int CNetwork::Error = SOCKET_ERROR;
const CNetwork::Socket CNetwork::Null = INVALID_SOCKET;
@@ -202,7 +199,7 @@ CNetwork::init2(
setfunc(getsockname, getsockname, int (PASCAL FAR *)(Socket s, Address FAR *name, AddressLength FAR * namelen));
setfunc(getsockopt, getsockopt, int (PASCAL FAR *)(Socket s, int level, int optname, void FAR * optval, AddressLength FAR *optlen));
setfunc(inet_addr, inet_addr, unsigned long (PASCAL FAR *)(const char FAR * cp));
setfunc(inet_ntoa, inet_ntoa, char FAR * (PASCAL FAR *)(struct in_addr in));
setfunc(inet_ntoa_n, inet_ntoa, char FAR * (PASCAL FAR *)(struct in_addr in));
setfunc(listen, listen, int (PASCAL FAR *)(Socket s, int backlog));
setfunc(recv, recv, ssize_t (PASCAL FAR *)(Socket s, void FAR * buf, size_t len, int flags));
setfunc(recvfrom, recvfrom, ssize_t (PASCAL FAR *)(Socket s, void FAR * buf, size_t len, int flags, Address FAR *from, AddressLength FAR * fromlen));
@@ -211,23 +208,20 @@ CNetwork::init2(
setfunc(setsockopt, setsockopt, int (PASCAL FAR *)(Socket s, int level, int optname, const void FAR * optval, AddressLength optlen));
setfunc(shutdown, shutdown, int (PASCAL FAR *)(Socket s, int how));
setfunc(socket, socket, Socket (PASCAL FAR *)(int af, int type, int protocol));
setfunc(gethostbyaddr, gethostbyaddr, struct hostent FAR * (PASCAL FAR *)(const char FAR * addr, int len, int type));
setfunc(gethostbyname, gethostbyname, struct hostent FAR * (PASCAL FAR *)(const char FAR * name));
setfunc(gethostname, gethostname, int (PASCAL FAR *)(char FAR * name, int namelen));
setfunc(getservbyport, getservbyport, struct servent FAR * (PASCAL FAR *)(int port, const char FAR * proto));
setfunc(getservbyname, getservbyname, struct servent FAR * (PASCAL FAR *)(const char FAR * name, const char FAR * proto));
setfunc(getprotobynumber, getprotobynumber, struct protoent FAR * (PASCAL FAR *)(int proto));
setfunc(getprotobyname, getprotobyname, struct protoent FAR * (PASCAL FAR *)(const char FAR * name));
setfunc(gethostbyaddr_n, gethostbyaddr, struct hostent FAR * (PASCAL FAR *)(const char FAR * addr, int len, int type));
setfunc(gethostbyname_n, gethostbyname, struct hostent FAR * (PASCAL FAR *)(const char FAR * name));
setfunc(getservbyport_n, getservbyport, struct servent FAR * (PASCAL FAR *)(int port, const char FAR * proto));
setfunc(getservbyname_n, getservbyname, struct servent FAR * (PASCAL FAR *)(const char FAR * name, const char FAR * proto));
setfunc(getprotobynumber_n, getprotobynumber, struct protoent FAR * (PASCAL FAR *)(int proto));
setfunc(getprotobyname_n, getprotobyname, struct protoent FAR * (PASCAL FAR *)(const char FAR * name));
setfunc(getsockerror, WSAGetLastError, int (PASCAL FAR *)(void));
setfunc(gethosterror, WSAGetLastError, int (PASCAL FAR *)(void));
setfunc(WSACleanup, WSACleanup, int (PASCAL FAR *)(void));
setfunc(__WSAFDIsSet, __WSAFDIsSet, int (PASCAL FAR *)(CNetwork::Socket, fd_set FAR *));
setfunc(select, select, int (PASCAL FAR *)(int nfds, fd_set FAR *readfds, fd_set FAR *writefds, fd_set FAR *exceptfds, const struct timeval FAR *timeout));
poll = poll2;
read = read2;
write = write2;
setblocking = setblocking2;
setnodelay = setnodelay2;
poll = poll2;
read = read2;
write = write2;
s_networkModule = module;
}
@@ -244,15 +238,130 @@ CNetwork::write2(Socket s, const void FAR* buf, size_t len)
return send(s, buf, len, 0);
}
CString PASCAL FAR
CNetwork::inet_ntoa(struct in_addr in)
{
// winsock returns strings per-thread
return CString(inet_ntoa_n(in));
}
int PASCAL FAR
CNetwork::setblocking2(CNetwork::Socket s, bool blocking)
CNetwork::gethostbyaddr(CHostInfo* hostinfo,
const char FAR * addr, int len, int type)
{
assert(hostinfo != NULL);
// winsock returns structures per-thread
struct hostent FAR* info = gethostbyaddr_n(addr, len, type);
if (info == NULL) {
return WSAGetLastError();
}
else {
CHostInfo tmp(info);
hostinfo->swap(tmp);
return 0;
}
}
int PASCAL FAR
CNetwork::gethostbyname(CHostInfo* hostinfo,
const char FAR * name)
{
assert(hostinfo != NULL);
// winsock returns structures per-thread
struct hostent FAR* info = gethostbyname_n(name);
if (info == NULL) {
return WSAGetLastError();
}
else {
CHostInfo tmp(info);
hostinfo->swap(tmp);
return 0;
}
}
int PASCAL FAR
CNetwork::getservbyport(CServiceInfo* servinfo,
int port, const char FAR * proto)
{
assert(servinfo != NULL);
// winsock returns structures per-thread
struct servent FAR* info = getservbyport_n(port, proto);
if (info == NULL) {
return WSAGetLastError();
}
else {
CServiceInfo tmp(info);
servinfo->swap(tmp);
return 0;
}
}
int PASCAL FAR
CNetwork::getservbyname(CServiceInfo* servinfo,
const char FAR * name, const char FAR * proto)
{
assert(servinfo != NULL);
// winsock returns structures per-thread
struct servent FAR* info = getservbyname_n(name, proto);
if (info == NULL) {
return WSAGetLastError();
}
else {
CServiceInfo tmp(info);
servinfo->swap(tmp);
return 0;
}
}
int PASCAL FAR
CNetwork::getprotobynumber(CProtocolInfo* protoinfo,
int proto)
{
assert(protoinfo != NULL);
// winsock returns structures per-thread
struct protoinfo FAR* info = getprotobynumber_n(proto);
if (info == NULL) {
return WSAGetLastError();
}
else {
CProtocolInfo tmp(info);
protoinfo->swap(tmp);
return 0;
}
}
int PASCAL FAR
CNetwork::getprotobyname(CProtocolInfo* protoinfo,
const char FAR * name)
{
assert(protoinfo != NULL);
// winsock returns structures per-thread
struct protoinfo FAR* info = getprotobyname_n(name);
if (info == NULL) {
return WSAGetLastError();
}
else {
CProtocolInfo tmp(info);
protoinfo->swap(tmp);
return 0;
}
}
int PASCAL FAR
CNetwork::setblocking(CNetwork::Socket s, bool blocking)
{
int flag = blocking ? 0 : 1;
return ioctl(s, FIONBIO, &flag);
}
int PASCAL FAR
CNetwork::setnodelay2(CNetwork::Socket s, bool nodelay)
CNetwork::setnodelay(CNetwork::Socket s, bool nodelay)
{
BOOL flag = nodelay ? 1 : 0;
setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag));
@@ -262,6 +371,9 @@ CNetwork::setnodelay2(CNetwork::Socket s, bool nodelay)
#if UNIX_LIKE
#include "CMutex.h"
#include "CLock.h"
#if HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
@@ -284,6 +396,8 @@ CNetwork::setnodelay2(CNetwork::Socket s, bool nodelay)
const int CNetwork::Error = -1;
const CNetwork::Socket CNetwork::Null = -1;
static CMutex* s_networkMutex = NULL;
#define setfunc(var, name, type) var = (type)::name
UInt32
@@ -313,6 +427,15 @@ CNetwork::swapntohs(UInt16 v)
void
CNetwork::init()
{
assert(s_networkMutex == NULL);
try {
s_networkMutex = new CMutex;
}
catch (...) {
throw XNetworkFailed();
}
setfunc(accept, accept, Socket (PASCAL FAR *)(Socket s, Address FAR *addr, AddressLength FAR *addrlen));
setfunc(bind, bind, int (PASCAL FAR *)(Socket s, const Address FAR *addr, AddressLength namelen));
setfunc(close, close, int (PASCAL FAR *)(Socket s));
@@ -322,7 +445,6 @@ CNetwork::init()
setfunc(getsockname, getsockname, int (PASCAL FAR *)(Socket s, Address FAR *name, AddressLength FAR * namelen));
setfunc(getsockopt, getsockopt, int (PASCAL FAR *)(Socket s, int level, int optname, void FAR * optval, AddressLength FAR *optlen));
setfunc(inet_addr, inet_addr, unsigned long (PASCAL FAR *)(const char FAR * cp));
setfunc(inet_ntoa, inet_ntoa, char FAR * (PASCAL FAR *)(struct in_addr in));
setfunc(listen, listen, int (PASCAL FAR *)(Socket s, int backlog));
#if HAVE_POLL
setfunc(poll, poll, int (PASCAL FAR *)(CNetwork::PollEntry fds[], int nfds, int timeout));
@@ -338,23 +460,15 @@ CNetwork::init()
setfunc(shutdown, shutdown, int (PASCAL FAR *)(Socket s, int how));
setfunc(socket, socket, Socket (PASCAL FAR *)(int af, int type, int protocol));
setfunc(write, write, ssize_t (PASCAL FAR *)(CNetwork::Socket s, const void FAR * buf, size_t len));
setfunc(gethostbyaddr, gethostbyaddr, struct hostent FAR * (PASCAL FAR *)(const char FAR * addr, int len, int type));
setfunc(gethostbyname, gethostbyname, struct hostent FAR * (PASCAL FAR *)(const char FAR * name));
setfunc(getservbyport, getservbyport, struct servent FAR * (PASCAL FAR *)(int port, const char FAR * proto));
setfunc(getservbyname, getservbyname, struct servent FAR * (PASCAL FAR *)(const char FAR * name, const char FAR * proto));
setfunc(getprotobynumber, getprotobynumber, struct protoent FAR * (PASCAL FAR *)(int proto));
setfunc(getprotobyname, getprotobyname, struct protoent FAR * (PASCAL FAR *)(const char FAR * name));
gethostname = gethostname2;
getsockerror = getsockerror2;
gethosterror = gethosterror2;
setblocking = setblocking2;
setnodelay = setnodelay2;
}
void
CNetwork::cleanup()
{
// do nothing
delete s_networkMutex;
s_networkMutex = NULL;
}
int PASCAL FAR
@@ -369,14 +483,130 @@ CNetwork::getsockerror2(void)
return errno;
}
int PASCAL FAR
CNetwork::gethosterror2(void)
CString PASCAL FAR
CNetwork::inet_ntoa(struct in_addr in)
{
return h_errno;
// single threaded access to inet_ntoa functions
CLock lock(s_networkMutex);
return CString(::inet_ntoa(in));
}
int PASCAL FAR
CNetwork::setblocking2(CNetwork::Socket s, bool blocking)
CNetwork::gethostbyaddr(CHostInfo* hostinfo,
const char FAR * addr, int len, int type)
{
assert(hostinfo != NULL);
// single threaded access to netdb functions
CLock lock(s_networkMutex);
struct hostent FAR* info = ::gethostbyaddr(addr, len, type);
if (info == NULL) {
return h_errno;
}
else {
CHostInfo tmp(info);
hostinfo->swap(tmp);
return 0;
}
}
int PASCAL FAR
CNetwork::gethostbyname(CHostInfo* hostinfo,
const char FAR * name)
{
assert(hostinfo != NULL);
// single threaded access to netdb functions
CLock lock(s_networkMutex);
struct hostent FAR* info = ::gethostbyname(name);
if (info == NULL) {
return h_errno;
}
else {
CHostInfo tmp(info);
hostinfo->swap(tmp);
return 0;
}
}
int PASCAL FAR
CNetwork::getservbyport(CServiceInfo* servinfo,
int port, const char FAR * proto)
{
assert(servinfo != NULL);
// single threaded access to netdb functions
CLock lock(s_networkMutex);
struct servent FAR* info = ::getservbyport(port, proto);
if (info == NULL) {
return -1;
}
else {
CServiceInfo tmp(info);
servinfo->swap(tmp);
return 0;
}
}
int PASCAL FAR
CNetwork::getservbyname(CServiceInfo* servinfo,
const char FAR * name, const char FAR * proto)
{
assert(servinfo != NULL);
// single threaded access to netdb functions
CLock lock(s_networkMutex);
struct servent FAR* info = ::getservbyname(name, proto);
if (info == NULL) {
return -1;
}
else {
CServiceInfo tmp(info);
servinfo->swap(tmp);
return 0;
}
}
int PASCAL FAR
CNetwork::getprotobynumber(CProtocolInfo* protoinfo,
int proto)
{
assert(protoinfo != NULL);
// single threaded access to netdb functions
CLock lock(s_networkMutex);
struct protoent FAR* info = ::getprotobynumber(proto);
if (info == NULL) {
return -1;
}
else {
CProtocolInfo tmp(info);
protoinfo->swap(tmp);
return 0;
}
}
int PASCAL FAR
CNetwork::getprotobyname(CProtocolInfo* protoinfo,
const char FAR * name)
{
assert(protoinfo != NULL);
// single threaded access to netdb functions
CLock lock(s_networkMutex);
struct protoent FAR* info = ::getprotobyname(name);
if (info == NULL) {
return -1;
}
else {
CProtocolInfo tmp(info);
protoinfo->swap(tmp);
return 0;
}
}
int PASCAL FAR
CNetwork::setblocking(CNetwork::Socket s, bool blocking)
{
int mode = fcntl(s, F_GETFL, 0);
if (mode == -1) {
@@ -395,7 +625,7 @@ CNetwork::setblocking2(CNetwork::Socket s, bool blocking)
}
int PASCAL FAR
CNetwork::setnodelay2(CNetwork::Socket s, bool nodelay)
CNetwork::setnodelay(CNetwork::Socket s, bool nodelay)
{
int flag = nodelay ? 1 : 0;
setsockopt(s, SOL_TCP, TCP_NODELAY, &flag, sizeof(flag));
@@ -502,3 +732,98 @@ CNetwork::poll2(PollEntry fd[], int nfds, int timeout)
}
#endif
//
// CNetwork::CHostInfo
//
CNetwork::CHostInfo::CHostInfo(const struct hostent* hent)
{
assert(hent != NULL);
m_name = hent->h_name;
m_addressType = hent->h_addrtype;
m_addressLength = hent->h_length;
for (char** scan = hent->h_aliases; *scan != NULL; ++scan) {
m_aliases.push_back(*scan);
}
// concatenate addresses together
UInt32 n = 0;
for (char** scan = hent->h_addr_list; *scan != NULL; ++scan) {
++n;
}
m_addressData.reserve(n);
for (char** scan = hent->h_addr_list; *scan != NULL; ++scan) {
m_addressData.append(*scan, m_addressLength);
}
// set pointers into concatenated data
const char* data = m_addressData.data();
for (char** scan = hent->h_addr_list; *scan != NULL; ++scan) {
m_addresses.push_back(data);
data += m_addressLength;
}
}
void
CNetwork::CHostInfo::swap(CHostInfo& v)
{
std::swap(m_name, v.m_name);
std::swap(m_aliases, v.m_aliases);
std::swap(m_addressType, v.m_addressType);
std::swap(m_addressLength, v.m_addressLength);
std::swap(m_addresses, v.m_addresses);
std::swap(m_addressData, v.m_addressData);
}
//
// CNetwork::CServiceInfo
//
CNetwork::CServiceInfo::CServiceInfo(const struct servent* sent)
{
assert(sent != NULL);
m_name = sent->s_name;
m_port = sent->s_port;
m_protocol = sent->s_proto;
for (char** scan = sent->s_aliases; *scan != NULL; ++scan) {
m_aliases.push_back(*scan);
}
}
void
CNetwork::CServiceInfo::swap(CServiceInfo& v)
{
std::swap(m_name, v.m_name);
std::swap(m_aliases, v.m_aliases);
std::swap(m_port, v.m_port);
std::swap(m_protocol, v.m_protocol);
}
//
// CNetwork::CProtocolInfo
//
CNetwork::CProtocolInfo::CProtocolInfo(const struct protoent* pent)
{
assert(pent != NULL);
m_name = pent->p_name;
m_protocol = pent->p_proto;
for (char** scan = pent->p_aliases; *scan != NULL; ++scan) {
m_aliases.push_back(*scan);
}
}
void
CNetwork::CProtocolInfo::swap(CProtocolInfo& v)
{
std::swap(m_name, v.m_name);
std::swap(m_aliases, v.m_aliases);
std::swap(m_protocol, v.m_protocol);
}