From 586a5a81ab055abe1ec22dd2b46004f43dcf94e3 Mon Sep 17 00:00:00 2001 From: crs Date: Thu, 17 Oct 2002 20:56:28 +0000 Subject: [PATCH] Changed non-reentrant network functions to be reentrant and thread safe. --- lib/net/CNetwork.cpp | 407 ++++++++++++++++++++++++++++++++---- lib/net/CNetwork.h | 109 ++++++++-- lib/net/CNetworkAddress.cpp | 30 +-- 3 files changed, 475 insertions(+), 71 deletions(-) diff --git a/lib/net/CNetwork.cpp b/lib/net/CNetwork.cpp index c844503f..7f7398a0 100644 --- a/lib/net/CNetwork.cpp +++ b/lib/net/CNetwork.cpp @@ -15,6 +15,7 @@ #include "CNetwork.h" #include "XNetwork.h" #include "CLog.h" +#include // // 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 #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); +} diff --git a/lib/net/CNetwork.h b/lib/net/CNetwork.h index 7b3ef64c..92205679 100644 --- a/lib/net/CNetwork.h +++ b/lib/net/CNetwork.h @@ -16,6 +16,8 @@ #define CNETWORK_H #include "BasicTypes.h" +#include "CString.h" +#include "stdvector.h" #if HAVE_SYS_TYPES_H # include @@ -82,6 +84,61 @@ public: }; #endif + //! Host name information + class CHostInfo { + public: + CHostInfo() { } + CHostInfo(const struct hostent*); + + void swap(CHostInfo&); + + public: + typedef std::vector AliasList; + typedef std::vector 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 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 AliasList; + + CString m_name; + AliasList m_aliases; + int m_protocol; + }; + //! @name manipulators //@{ @@ -142,7 +199,7 @@ public: kNO_RECOVERY = NO_RECOVERY, kTRY_AGAIN = TRY_AGAIN, #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 *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 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 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); @@ -170,27 +227,26 @@ public: static int (PASCAL FAR *shutdown)(Socket s, int how); 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 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 struct servent FAR * (PASCAL FAR *getservbyport)(int port, const char FAR * proto); - static struct servent FAR * (PASCAL FAR *getservbyname)(const char FAR * name, const char FAR * proto); - static struct protoent FAR * (PASCAL FAR *getprotobynumber)(int proto); - static struct protoent FAR * (PASCAL FAR *getprotobyname)(const char FAR * name); + static int PASCAL FAR gethostbyaddr(CHostInfo* hostinfo, const char FAR * addr, int len, int type); + static int PASCAL FAR gethostbyname(CHostInfo* hostinfo, const char FAR * name); + static int PASCAL FAR getservbyport(CServiceInfo* servinfo, int port, const char FAR * proto); + 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 *gethosterror)(void); // convenience functions (only available after init()) //! 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 /*! Set socket to send messages immediately (true) or to collect small 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: #if WINDOWS_LIKE @@ -200,19 +256,40 @@ private: static void init2(HMODULE); 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 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 *__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 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 #if UNIX_LIKE static int PASCAL FAR gethostname2(char FAR * name, int namelen); static int PASCAL FAR getsockerror2(void); - static int PASCAL FAR gethosterror2(void); - static int PASCAL FAR setblocking2(CNetwork::Socket s, bool blocking); - static int PASCAL FAR setnodelay2(CNetwork::Socket s, bool nodelay); +#endif + +#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 #if WINDOWS_LIKE || !HAVE_POLL diff --git a/lib/net/CNetworkAddress.cpp b/lib/net/CNetworkAddress.cpp index ff0515d6..7e284208 100644 --- a/lib/net/CNetworkAddress.cpp +++ b/lib/net/CNetworkAddress.cpp @@ -126,27 +126,29 @@ CNetworkAddress::CNetworkAddress(const CString& hostname_, UInt16 port) : } // look up name - struct hostent* hent = CNetwork::gethostbyname(hostname.c_str()); - if (hent == NULL) { - switch (CNetwork::gethosterror()) { - case CNetwork::kHOST_NOT_FOUND: - throw XSocketAddress(XSocketAddress::kNotFound, hostname, port); + CNetwork::CHostInfo hostInfo; + switch (CNetwork::gethostbyname(&hostInfo, hostname.c_str())) { + case CNetwork::kHOST_OK: + break; - case CNetwork::kNO_DATA: - throw XSocketAddress(XSocketAddress::kNoAddress, hostname, port); + case CNetwork::kHOST_NOT_FOUND: + throw XSocketAddress(XSocketAddress::kNotFound, hostname, port); - case CNetwork::kNO_RECOVERY: - case CNetwork::kTRY_AGAIN: - default: - throw XSocketAddress(XSocketAddress::kUnknown, hostname, port); - } + case CNetwork::kNO_DATA: + throw XSocketAddress(XSocketAddress::kNoAddress, hostname, port); + + case CNetwork::kNO_RECOVERY: + case CNetwork::kTRY_AGAIN: + default: + throw XSocketAddress(XSocketAddress::kUnknown, hostname, port); } struct sockaddr_in* inetAddress = reinterpret_cast< struct sockaddr_in*>(&m_address); - inetAddress->sin_family = hent->h_addrtype; + inetAddress->sin_family = hostInfo.m_addressType; 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)); }