📄 winsock.cxx
字号:
switch (selerr) {
case 1 :
if (writefds.IsPresent(os_handle)) {
// The following is to avoid a bug in Win32 sockets. The getpeername() function doesn't
// work for some period of time after a connect, saying it is not connected yet!
for (PINDEX failsafe = 0; failsafe < 1000; failsafe++) {
sockaddr_in address;
int sz = sizeof(address);
if (::getpeername(os_handle, (struct sockaddr *)&address, &sz) == 0) {
if (address.sin_port != 0)
break;
}
::Sleep(0);
}
err = 0;
}
else {
// The following is to avoid a bug in Win32 sockets. The getsockopt() function
// doesn't work for some period of time after a connect, saying no error!
for (PINDEX failsafe = 0; failsafe < 1000; failsafe++) {
int sz = sizeof(err);
if (::getsockopt(os_handle, SOL_SOCKET, SO_ERROR, (char *)&err, &sz) == 0) {
if (err != 0)
break;
}
::Sleep(0);
}
if (err == 0)
err = WSAEFAULT; // Need to have something!
}
break;
case 0 :
err = WSAETIMEDOUT;
break;
default :
err = GetLastError();
}
if (::ioctlsocket(os_handle, FIONBIO, &fionbio) == SOCKET_ERROR) {
if (err == 0)
err = GetLastError();
}
SetLastError(err);
return ConvertOSError(err == 0 ? 0 : SOCKET_ERROR);
}
BOOL PSocket::os_accept(PSocket & listener, struct sockaddr * addr, int * size)
{
if (listener.GetReadTimeout() != PMaxTimeInterval) {
P_fd_set readfds = listener.GetHandle();
P_timeval tv = listener.GetReadTimeout();
switch (select(0, readfds, NULL, NULL, tv)) {
case 1 :
break;
case 0 :
SetLastError(WSAETIMEDOUT);
// Then return -1
default :
return ConvertOSError(-1);
}
}
return ConvertOSError(os_handle = ::accept(listener.GetHandle(), addr, size));
}
BOOL PSocket::os_recvfrom(void * buf,
PINDEX len,
int flags,
struct sockaddr * from,
PINDEX * fromlen)
{
lastReadCount = 0;
if (readTimeout != PMaxTimeInterval) {
DWORD available;
if (!ConvertOSError(ioctlsocket(os_handle, FIONREAD, &available), LastReadError))
return FALSE;
if (available == 0) {
P_fd_set readfds = os_handle;
P_timeval tv = readTimeout;
int selval = ::select(0, readfds, NULL, NULL, tv);
if (!ConvertOSError(selval, LastReadError))
return FALSE;
if (selval == 0)
return SetErrorValues(Timeout, EAGAIN, LastReadError);
if (!ConvertOSError(ioctlsocket(os_handle, FIONREAD, &available), LastReadError))
return FALSE;
}
if (available > 0 && len > (PINDEX)available)
len = available;
}
int recvResult = ::recvfrom(os_handle, (char *)buf, len, flags, from, fromlen);
if (!ConvertOSError(recvResult, LastReadError))
return FALSE;
lastReadCount = recvResult;
return TRUE;
}
BOOL PSocket::os_sendto(const void * buf,
PINDEX len,
int flags,
struct sockaddr * to,
PINDEX tolen)
{
lastWriteCount = 0;
if (writeTimeout != PMaxTimeInterval) {
P_fd_set writefds = os_handle;
P_timeval tv = writeTimeout;
int selval = ::select(0, NULL, writefds, NULL, tv);
if (selval < 0)
return FALSE;
if (selval == 0) {
#ifndef _WIN32_WCE
errno = EAGAIN;
#else
SetLastError(EAGAIN);
#endif
return FALSE;
}
}
int sendResult = ::sendto(os_handle, (const char *)buf, len, flags, to, tolen);
if (!ConvertOSError(sendResult, LastWriteError))
return FALSE;
if (sendResult == 0)
return FALSE;
lastWriteCount = sendResult;
return TRUE;
}
PChannel::Errors PSocket::Select(SelectList & read,
SelectList & write,
SelectList & except,
const PTimeInterval & timeout)
{
PINDEX i;
P_fd_set readfds;
for (i = 0; i < read.GetSize(); i++) {
if (!read[i].IsOpen())
return NotOpen;
readfds += read[i].GetHandle();
}
P_fd_set writefds;
for (i = 0; i < write.GetSize(); i++) {
if (!write[i].IsOpen())
return NotOpen;
writefds += write[i].GetHandle();
}
P_fd_set exceptfds;
for (i = 0; i < except.GetSize(); i++) {
if (!except[i].IsOpen())
return NotOpen;
exceptfds += except[i].GetHandle();
}
P_timeval tval = timeout;
int retval = select(INT_MAX, readfds, writefds, exceptfds, tval);
Errors lastError;
int osError;
if (!ConvertOSError(retval, lastError, osError))
return lastError;
if (retval > 0) {
for (i = 0; i < read.GetSize(); i++) {
int h = read[i].GetHandle();
if (h < 0)
return Interrupted;
if (!readfds.IsPresent(h))
read.RemoveAt(i--);
}
for (i = 0; i < write.GetSize(); i++) {
int h = write[i].GetHandle();
if (h < 0)
return Interrupted;
if (!writefds.IsPresent(h))
write.RemoveAt(i--);
}
for (i = 0; i < except.GetSize(); i++) {
int h = except[i].GetHandle();
if (h < 0)
return Interrupted;
if (!exceptfds.IsPresent(h))
except.RemoveAt(i--);
}
}
else {
read.RemoveAll();
write.RemoveAll();
except.RemoveAll();
}
return NoError;
}
BOOL PSocket::ConvertOSError(int status, ErrorGroup group)
{
Errors lastError;
int osError;
BOOL ok = ConvertOSError(status, lastError, osError);
SetErrorValues(lastError, osError, group);
return ok;
}
BOOL PSocket::ConvertOSError(int status, Errors & lastError, int & osError)
{
if (status >= 0) {
lastError = NoError;
osError = 0;
return TRUE;
}
#ifdef _WIN32
SetLastError(WSAGetLastError());
return PChannel::ConvertOSError(-2, lastError, osError);
#else
osError = WSAGetLastError();
switch (osError) {
case 0 :
lastError = NoError;
return TRUE;
case WSAEWOULDBLOCK :
lastError = Timeout;
break;
default :
osError |= PWIN32ErrorFlag;
lastError = Miscellaneous;
}
return FALSE;
#endif
}
//////////////////////////////////////////////////////////////////////////////
// PIPSocket::Address
PIPSocket::Address::Address(BYTE b1, BYTE b2, BYTE b3, BYTE b4)
{
version = 4;
v.four.S_un.S_un_b.s_b1 = b1;
v.four.S_un.S_un_b.s_b2 = b2;
v.four.S_un.S_un_b.s_b3 = b3;
v.four.S_un.S_un_b.s_b4 = b4;
}
PIPSocket::Address::Address(DWORD dw)
{
operator=(dw);
}
PIPSocket::Address & PIPSocket::Address::operator=(DWORD dw)
{
if (dw == 0) {
version = 0;
memset(&v, 0, sizeof(v));
}
else {
version = 4;
v.four.S_un.S_addr = dw;
}
return *this;
}
PIPSocket::Address::operator DWORD() const
{
return version != 4 ? 0 : v.four.S_un.S_addr;
}
BYTE PIPSocket::Address::Byte1() const
{
return v.four.S_un.S_un_b.s_b1;
}
BYTE PIPSocket::Address::Byte2() const
{
return v.four.S_un.S_un_b.s_b2;
}
BYTE PIPSocket::Address::Byte3() const
{
return v.four.S_un.S_un_b.s_b3;
}
BYTE PIPSocket::Address::Byte4() const
{
return v.four.S_un.S_un_b.s_b4;
}
//////////////////////////////////////////////////////////////////////////////
// PIPSocket
BOOL P_IsOldWin95()
{
static int state = -1;
if (state < 0) {
state = 1;
OSVERSIONINFO info;
info.dwOSVersionInfoSize = sizeof(info);
if (GetVersionEx(&info)) {
state = 0;
if (info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS && info.dwBuildNumber < 1000)
state = 1;
}
}
return state != 0;
}
BOOL PIPSocket::IsLocalHost(const PString & hostname)
{
if (hostname.IsEmpty())
return TRUE;
if (hostname *= "localhost")
return TRUE;
// lookup the host address using inet_addr, assuming it is a "." address
PIPSocket::Address addr = hostname;
if (addr.IsLoopback()) // Is 127.0.0.1 or ::1
return TRUE;
if (addr == 0) {
if (!GetHostAddress(hostname, addr))
return FALSE;
}
// Seb: Should check that it's really IPv4 aware.
struct hostent * host_info = ::gethostbyname(GetHostName());
if (P_IsOldWin95())
return addr == *(struct in_addr *)host_info->h_addr_list[0];
for (PINDEX i = 0; host_info->h_addr_list[i] != NULL; i++) {
#if P_HAS_IPV6
if (host_info->h_length == 16) {
if (addr == *(struct in6_addr *)host_info->h_addr_list[i])
return TRUE;
}
else
#endif
if (addr == *(struct in_addr *)host_info->h_addr_list[i])
return TRUE;
}
return FALSE;
}
//////////////////////////////////////////////////////////////////////////////
// PUDPSocket
BOOL PUDPSocket::disableGQoS = TRUE;
void PUDPSocket::EnableGQoS()
{
disableGQoS = FALSE;
}
#if P_HAS_QOS
BOOL PUDPSocket::SupportQoS(const PIPSocket::Address & address)
{
if (disableGQoS)
return FALSE;
if (!address.IsValid())
return FALSE;
// Check to See if OS supportive
OSVERSIONINFO versInfo;
ZeroMemory(&versInfo,sizeof(OSVERSIONINFO));
versInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if (!(GetVersionEx(&versInfo)))
return FALSE;
else
{
if (versInfo.dwMajorVersion < 5)
return FALSE; // Not Supported in Windows
if (versInfo.dwMajorVersion == 5 &&
versInfo.dwMinorVersion == 0)
return FALSE; //Windows 2000 does not always support QOS_DESTADDR
}
// Need to put in a check to see if the NIC has 802.1p packet priority support
// This Requires access to the NIC driver and requires Windows DDK. To Be Done Sometime...
// Get the name of the required NIC to check whether it supports 802.1p
PString NICname = PIPSocket::GetInterface(address);
// For Now Assume it can.
return TRUE;
}
#else
BOOL PUDPSocket::SupportQoS(const PIPSocket::Address &)
{
return FALSE;
}
#endif // P_HAS_QOS
#if P_HAS_QOS
#ifndef _WIN32_WCE
PWinQoS::~PWinQoS()
{
delete sa;
}
PWinQoS::PWinQoS(PQoS & pqos, struct sockaddr * to, char * inBuf, DWORD & bufLen)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -