📄 sockets.cxx
字号:
#elif defined P_LINUX
char buffer[REENTRANT_BUFFER_LEN];
struct hostent hostEnt;
do {
if (::gethostbyname_r(name,
&hostEnt,
buffer, REENTRANT_BUFFER_LEN,
&host_info,
&localErrNo) == 0)
localErrNo = NETDB_SUCCESS;
} while (localErrNo == TRY_AGAIN && --retry > 0);
#elif (defined(P_PTHREADS) && !defined(P_THREAD_SAFE_CLIB)) || defined(__NUCLEUS_PLUS__)
char buffer[REENTRANT_BUFFER_LEN];
struct hostent hostEnt;
do {
host_info = ::gethostbyname_r(name,
&hostEnt,
buffer, REENTRANT_BUFFER_LEN,
&localErrNo);
} while (localErrNo == TRY_AGAIN && --retry > 0);
#else
host_info = ::gethostbyname(name);
localErrNo = h_errno;
#endif
mutex.Wait();
if (localErrNo != NETDB_SUCCESS || retry == 0)
return NULL;
host = new PIPCacheData(host_info, name);
#endif //P_HAS_IPV6
SetAt(key, host);
}
if (host->GetHostAddress() == 0)
return NULL;
return host;
}
PBoolean PHostByAddr::GetHostName(const PIPSocket::Address & addr, PString & hostname)
{
PIPCacheData * host = GetHost(addr);
if (host != NULL) {
hostname = host->GetHostName();
hostname.MakeUnique();
}
mutex.Signal();
return host != NULL;
}
PBoolean PHostByAddr::GetHostAddress(const PIPSocket::Address & addr, PIPSocket::Address & address)
{
PIPCacheData * host = GetHost(addr);
if (host != NULL)
address = host->GetHostAddress();
mutex.Signal();
return host != NULL;
}
PBoolean PHostByAddr::GetHostAliases(const PIPSocket::Address & addr, PStringArray & aliases)
{
PIPCacheData * host = GetHost(addr);
if (host != NULL)
aliases = host->GetHostAliases();
mutex.Signal();
return host != NULL;
}
PIPCacheData * PHostByAddr::GetHost(const PIPSocket::Address & addr)
{
mutex.Wait();
PIPCacheKey key = addr;
PIPCacheData * host = GetAt(key);
if (host != NULL && host->HasAged()) {
SetAt(key, NULL);
host = NULL;
}
if (host == NULL) {
mutex.Signal();
int retry = 3;
int localErrNo = NETDB_SUCCESS;
struct hostent * host_info;
#ifdef P_AIX
struct hostent_data ht_data;
struct hostent hostEnt;
do {
host_info = &hostEnt;
::gethostbyaddr_r((char *)addr.GetPointer(), addr.GetSize(),
PF_INET,
host_info,
&ht_data);
localErrNo = h_errno;
} while (localErrNo == TRY_AGAIN && --retry > 0);
#elif defined P_RTEMS || defined P_CYGWIN || defined P_MINGW
host_info = ::gethostbyaddr(addr.GetPointer(), addr.GetSize(), PF_INET);
localErrNo = h_errno;
#elif defined P_VXWORKS
struct hostent hostEnt;
host_info = Vx_gethostbyaddr(addr.GetPointer(), &hostEnt);
#elif defined P_LINUX
char buffer[REENTRANT_BUFFER_LEN];
struct hostent hostEnt;
do {
::gethostbyaddr_r(addr.GetPointer(), addr.GetSize(),
PF_INET,
&hostEnt,
buffer, REENTRANT_BUFFER_LEN,
&host_info,
&localErrNo);
} while (localErrNo == TRY_AGAIN && --retry > 0);
#elif (defined(P_PTHREADS) && !defined(P_THREAD_SAFE_CLIB)) || defined(__NUCLEUS_PLUS__)
char buffer[REENTRANT_BUFFER_LEN];
struct hostent hostEnt;
do {
host_info = ::gethostbyaddr_r(addr.GetPointer(), addr.GetSize(),
PF_INET,
&hostEnt,
buffer, REENTRANT_BUFFER_LEN,
&localErrNo);
} while (localErrNo == TRY_AGAIN && --retry > 0);
#else
host_info = ::gethostbyaddr(addr.GetPointer(), addr.GetSize(), PF_INET);
localErrNo = h_errno;
#if defined(_WIN32) || defined(WINDOWS) // Kludge to avoid strange 95 bug
extern PBoolean P_IsOldWin95();
if (P_IsOldWin95() && host_info != NULL && host_info->h_addr_list[0] != NULL)
host_info->h_addr_list[1] = NULL;
#endif
#endif
mutex.Wait();
if (localErrNo != NETDB_SUCCESS || retry == 0)
return NULL;
host = new PIPCacheData(host_info, addr.AsString());
SetAt(key, host);
}
if (host->GetHostAddress() == 0)
return NULL;
return host;
}
//////////////////////////////////////////////////////////////////////////////
// P_fd_set
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4127)
#endif
P_fd_set::P_fd_set()
{
Construct();
Zero();
}
P_fd_set::P_fd_set(SOCKET fd)
{
Construct();
Zero();
FD_SET(fd, set);
}
P_fd_set & P_fd_set::operator=(SOCKET fd)
{
PAssert(fd < max_fd, PInvalidParameter);
Zero();
FD_SET(fd, set);
return *this;
}
P_fd_set & P_fd_set::operator+=(SOCKET fd)
{
PAssert(fd < max_fd, PInvalidParameter);
FD_SET(fd, set);
return *this;
}
P_fd_set & P_fd_set::operator-=(SOCKET fd)
{
PAssert(fd < max_fd, PInvalidParameter);
FD_CLR(fd, set);
return *this;
}
#ifdef _MSC_VER
#pragma warning(pop)
#endif
//////////////////////////////////////////////////////////////////////////////
// P_timeval
P_timeval::P_timeval()
{
tval.tv_usec = 0;
tval.tv_sec = 0;
infinite = PFalse;
}
P_timeval & P_timeval::operator=(const PTimeInterval & time)
{
infinite = time == PMaxTimeInterval;
tval.tv_usec = (long)(time.GetMilliSeconds()%1000)*1000;
tval.tv_sec = time.GetSeconds();
return *this;
}
//////////////////////////////////////////////////////////////////////////////
// PSocket
PSocket::PSocket()
{
port = 0;
#if P_HAS_RECVMSG
catchReceiveToAddr = PFalse;
#endif
}
PBoolean PSocket::Connect(const PString &)
{
PAssertAlways("Illegal operation.");
return PFalse;
}
PBoolean PSocket::Listen(unsigned, WORD, Reusability)
{
PAssertAlways("Illegal operation.");
return PFalse;
}
PBoolean PSocket::Accept(PSocket &)
{
PAssertAlways("Illegal operation.");
return PFalse;
}
PBoolean PSocket::SetOption(int option, int value, int level)
{
#ifdef _WIN32_WCE
if(option == SO_RCVBUF || option == SO_SNDBUF || option == IP_TOS)
return PTrue;
#endif
return ConvertOSError(::setsockopt(os_handle, level, option,
(char *)&value, sizeof(value)));
}
PBoolean PSocket::SetOption(int option, const void * valuePtr, PINDEX valueSize, int level)
{
return ConvertOSError(::setsockopt(os_handle, level, option,
(char *)valuePtr, valueSize));
}
PBoolean PSocket::GetOption(int option, int & value, int level)
{
socklen_t valSize = sizeof(value);
return ConvertOSError(::getsockopt(os_handle, level, option,
(char *)&value, &valSize));
}
PBoolean PSocket::GetOption(int option, void * valuePtr, PINDEX valueSize, int level)
{
return ConvertOSError(::getsockopt(os_handle, level, option,
(char *)valuePtr, (socklen_t *)&valueSize));
}
PBoolean PSocket::Shutdown(ShutdownValue value)
{
return ConvertOSError(::shutdown(os_handle, value));
}
WORD PSocket::GetProtocolByName(const PString & name)
{
#if !defined(__NUCLEUS_PLUS__) && !defined(P_VXWORKS)
struct protoent * ent = getprotobyname(name);
if (ent != NULL)
return ent->p_proto;
#endif
return 0;
}
PString PSocket::GetNameByProtocol(WORD proto)
{
#if !defined(__NUCLEUS_PLUS__) && !defined(P_VXWORKS)
struct protoent * ent = getprotobynumber(proto);
if (ent != NULL)
return ent->p_name;
#endif
return psprintf("%u", proto);
}
WORD PSocket::GetPortByService(const PString & serviceName) const
{
return GetPortByService(GetProtocolName(), serviceName);
}
WORD PSocket::GetPortByService(const char * protocol, const PString & service)
{
// if the string is a valid integer, then use integer value
// this avoids stupid problems like operating systems that match service
// names to substrings (like "2000" to "taskmaster2000")
if (service.FindSpan("0123456789") == P_MAX_INDEX)
return (WORD)service.AsUnsigned();
#if defined( __NUCLEUS_PLUS__ )
PAssertAlways("PSocket::GetPortByService: problem as no ::getservbyname in Nucleus NET");
return 0;
#elif defined(P_VXWORKS)
PAssertAlways("PSocket::GetPortByService: problem as no ::getservbyname in VxWorks");
return 0;
#else
PINDEX space = service.FindOneOf(" \t\r\n");
struct servent * serv = ::getservbyname(service(0, space-1), protocol);
if (serv != NULL)
return ntohs(serv->s_port);
long portNum;
if (space != P_MAX_INDEX)
portNum = atol(service(space+1, P_MAX_INDEX));
else if (isdigit(service[0]))
portNum = atoi(service);
else
portNum = -1;
if (portNum < 0 || portNum > 65535)
return 0;
return (WORD)portNum;
#endif
}
PString PSocket::GetServiceByPort(WORD port) const
{
return GetServiceByPort(GetProtocolName(), port);
}
PString PSocket::GetServiceByPort(const char * protocol, WORD port)
{
#if !defined(__NUCLEUS_PLUS__) && !defined(P_VXWORKS)
struct servent * serv = ::getservbyport(htons(port), protocol);
if (serv != NULL)
return PString(serv->s_name);
else
#endif
return PString(PString::Unsigned, port);
}
void PSocket::SetPort(WORD newPort)
{
PAssert(!IsOpen(), "Cannot change port number of opened socket");
port = newPort;
}
void PSocket::SetPort(const PString & service)
{
PAssert(!IsOpen(), "Cannot change port number of opened socket");
port = GetPortByService(service);
}
WORD PSocket::GetPort() const
{
return port;
}
PString PSocket::GetService() const
{
return GetServiceByPort(port);
}
int PSocket::Select(PSocket & sock1, PSocket & sock2)
{
return Select(sock1, sock2, PMaxTimeInterval);
}
int PSocket::Select(PSocket & sock1,
PSocket & sock2,
const PTimeInterval & timeout)
{
SelectList read, dummy1, dummy2;
read += sock1;
read += sock2;
Errors lastError;
int osError;
if (!ConvertOSError(Select(read, dummy1, dummy2, timeout), lastError, osError))
return lastError;
switch (read.GetSize()) {
case 0 :
return 0;
case 2 :
return -3;
default :
return &read.front() == &sock1 ? -1 : -2;
}
}
PChannel::Errors PSocket::Select(SelectList & read)
{
SelectList dummy1, dummy2;
return Select(read, dummy1, dummy2, PMaxTimeInterval);
}
PChannel::Errors PSocket::Select(SelectList & read, const PTimeInterval & timeout)
{
SelectList dummy1, dummy2;
return Select(read, dummy1, dummy2, timeout);
}
PChannel::Errors PSocket::Select(SelectList & read, SelectList & write)
{
SelectList dummy1;
return Select(read, write, dummy1, PMaxTimeInterval);
}
PChannel::Errors PSocket::Select(SelectList & read,
SelectList & write,
const PTimeInterval & timeout)
{
SelectList dummy1;
return Select(read, write, dummy1, timeout);
}
PChannel::Errors PSocket::Select(SelectList & read,
SelectList & write,
SelectList & except)
{
return Select(read, write, except, PMaxTimeInterval);
}
//////////////////////////////////////////////////////////////////////////////
// PIPSocket
PIPSocket::PIPSocket()
{
}
void PIPSocket::ClearNameCache()
{
pHostByName().mutex.Wait();
pHostByAddr().mutex.Wait();
pHostByName().RemoveAll();
pHostByAddr().RemoveAll();
#if (defined(_WIN32) || defined(WINDOWS)) && !defined(__NUCLEUS_MNT__) // Kludge to avoid strange NT bug
static PTimeInterval delay = GetConfigTime("NT Bug Delay", 0);
if (delay != 0) {
::Sleep(delay.GetInterval());
::gethostbyname("www.microsoft.com");
}
#endif
pHostByName().mutex.Signal();
pHostByAddr().mutex.Signal();
}
PString PIPSocket::GetName() const
{
#if P_HAS_IPV6
Psockaddr sa;
socklen_t size = sa.GetSize();
if (getpeername(os_handle, sa, &size) == 0)
return GetHostName(sa.GetIP()) + psprintf(":%u", sa.GetPort());
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -