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 "CNetwork.h"
#include "XNetwork.h" #include "XNetwork.h"
#include "CLog.h" #include "CLog.h"
#include <algorithm>
// //
// CNetwork // 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::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); 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); 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); 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::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); 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); int (PASCAL FAR *CNetwork::shutdown)(CNetwork::Socket s, int how);
CNetwork::Socket (PASCAL FAR *CNetwork::socket)(int af, int type, int protocol); 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); 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); 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::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 #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::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::WSACleanup)(void);
int (PASCAL FAR *CNetwork::__WSAFDIsSet)(CNetwork::Socket, fd_set FAR *); 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 int CNetwork::Error = SOCKET_ERROR;
const CNetwork::Socket CNetwork::Null = INVALID_SOCKET; 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(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(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_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(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(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)); 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(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(shutdown, shutdown, int (PASCAL FAR *)(Socket s, int how));
setfunc(socket, socket, Socket (PASCAL FAR *)(int af, int type, int protocol)); 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(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(gethostbyaddr_n, gethostbyaddr, struct hostent FAR * (PASCAL FAR *)(const char FAR * addr, int len, int type));
setfunc(getservbyname, getservbyname, struct servent FAR * (PASCAL FAR *)(const char FAR * name, const char FAR * proto)); setfunc(gethostbyname_n, gethostbyname, struct hostent FAR * (PASCAL FAR *)(const char FAR * name));
setfunc(getprotobynumber, getprotobynumber, struct protoent FAR * (PASCAL FAR *)(int proto)); setfunc(getservbyport_n, getservbyport, struct servent FAR * (PASCAL FAR *)(int port, const char FAR * proto));
setfunc(getprotobyname, getprotobyname, struct protoent FAR * (PASCAL FAR *)(const char FAR * name)); 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(getsockerror, WSAGetLastError, int (PASCAL FAR *)(void));
setfunc(gethosterror, WSAGetLastError, int (PASCAL FAR *)(void));
setfunc(WSACleanup, WSACleanup, int (PASCAL FAR *)(void)); setfunc(WSACleanup, WSACleanup, int (PASCAL FAR *)(void));
setfunc(__WSAFDIsSet, __WSAFDIsSet, int (PASCAL FAR *)(CNetwork::Socket, fd_set FAR *)); 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)); 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; poll = poll2;
read = read2; read = read2;
write = write2; write = write2;
setblocking = setblocking2;
setnodelay = setnodelay2;
s_networkModule = module; s_networkModule = module;
} }
@ -244,15 +238,130 @@ CNetwork::write2(Socket s, const void FAR* buf, size_t len)
return send(s, buf, len, 0); 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 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; int flag = blocking ? 0 : 1;
return ioctl(s, FIONBIO, &flag); return ioctl(s, FIONBIO, &flag);
} }
int PASCAL FAR int PASCAL FAR
CNetwork::setnodelay2(CNetwork::Socket s, bool nodelay) CNetwork::setnodelay(CNetwork::Socket s, bool nodelay)
{ {
BOOL flag = nodelay ? 1 : 0; BOOL flag = nodelay ? 1 : 0;
setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag)); setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag));
@ -262,6 +371,9 @@ CNetwork::setnodelay2(CNetwork::Socket s, bool nodelay)
#if UNIX_LIKE #if UNIX_LIKE
#include "CMutex.h"
#include "CLock.h"
#if HAVE_SYS_TYPES_H #if HAVE_SYS_TYPES_H
# include <sys/types.h> # include <sys/types.h>
#endif #endif
@ -284,6 +396,8 @@ CNetwork::setnodelay2(CNetwork::Socket s, bool nodelay)
const int CNetwork::Error = -1; const int CNetwork::Error = -1;
const CNetwork::Socket CNetwork::Null = -1; const CNetwork::Socket CNetwork::Null = -1;
static CMutex* s_networkMutex = NULL;
#define setfunc(var, name, type) var = (type)::name #define setfunc(var, name, type) var = (type)::name
UInt32 UInt32
@ -313,6 +427,15 @@ CNetwork::swapntohs(UInt16 v)
void void
CNetwork::init() 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(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(bind, bind, int (PASCAL FAR *)(Socket s, const Address FAR *addr, AddressLength namelen));
setfunc(close, close, int (PASCAL FAR *)(Socket s)); 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(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(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_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)); setfunc(listen, listen, int (PASCAL FAR *)(Socket s, int backlog));
#if HAVE_POLL #if HAVE_POLL
setfunc(poll, poll, int (PASCAL FAR *)(CNetwork::PollEntry fds[], int nfds, int timeout)); 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(shutdown, shutdown, int (PASCAL FAR *)(Socket s, int how));
setfunc(socket, socket, Socket (PASCAL FAR *)(int af, int type, int protocol)); 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(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; gethostname = gethostname2;
getsockerror = getsockerror2; getsockerror = getsockerror2;
gethosterror = gethosterror2;
setblocking = setblocking2;
setnodelay = setnodelay2;
} }
void void
CNetwork::cleanup() CNetwork::cleanup()
{ {
// do nothing delete s_networkMutex;
s_networkMutex = NULL;
} }
int PASCAL FAR int PASCAL FAR
@ -369,14 +483,130 @@ CNetwork::getsockerror2(void)
return errno; return errno;
} }
int PASCAL FAR CString PASCAL FAR
CNetwork::gethosterror2(void) 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 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); int mode = fcntl(s, F_GETFL, 0);
if (mode == -1) { if (mode == -1) {
@ -395,7 +625,7 @@ CNetwork::setblocking2(CNetwork::Socket s, bool blocking)
} }
int PASCAL FAR int PASCAL FAR
CNetwork::setnodelay2(CNetwork::Socket s, bool nodelay) CNetwork::setnodelay(CNetwork::Socket s, bool nodelay)
{ {
int flag = nodelay ? 1 : 0; int flag = nodelay ? 1 : 0;
setsockopt(s, SOL_TCP, TCP_NODELAY, &flag, sizeof(flag)); setsockopt(s, SOL_TCP, TCP_NODELAY, &flag, sizeof(flag));
@ -502,3 +732,98 @@ CNetwork::poll2(PollEntry fd[], int nfds, int timeout)
} }
#endif #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);
}

View File

@ -16,6 +16,8 @@
#define CNETWORK_H #define CNETWORK_H
#include "BasicTypes.h" #include "BasicTypes.h"
#include "CString.h"
#include "stdvector.h"
#if HAVE_SYS_TYPES_H #if HAVE_SYS_TYPES_H
# include <sys/types.h> # include <sys/types.h>
@ -82,6 +84,61 @@ public:
}; };
#endif #endif
//! Host name information
class CHostInfo {
public:
CHostInfo() { }
CHostInfo(const struct hostent*);
void swap(CHostInfo&);
public:
typedef std::vector<CString> AliasList;
typedef std::vector<const char*> AddressList;
CString m_name;
AliasList m_aliases;
int m_addressType;
int m_addressLength;
AddressList m_addresses;
private:
std::string m_addressData;
};
//! Network service information
class CServiceInfo {
public:
CServiceInfo() { }
CServiceInfo(const struct servent*);
void swap(CServiceInfo&);
public:
typedef std::vector<CString> AliasList;
CString m_name;
AliasList m_aliases;
int m_port;
CString m_protocol;
};
//! Network protocol information
class CProtocolInfo {
public:
CProtocolInfo() { }
CProtocolInfo(const struct protoent*);
void swap(CProtocolInfo&);
public:
typedef std::vector<CString> AliasList;
CString m_name;
AliasList m_aliases;
int m_protocol;
};
//! @name manipulators //! @name manipulators
//@{ //@{
@ -142,7 +199,7 @@ public:
kNO_RECOVERY = NO_RECOVERY, kNO_RECOVERY = NO_RECOVERY,
kTRY_AGAIN = TRY_AGAIN, kTRY_AGAIN = TRY_AGAIN,
#endif #endif
kHNone = 0 kHOST_OK = 0
}; };
//@} //@}
@ -158,7 +215,7 @@ public:
static int (PASCAL FAR *getsockname)(Socket s, Address FAR *name, AddressLength FAR * namelen); static int (PASCAL FAR *getsockname)(Socket s, Address FAR *name, AddressLength FAR * namelen);
static int (PASCAL FAR *getsockopt)(Socket s, int level, int optname, void FAR * optval, AddressLength FAR *optlen); static int (PASCAL FAR *getsockopt)(Socket s, int level, int optname, void FAR * optval, AddressLength FAR *optlen);
static unsigned long (PASCAL FAR *inet_addr)(const char FAR * cp); static unsigned long (PASCAL FAR *inet_addr)(const char FAR * cp);
static char FAR * (PASCAL FAR *inet_ntoa)(struct in_addr in); static CString PASCAL FAR inet_ntoa(struct in_addr in);
static int (PASCAL FAR *listen)(Socket s, int backlog); static int (PASCAL FAR *listen)(Socket s, int backlog);
static ssize_t (PASCAL FAR *read)(Socket s, void FAR * buf, size_t len); static ssize_t (PASCAL FAR *read)(Socket s, void FAR * buf, size_t len);
static ssize_t (PASCAL FAR *recv)(Socket s, void FAR * buf, size_t len, int flags); static ssize_t (PASCAL FAR *recv)(Socket s, void FAR * buf, size_t len, int flags);
@ -170,27 +227,26 @@ public:
static int (PASCAL FAR *shutdown)(Socket s, int how); static int (PASCAL FAR *shutdown)(Socket s, int how);
static Socket (PASCAL FAR *socket)(int af, int type, int protocol); static Socket (PASCAL FAR *socket)(int af, int type, int protocol);
static ssize_t (PASCAL FAR *write)(Socket s, const void FAR * buf, size_t len); static ssize_t (PASCAL FAR *write)(Socket s, const void FAR * buf, size_t len);
static struct hostent FAR * (PASCAL FAR *gethostbyaddr)(const char FAR * addr, int len, int type);
static struct hostent FAR * (PASCAL FAR *gethostbyname)(const char FAR * name);
static int (PASCAL FAR *gethostname)(char FAR * name, int namelen); static int (PASCAL FAR *gethostname)(char FAR * name, int namelen);
static struct servent FAR * (PASCAL FAR *getservbyport)(int port, const char FAR * proto); static int PASCAL FAR gethostbyaddr(CHostInfo* hostinfo, const char FAR * addr, int len, int type);
static struct servent FAR * (PASCAL FAR *getservbyname)(const char FAR * name, const char FAR * proto); static int PASCAL FAR gethostbyname(CHostInfo* hostinfo, const char FAR * name);
static struct protoent FAR * (PASCAL FAR *getprotobynumber)(int proto); static int PASCAL FAR getservbyport(CServiceInfo* servinfo, int port, const char FAR * proto);
static struct protoent FAR * (PASCAL FAR *getprotobyname)(const char FAR * name); static int PASCAL FAR getservbyname(CServiceInfo* servinfo, const char FAR * name, const char FAR * proto);
static int PASCAL FAR getprotobynumber(CProtocolInfo* protoinfo, int proto);
static int PASCAL FAR getprotobyname(CProtocolInfo* protoinfo, const char FAR * name);
static int (PASCAL FAR *getsockerror)(void); static int (PASCAL FAR *getsockerror)(void);
static int (PASCAL FAR *gethosterror)(void);
// convenience functions (only available after init()) // convenience functions (only available after init())
//! Set socket to (non-)blocking operation //! Set socket to (non-)blocking operation
static int (PASCAL FAR *setblocking)(CNetwork::Socket s, bool blocking); static int PASCAL FAR setblocking(CNetwork::Socket s, bool blocking);
//! Turn Nagle algorithm on or off on socket //! Turn Nagle algorithm on or off on socket
/*! /*!
Set socket to send messages immediately (true) or to collect small Set socket to send messages immediately (true) or to collect small
messages into one packet (false). messages into one packet (false).
*/ */
static int (PASCAL FAR *setnodelay)(CNetwork::Socket s, bool nodelay); static int PASCAL FAR setnodelay(CNetwork::Socket s, bool nodelay);
private: private:
#if WINDOWS_LIKE #if WINDOWS_LIKE
@ -200,19 +256,40 @@ private:
static void init2(HMODULE); static void init2(HMODULE);
static ssize_t PASCAL FAR read2(Socket s, void FAR * buf, size_t len); static ssize_t PASCAL FAR read2(Socket s, void FAR * buf, size_t len);
static ssize_t PASCAL FAR write2(Socket s, const void FAR * buf, size_t len); static ssize_t PASCAL FAR write2(Socket s, const void FAR * buf, size_t len);
static int PASCAL FAR setblocking2(CNetwork::Socket s, bool blocking);
static int PASCAL FAR setnodelay2(CNetwork::Socket s, bool nodelay);
static int (PASCAL FAR *WSACleanup)(void); static int (PASCAL FAR *WSACleanup)(void);
static int (PASCAL FAR *__WSAFDIsSet)(CNetwork::Socket, fd_set FAR *); static int (PASCAL FAR *__WSAFDIsSet)(CNetwork::Socket, fd_set FAR *);
static int (PASCAL FAR *select)(int nfds, fd_set FAR *readfds, fd_set FAR *writefds, fd_set FAR *exceptfds, const struct timeval FAR *timeout); static int (PASCAL FAR *select)(int nfds, fd_set FAR *readfds, fd_set FAR *writefds, fd_set FAR *exceptfds, const struct timeval FAR *timeout);
static char FAR * (PASCAL FAR *inet_ntoa_n)(struct in_addr in);
static struct hostent FAR * (PASCAL FAR *gethostbyaddr_n)(const char FAR * addr, int len, int type);
static struct hostent FAR * (PASCAL FAR *gethostbyname_n)(const char FAR * name);
static struct servent FAR * (PASCAL FAR *getservbyport_n)(int port, const char FAR * proto);
static struct servent FAR * (PASCAL FAR *getservbyname_n)(const char FAR * name, const char FAR * proto);
static struct protoent FAR * (PASCAL FAR *getprotobynumber_n)(int proto);
static struct protoent FAR * (PASCAL FAR *getprotobyname_n)(const char FAR * name);
#endif #endif
#if UNIX_LIKE #if UNIX_LIKE
static int PASCAL FAR gethostname2(char FAR * name, int namelen); static int PASCAL FAR gethostname2(char FAR * name, int namelen);
static int PASCAL FAR getsockerror2(void); static int PASCAL FAR getsockerror2(void);
static int PASCAL FAR gethosterror2(void); #endif
static int PASCAL FAR setblocking2(CNetwork::Socket s, bool blocking);
static int PASCAL FAR setnodelay2(CNetwork::Socket s, bool nodelay); #if WINDOWS_LIKE || UNIX_LIKE
/* FIXME -- reentrant netdb stuff
create classes for hostent, servent, protoent.
each class can clean itself up automatically.
inside CNetwork we'll convert from netdb structs to classes.
clients will pass a class pointer which CNetwork will assign to (or swap into).
won't need free...() functions to clean up structs.
each class should know how to copy from respective netdb struct.
will need to fix CNetworkAddress to use classes.
*/
static void copyhostent(struct hostent FAR * dst, const struct hostent FAR * src);
static void copyservent(struct servent FAR * dst, const struct servent FAR * src);
static void copyprotoent(struct protoent FAR * dst, const struct protoent FAR * src);
static void freehostent(struct hostent FAR * ent);
static void freeservent(struct servent FAR * ent);
static void freeprotoent(struct protoent FAR * ent);
#endif #endif
#if WINDOWS_LIKE || !HAVE_POLL #if WINDOWS_LIKE || !HAVE_POLL

View File

@ -126,9 +126,11 @@ CNetworkAddress::CNetworkAddress(const CString& hostname_, UInt16 port) :
} }
// look up name // look up name
struct hostent* hent = CNetwork::gethostbyname(hostname.c_str()); CNetwork::CHostInfo hostInfo;
if (hent == NULL) { switch (CNetwork::gethostbyname(&hostInfo, hostname.c_str())) {
switch (CNetwork::gethosterror()) { case CNetwork::kHOST_OK:
break;
case CNetwork::kHOST_NOT_FOUND: case CNetwork::kHOST_NOT_FOUND:
throw XSocketAddress(XSocketAddress::kNotFound, hostname, port); throw XSocketAddress(XSocketAddress::kNotFound, hostname, port);
@ -140,13 +142,13 @@ CNetworkAddress::CNetworkAddress(const CString& hostname_, UInt16 port) :
default: default:
throw XSocketAddress(XSocketAddress::kUnknown, hostname, port); throw XSocketAddress(XSocketAddress::kUnknown, hostname, port);
} }
}
struct sockaddr_in* inetAddress = reinterpret_cast< struct sockaddr_in* inetAddress = reinterpret_cast<
struct sockaddr_in*>(&m_address); struct sockaddr_in*>(&m_address);
inetAddress->sin_family = hent->h_addrtype; inetAddress->sin_family = hostInfo.m_addressType;
inetAddress->sin_port = CNetwork::swaphtons(port); inetAddress->sin_port = CNetwork::swaphtons(port);
memcpy(&inetAddress->sin_addr, hent->h_addr_list[0], hent->h_length); memcpy(&inetAddress->sin_addr, hostInfo.m_addresses[0],
hostInfo.m_addressLength);
memset(inetAddress->sin_zero, 0, sizeof(inetAddress->sin_zero)); memset(inetAddress->sin_zero, 0, sizeof(inetAddress->sin_zero));
} }