📄 sockets.cxx
字号:
//////////////////////////////////////////////////////////////////////////////
// IP Caching
PIPCacheData::PIPCacheData(struct hostent * host_info, const char * original)
{
if (host_info == NULL) {
address.s_addr = 0;
return;
}
hostname = host_info->h_name;
#ifndef _WIN32_WCE
address = *(DWORD *)host_info->h_addr;
#else
if( host_info->h_addr )
address = PIPSocket::Address(
(BYTE) host_info->h_addr[0],
(BYTE) host_info->h_addr[1],
(BYTE) host_info->h_addr[2],
(BYTE) host_info->h_addr[3]);
#endif
aliases.AppendString(host_info->h_name);
PINDEX i;
for (i = 0; host_info->h_aliases[i] != NULL; i++)
aliases.AppendString(host_info->h_aliases[i]);
for (i = 0; host_info->h_addr_list[i] != NULL; i++)
aliases.AppendString(inet_ntoa(*(struct in_addr *)host_info->h_addr_list[i]));
for (i = 0; i < aliases.GetSize(); i++)
if (aliases[i] *= original)
return;
aliases.AppendString(original);
}
static PTimeInterval GetConfigTime(const char * key, DWORD dflt)
{
PConfig cfg("DNS Cache");
return cfg.GetInteger(key, dflt);
}
BOOL PIPCacheData::HasAged() const
{
static PTimeInterval retirement = GetConfigTime("Age Limit", 300000); // 5 minutes
PTime now;
PTimeInterval age = now - birthDate;
return age > retirement;
}
BOOL PHostByName::GetHostName(const PString & name, PString & hostname)
{
PIPCacheData * host = GetHost(name);
if (host != NULL) {
hostname = host->GetHostName();
hostname.MakeUnique();
}
mutex.Signal();
return host != NULL;
}
BOOL PHostByName::GetHostAddress(const PString & name, PIPSocket::Address & address)
{
PIPCacheData * host = GetHost(name);
if (host != NULL)
address = host->GetHostAddress();
mutex.Signal();
return host != NULL;
}
BOOL PHostByName::GetHostAliases(const PString & name, PStringArray & aliases)
{
PIPCacheData * host = GetHost(name);
if (host != NULL) {
const PStringList & a = host->GetHostAliases();
aliases.SetSize(a.GetSize());
for (PINDEX i = 0; i < a.GetSize(); i++)
aliases[i] = a[i];
}
mutex.Signal();
return host != NULL;
}
PIPCacheData * PHostByName::GetHost(const PString & name)
{
mutex.Wait();
PCaselessString key = name;
PIPCacheData * host = GetAt(key);
if (host != NULL && host->HasAged()) {
SetAt(key, NULL);
host = NULL;
}
if (host == NULL) {
mutex.Signal();
#ifdef P_AIX
struct hostent_data ht_data;
memset(&ht_data, 0, sizeof(ht_data));
struct hostent host_info;
#else
struct hostent * host_info;
#endif
int retry = 3;
do {
#if ( ( defined(P_PTHREADS) && !defined(P_THREAD_SAFE_CLIB) ) || (defined(__NUCLEUS_PLUS__) ) )
// this function should really be a static on PIPSocket, but this would
// require allocating thread-local storage for the data and that's too much
// of a pain!
#ifndef P_AIX // that I get no warnings
int localErrNo;
char buffer[REENTRANT_BUFFER_LEN];
struct hostent hostEnt;
#endif
#ifdef P_LINUX
::gethostbyname_r(name,
&hostEnt,
buffer, REENTRANT_BUFFER_LEN,
&host_info,
&localErrNo);
#elif defined P_AIX
::gethostbyname_r(name,
&host_info,
&ht_data);
#else
host_info = ::gethostbyname_r(name,
&hostEnt, buffer, REENTRANT_BUFFER_LEN,
&localErrNo);
#endif
#else
host_info = ::gethostbyname(name);
#endif
} while (h_errno == TRY_AGAIN && --retry > 0);
mutex.Wait();
if (retry == 0)
return NULL;
#ifdef P_AIX
host = new PIPCacheData (&host_info, (const char*) name);
#else
host = new PIPCacheData(host_info, name);
#endif
SetAt(key, host);
}
if (host->GetHostAddress() == 0)
return NULL;
return host;
}
BOOL 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;
}
BOOL PHostByAddr::GetHostAddress(const PIPSocket::Address & addr, PIPSocket::Address & address)
{
PIPCacheData * host = GetHost(addr);
if (host != NULL)
address = host->GetHostAddress();
mutex.Signal();
return host != NULL;
}
BOOL PHostByAddr::GetHostAliases(const PIPSocket::Address & addr, PStringArray & aliases)
{
PIPCacheData * host = GetHost(addr);
if (host != NULL) {
const PStringList & a = host->GetHostAliases();
aliases.SetSize(a.GetSize());
for (PINDEX i = 0; i < a.GetSize(); i++)
aliases[i] = a[i];
}
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();
#ifdef P_AIX
struct hostent_data ht_data;
struct hostent host_info;
#else
struct hostent * host_info;
#endif
int retry = 3;
do {
#if ( ( defined(P_PTHREADS) && !defined(P_THREAD_SAFE_CLIB) ) || ( defined(__NUCLEUS_PLUS__) ) )
// this function should really be a static on PIPSocket, but this would
// require allocating thread-local storage for the data and that's too much
// of a pain!
#ifndef P_AIX // that I get no warnings
int localErrNo;
char buffer[REENTRANT_BUFFER_LEN];
struct hostent hostEnt;
#endif
#ifdef P_LINUX
::gethostbyaddr_r((const char *)&addr, sizeof(addr),
PF_INET,
&hostEnt,
buffer, REENTRANT_BUFFER_LEN,
&host_info,
&localErrNo);
#elif P_AIX
::gethostbyaddr_r((char *)&addr, sizeof(addr),
PF_INET,
&host_info,
&ht_data );
#else
host_info = ::gethostbyaddr_r((const char *)&addr, sizeof(addr), PF_INET,
&hostEnt, buffer, REENTRANT_BUFFER_LEN, &localErrNo);
#endif
#else
host_info = ::gethostbyaddr((const char *)&addr, sizeof(addr), PF_INET);
#if defined(_WIN32) || defined(WINDOWS) // Kludge to avoid strange 95 bug
extern P_IsOldWin95();
if (P_IsOldWin95() && host_info != NULL && host_info->h_addr_list[0] != NULL)
host_info->h_addr_list[1] = NULL;
#endif
#endif
} while (h_errno == TRY_AGAIN && --retry > 0);
mutex.Wait();
if (retry == 0)
return FALSE;
#ifdef P_AIX
host = new PIPCacheData(&host_info, inet_ntoa(addr));
#else
host = new PIPCacheData(host_info, inet_ntoa(addr));
#endif
SetAt(key, host);
}
if (host->GetHostAddress() == 0)
return NULL;
return host;
}
//////////////////////////////////////////////////////////////////////////////
// PSocket
PSocket::PSocket()
{
port = 0;
}
BOOL PSocket::Connect(const PString &)
{
PAssertAlways("Illegal operation.");
return FALSE;
}
BOOL PSocket::Listen(unsigned, WORD, Reusability)
{
PAssertAlways("Illegal operation.");
return FALSE;
}
BOOL PSocket::Accept(PSocket &)
{
PAssertAlways("Illegal operation.");
return FALSE;
}
BOOL PSocket::SetOption(int option, int value, int level)
{
#ifdef _WIN32_WCE
if(option == SO_RCVBUF || option == SO_SNDBUF || option == IP_TOS)
return TRUE;
#endif
return ConvertOSError(::setsockopt(os_handle, level, option,
(char *)&value, sizeof(value)));
}
BOOL PSocket::SetOption(int option, const void * valuePtr, PINDEX valueSize, int level)
{
return ConvertOSError(::setsockopt(os_handle, level, option,
(char *)valuePtr, valueSize));
}
BOOL PSocket::GetOption(int option, int & value, int level)
{
#ifdef BE_BONELESS
return FALSE;
#else
socklen_t valSize = sizeof(value);
return ConvertOSError(::getsockopt(os_handle, level, option,
(char *)&value, &valSize));
#endif
}
BOOL PSocket::GetOption(int option, void * valuePtr, PINDEX valueSize, int level)
{
#ifdef BE_BONELESS
return FALSE;
#else
return ConvertOSError(::getsockopt(os_handle, level, option,
(char *)valuePtr, (socklen_t *)&valueSize));
#endif
}
BOOL PSocket::Shutdown(ShutdownValue value)
{
return ConvertOSError(::shutdown(os_handle, value));
}
WORD PSocket::GetProtocolByName(const PString & name)
{
#if !defined(BE_BONELESS) && !defined(__NUCLEUS_PLUS__) && !defined(_WIN32_WCE)
struct protoent * ent = getprotobyname(name);
if (ent != NULL)
return ent->p_proto;
#endif
return 0;
}
PString PSocket::GetNameByProtocol(WORD proto)
{
#if !defined(BE_BONELESS) && !defined(__NUCLEUS_PLUS__) && !defined(_WIN32_WCE)
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 defined( __NUCLEUS_PLUS__ )
if(!strcmp(protocol,"tcp") && service.AsInteger()>0) return service.AsInteger();
PAssertAlways
("PSocket::GetPortByService: problem as no ::getservbyname in Nucleus NET");
return 0;
#elif defined(_WIN32_WCE)
if( service.AsInteger() > 0 )
return (WORD) service.AsInteger();
PAssertAlways("PSocket::GetPortByService: problem for WindowsCE as no port given.");
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(BE_BONELESS) && !defined(__NUCLEUS_PLUS__) && !defined(_WIN32_WCE)
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;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -