📄 sockets.cxx
字号:
/*
* sockets.cxx
*
* Berkley sockets classes.
*
* Portable Windows Library
*
* Copyright (c) 1993-1998 Equivalence Pty. Ltd.
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is Portable Windows Library.
*
* The Initial Developer of the Original Code is Equivalence Pty. Ltd.
*
* Portions are Copyright (C) 1993 Free Software Foundation, Inc.
* All Rights Reserved.
*
* Contributor(s): ______________________________________.
*
* $Revision: 19426 $
* $Author: rjongbloed $
* $Date: 2008-02-09 03:19:51 +0000 (Sat, 09 Feb 2008) $
*/
#include <ptlib.h>
#include <ptlib/sockets.h>
#include <ctype.h>
#ifdef P_VXWORKS
// VxWorks variant of inet_ntoa() allocates INET_ADDR_LEN bytes via malloc
// BUT DOES NOT FREE IT !!! Use inet_ntoa_b() instead.
#define INET_ADDR_LEN 18
extern "C" void inet_ntoa_b(struct in_addr inetAddress, char *pString);
#endif // P_VXWORKS
#ifdef __NUCLEUS_PLUS__
#include <ConfigurationClass.h>
#endif
#if P_HAS_QOS
#ifdef _WIN32
#include <winbase.h>
#include <winreg.h>
#ifndef _WIN32_WCE
void CALLBACK CompletionRoutine(DWORD dwError,
DWORD cbTransferred,
LPWSAOVERLAPPED lpOverlapped,
DWORD dwFlags);
#endif // _WIN32_WCE
#endif // _WIN32
#endif // P_HAS_QOS
///////////////////////////////////////////////////////////////////////////////
// PIPSocket::Address
static int defaultIpAddressFamily = PF_INET; // PF_UNSPEC; // default to IPV4
static PIPSocket::Address loopback4(127,0,0,1);
static PIPSocket::Address broadcast4(INADDR_BROADCAST);
static PIPSocket::Address any4(INADDR_ANY);
static in_addr inaddr_empty;
#if P_HAS_IPV6
static PIPSocket::Address loopback6(16,(const BYTE *)"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\001");
static PIPSocket::Address any6(16,(const BYTE *)"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
#endif
int PIPSocket::GetDefaultIpAddressFamily()
{
return defaultIpAddressFamily;
}
void PIPSocket::SetDefaultIpAddressFamily(int ipAdressFamily)
{
defaultIpAddressFamily = ipAdressFamily;
}
void PIPSocket::SetDefaultIpAddressFamilyV4()
{
SetDefaultIpAddressFamily(PF_INET);
}
#if P_HAS_IPV6
void PIPSocket::SetDefaultIpAddressFamilyV6()
{
SetDefaultIpAddressFamily(PF_INET6);
}
PBoolean PIPSocket::IsIpAddressFamilyV6Supported()
{
int s = ::socket(PF_INET6, SOCK_DGRAM, 0);
if (s < 0)
return PFalse;
#if _WIN32
closesocket(s);
#else
_close(s);
#endif
return PTrue;
}
#endif
PIPSocket::Address PIPSocket::GetDefaultIpAny()
{
#if P_HAS_IPV6
if (defaultIpAddressFamily != PF_INET)
return any6;
#endif
return any4;
}
#if P_HAS_IPV6
class Psockaddr
{
public:
Psockaddr() { memset(&storage, 0, sizeof(storage)); }
Psockaddr(const PIPSocket::Address & ip, WORD port);
sockaddr* operator->() const { return (sockaddr *)&storage; }
operator sockaddr*() const { return (sockaddr *)&storage; }
socklen_t GetSize() const;
PIPSocket::Address GetIP() const;
WORD GetPort() const;
private:
sockaddr_storage storage;
};
Psockaddr::Psockaddr(const PIPSocket::Address & ip, WORD port)
{
memset(&storage, 0, sizeof(storage));
if (ip.GetVersion() == 6) {
sockaddr_in6 * addr6 = (sockaddr_in6 *)&storage;
addr6->sin6_family = AF_INET6;
addr6->sin6_addr = ip;
addr6->sin6_port = htons(port);
addr6->sin6_flowinfo = 0;
addr6->sin6_scope_id = 0; // Should be set to the right interface....
}
else {
sockaddr_in * addr4 = (sockaddr_in *)&storage;
addr4->sin_family = AF_INET;
addr4->sin_addr = ip;
addr4->sin_port = htons(port);
}
}
socklen_t Psockaddr::GetSize() const
{
switch (((sockaddr *)&storage)->sa_family) {
case AF_INET :
return sizeof(sockaddr_in);
case AF_INET6 :
// RFC 2133 (Old IPv6 spec) size is 24
// RFC 2553 (New IPv6 spec) size is 28
return sizeof(sockaddr_in6);
default :
return sizeof(storage);
}
}
PIPSocket::Address Psockaddr::GetIP() const
{
switch (((sockaddr *)&storage)->sa_family) {
case AF_INET :
return ((sockaddr_in *)&storage)->sin_addr;
case AF_INET6 :
return ((sockaddr_in6 *)&storage)->sin6_addr;
default :
return 0;
}
}
WORD Psockaddr::GetPort() const
{
switch (((sockaddr *)&storage)->sa_family) {
case AF_INET :
return ntohs(((sockaddr_in *)&storage)->sin_port);
case AF_INET6 :
return ntohs(((sockaddr_in6 *)&storage)->sin6_port);
default :
return 0;
}
}
#endif
#if (defined(_WIN32) || defined(WINDOWS)) && !defined(__NUCLEUS_MNT__)
static PWinSock dummyForWinSock; // Assure winsock is initialised
#endif
#if (defined(P_PTHREADS) && !defined(P_THREAD_SAFE_CLIB)) || defined(__NUCLEUS_PLUS__)
#define REENTRANT_BUFFER_LEN 1024
#endif
class PIPCacheData : public PObject
{
PCLASSINFO(PIPCacheData, PObject)
public:
PIPCacheData(struct hostent * ent, const char * original);
#if P_HAS_IPV6
PIPCacheData(struct addrinfo * addr_info, const char * original);
void AddEntry(struct addrinfo * addr_info);
#endif
const PString & GetHostName() const { return hostname; }
const PIPSocket::Address & GetHostAddress() const { return address; }
const PStringArray& GetHostAliases() const { return aliases; }
PBoolean HasAged() const;
private:
PString hostname;
PIPSocket::Address address;
PStringArray aliases;
PTime birthDate;
};
PDICTIONARY(PHostByName_private, PCaselessString, PIPCacheData);
class PHostByName : PHostByName_private
{
public:
PBoolean GetHostName(const PString & name, PString & hostname);
PBoolean GetHostAddress(const PString & name, PIPSocket::Address & address);
PBoolean GetHostAliases(const PString & name, PStringArray & aliases);
private:
PIPCacheData * GetHost(const PString & name);
PMutex mutex;
friend void PIPSocket::ClearNameCache();
};
PMutex creationMutex;
static PHostByName & pHostByName()
{
PWaitAndSignal m(creationMutex);
static PHostByName t;
return t;
}
class PIPCacheKey : public PObject
{
PCLASSINFO(PIPCacheKey, PObject)
public:
PIPCacheKey(const PIPSocket::Address & a)
{ addr = a; }
PObject * Clone() const
{ return new PIPCacheKey(*this); }
PINDEX HashFunction() const
{ return (addr[1] + addr[2] + addr[3])%41; }
private:
PIPSocket::Address addr;
};
PDICTIONARY(PHostByAddr_private, PIPCacheKey, PIPCacheData);
class PHostByAddr : PHostByAddr_private
{
public:
PBoolean GetHostName(const PIPSocket::Address & addr, PString & hostname);
PBoolean GetHostAddress(const PIPSocket::Address & addr, PIPSocket::Address & address);
PBoolean GetHostAliases(const PIPSocket::Address & addr, PStringArray & aliases);
private:
PIPCacheData * GetHost(const PIPSocket::Address & addr);
PMutex mutex;
friend void PIPSocket::ClearNameCache();
};
static PHostByAddr & pHostByAddr()
{
PWaitAndSignal m(creationMutex);
static PHostByAddr t;
return t;
}
#define new PNEW
//////////////////////////////////////////////////////////////////////////////
// IP Caching
PIPCacheData::PIPCacheData(struct hostent * host_info, const char * original)
{
if (host_info == NULL) {
address = 0;
return;
}
hostname = host_info->h_name;
if (host_info->h_addr != NULL)
#ifndef _WIN32_WCE
address = *(DWORD *)host_info->h_addr;
#else
address = PIPSocket::Address(host_info->h_length, (const BYTE *)host_info->h_addr);
#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++) {
#ifndef _WIN32_WCE
PIPSocket::Address ip(*(DWORD *)host_info->h_addr_list[i]);
#else
PIPSocket::Address ip(host_info->h_length, (const BYTE *)host_info->h_addr_list[i]);
#endif
aliases.AppendString(ip.AsString());
}
for (i = 0; i < aliases.GetSize(); i++)
if (aliases[i] *= original)
return;
aliases.AppendString(original);
}
#if P_HAS_IPV6
PIPCacheData::PIPCacheData(struct addrinfo * addr_info, const char * original)
{
PINDEX i;
if (addr_info == NULL) {
address = 0;
return;
}
// Fill Host primary informations
hostname = addr_info->ai_canonname; // Fully Qualified Domain Name (FQDN)
if (addr_info->ai_addr != NULL)
address = PIPSocket::Address(addr_info->ai_family, addr_info->ai_addrlen, addr_info->ai_addr);
// Next entries
while (addr_info != NULL) {
AddEntry(addr_info);
addr_info = addr_info->ai_next;
}
// Add original as alias or allready added ?
for (i = 0; i < aliases.GetSize(); i++) {
if (aliases[i] *= original)
return;
}
aliases.AppendString(original);
}
void PIPCacheData::AddEntry(struct addrinfo * addr_info)
{
PINDEX i;
if (addr_info == NULL)
return;
// Add canonical name
PBoolean add_it = PTrue;
for (i = 0; i < aliases.GetSize(); i++) {
if (addr_info->ai_canonname != NULL && (aliases[i] *= addr_info->ai_canonname)) {
add_it = PFalse;
break;
}
}
if (add_it && addr_info->ai_canonname != NULL)
aliases.AppendString(addr_info->ai_canonname);
// Add IP address
PIPSocket::Address ip(addr_info->ai_family, addr_info->ai_addrlen, addr_info->ai_addr);
add_it = PTrue;
for (i = 0; i < aliases.GetSize(); i++) {
if (aliases[i] *= ip.AsString()) {
add_it = PFalse;
break;
}
}
if (add_it)
aliases.AppendString(ip.AsString());
}
#endif
static PTimeInterval GetConfigTime(const char * /*key*/, DWORD dflt)
{
//PConfig cfg("DNS Cache");
//return cfg.GetInteger(key, dflt);
return dflt;
}
PBoolean PIPCacheData::HasAged() const
{
static PTimeInterval retirement = GetConfigTime("Age Limit", 300000); // 5 minutes
PTime now;
PTimeInterval age = now - birthDate;
return age > retirement;
}
PBoolean PHostByName::GetHostName(const PString & name, PString & hostname)
{
PIPCacheData * host = GetHost(name);
if (host != NULL) {
hostname = host->GetHostName();
hostname.MakeUnique();
}
mutex.Signal();
return host != NULL;
}
PBoolean PHostByName::GetHostAddress(const PString & name, PIPSocket::Address & address)
{
PIPCacheData * host = GetHost(name);
if (host != NULL)
address = host->GetHostAddress();
mutex.Signal();
return host != NULL;
}
PBoolean PHostByName::GetHostAliases(const PString & name, PStringArray & aliases)
{
PIPCacheData * host = GetHost(name);
if (host != NULL)
aliases = host->GetHostAliases();
mutex.Signal();
return host != NULL;
}
PIPCacheData * PHostByName::GetHost(const PString & name)
{
mutex.Wait();
PCaselessString key = name;
// Check for a legal hostname as per RFC952
if (key.IsEmpty() ||
key.FindSpan("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-.") != P_MAX_INDEX ||
key[key.GetLength()-1] == '-' ||
!isalpha(key[0]))
return NULL;
PIPCacheData * host = GetAt(key);
int localErrNo = NETDB_SUCCESS;
if (host != NULL && host->HasAged()) {
SetAt(key, NULL);
host = NULL;
}
if (host == NULL) {
mutex.Signal();
#if P_HAS_IPV6
struct addrinfo *res = NULL;
struct addrinfo hints = { AI_CANONNAME, PF_UNSPEC };
hints.ai_family = defaultIpAddressFamily;
localErrNo = getaddrinfo((const char *)name, NULL , &hints, &res);
mutex.Wait();
if (localErrNo != NETDB_SUCCESS) {
freeaddrinfo(res);
return NULL;
}
host = new PIPCacheData(res, name);
freeaddrinfo(res);
#else // P_HAS_IPV6
int retry = 3;
struct hostent * host_info;
#ifdef P_AIX
struct hostent_data ht_data;
memset(&ht_data, 0, sizeof(ht_data));
struct hostent hostEnt;
do {
host_info = &hostEnt;
::gethostbyname_r(name,
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 = ::gethostbyname(name);
localErrNo = h_errno;
#elif defined P_VXWORKS
struct hostent hostEnt;
host_info = Vx_gethostbyname((char *)name, &hostEnt);
localErrNo = h_errno;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -