📄 winsock.cxx
字号:
/*
* winsock.cxx
*
* WINSOCK implementation of Berkley sockets.
*
* 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 <svcguid.h>
#ifndef _WIN32_WCE
#include <nspapi.h>
#include <wsipx.h>
#ifdef _MSC_VER
#include <wsnwlink.h>
#if defined(P_WINSOCK2_LIBRARY)
#pragma comment(lib, P_WINSOCK2_LIBRARY)
#else
#pragma comment(lib, "wsock32.lib")
#endif
#else
#define IPX_PTYPE 0x4000
#define NS_DEFAULT 0
#ifndef SVCID_NETWARE
#define SVCID_NETWARE(_SapId) {(0x000B << 16)|(_SapId),0,0,{0xC0,0,0,0,0,0,0,0x46}}
#endif /* SVCID_NETWARE */
#define SVCID_FILE_SERVER SVCID_NETWARE(0x4)
#endif
#endif // !_WIN32_WCE
//////////////////////////////////////////////////////////////////////////////
// PWinSock
PWinSock::PWinSock()
{
WSADATA winsock;
#if 0 // old WinSock version check
PAssert(WSAStartup(0x101, &winsock) == 0, POperatingSystemError);
PAssert(LOBYTE(winsock.wVersion) == 1 &&
HIBYTE(winsock.wVersion) == 1, POperatingSystemError);
#endif
// ensure we support QoS
PAssert(WSAStartup(0x0202, &winsock) == 0, POperatingSystemError);
PAssert(LOBYTE(winsock.wVersion) >= 1 &&
HIBYTE(winsock.wVersion) >= 1, POperatingSystemError);
}
PWinSock::~PWinSock()
{
WSACleanup();
}
PBoolean PWinSock::OpenSocket()
{
return PFalse;
}
const char * PWinSock::GetProtocolName() const
{
return NULL;
}
//////////////////////////////////////////////////////////////////////////////
// P_fd_set
void P_fd_set::Construct()
{
max_fd = UINT_MAX;
set = (fd_set *)malloc(sizeof(fd_set));
}
void P_fd_set::Zero()
{
if (PAssertNULL(set) != NULL)
FD_ZERO(set);
}
//////////////////////////////////////////////////////////////////////////////
// PSocket
PSocket::~PSocket()
{
Close();
}
PBoolean PSocket::Read(void * buf, PINDEX len)
{
flush();
lastReadCount = 0;
if (len == 0)
return SetErrorValues(BadParameter, EINVAL, LastReadError);
os_recvfrom((char *)buf, len, 0, NULL, NULL);
return lastReadCount > 0;
}
PBoolean PSocket::Write(const void * buf, PINDEX len)
{
flush();
return os_sendto(buf, len, 0, NULL, 0) && lastWriteCount >= len;
}
PBoolean PSocket::Close()
{
if (!IsOpen())
return PFalse;
flush();
return ConvertOSError(os_close());
}
int PSocket::os_close()
{
int err = closesocket(os_handle);
os_handle = -1;
clear();
return err;
}
int PSocket::os_socket(int af, int type, int proto)
{
return ::socket(af, type, proto);
}
PBoolean PSocket::os_connect(struct sockaddr * addr, PINDEX size)
{
if (readTimeout == PMaxTimeInterval)
return ConvertOSError(::connect(os_handle, addr, size));
DWORD fionbio = 1;
if (!ConvertOSError(::ioctlsocket(os_handle, FIONBIO, &fionbio)))
return PFalse;
fionbio = 0;
if (::connect(os_handle, addr, size) != SOCKET_ERROR)
return ConvertOSError(::ioctlsocket(os_handle, FIONBIO, &fionbio));
DWORD err = GetLastError();
if (err != WSAEWOULDBLOCK) {
::ioctlsocket(os_handle, FIONBIO, &fionbio);
SetLastError(err);
return ConvertOSError(-1);
}
P_fd_set writefds = os_handle;
P_fd_set exceptfds = os_handle;
P_timeval tv;
/* To avoid some strange behaviour on various windows platforms, do a zero
timeout select first to pick up errors. Then do real timeout. */
int selerr = ::select(1, NULL, writefds, exceptfds, tv);
if (selerr == 0) {
writefds = os_handle;
exceptfds = os_handle;
tv = readTimeout;
selerr = ::select(1, NULL, writefds, exceptfds, tv);
}
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);
}
PBoolean 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));
}
PBoolean 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 PFalse;
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 PFalse;
if (selval == 0)
return SetErrorValues(Timeout, EAGAIN, LastReadError);
if (!ConvertOSError(ioctlsocket(os_handle, FIONREAD, &available), LastReadError))
return PFalse;
}
if (available > 0 && len > (PINDEX)available)
len = available;
}
int recvResult = ::recvfrom(os_handle, (char *)buf, len, flags, from, fromlen);
if (!ConvertOSError(recvResult, LastReadError))
return PFalse;
lastReadCount = recvResult;
return PTrue;
}
PBoolean 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 PFalse;
if (selval == 0) {
#ifndef _WIN32_WCE
errno = EAGAIN;
#else
SetLastError(EAGAIN);
#endif
return PFalse;
}
}
int sendResult = ::sendto(os_handle, (const char *)buf, len, flags, to, tolen);
if (!ConvertOSError(sendResult, LastWriteError))
return PFalse;
if (sendResult == 0)
return PFalse;
lastWriteCount = sendResult;
return PTrue;
}
PChannel::Errors PSocket::Select(SelectList & read,
SelectList & write,
SelectList & except,
const PTimeInterval & timeout)
{
SelectList::iterator sock;
P_fd_set readfds;
for (sock = read.begin(); sock != read.end(); ++sock) {
if (!sock->IsOpen())
return NotOpen;
readfds += sock->GetHandle();
}
P_fd_set writefds;
for (sock = write.begin(); sock != write.end(); ++sock) {
if (!sock->IsOpen())
return NotOpen;
writefds += sock->GetHandle();
}
P_fd_set exceptfds;
for (sock = except.begin(); sock != except.end(); ++sock) {
if (!sock->IsOpen())
return NotOpen;
exceptfds += sock->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) {
sock = read.begin();
while (sock != read.end()) {
int h = sock->GetHandle();
if (h < 0)
return Interrupted;
if (readfds.IsPresent(h))
++sock;
else
read.erase(sock++);
}
sock = write.begin();
while ( sock != write.end()) {
int h = sock->GetHandle();
if (h < 0)
return Interrupted;
if (writefds.IsPresent(h))
++sock;
else
write.erase(sock++);
}
sock = except.begin();
while ( sock != except.end()) {
int h = sock->GetHandle();
if (h < 0)
return Interrupted;
if (exceptfds.IsPresent(h))
++sock;
else
except.erase(sock++);
}
}
else {
read.RemoveAll();
write.RemoveAll();
except.RemoveAll();
}
return NoError;
}
PBoolean PSocket::ConvertOSError(int status, ErrorGroup group)
{
Errors lastError;
int osError;
PBoolean ok = ConvertOSError(status, lastError, osError);
SetErrorValues(lastError, osError, group);
return ok;
}
PBoolean PSocket::ConvertOSError(int status, Errors & lastError, int & osError)
{
if (status >= 0) {
lastError = NoError;
osError = 0;
return PTrue;
}
#ifdef _WIN32
SetLastError(WSAGetLastError());
return PChannel::ConvertOSError(-2, lastError, osError);
#else
osError = WSAGetLastError();
switch (osError) {
case 0 :
lastError = NoError;
return PTrue;
case WSAEWOULDBLOCK :
lastError = Timeout;
break;
default :
osError |= PWIN32ErrorFlag;
lastError = Miscellaneous;
}
return PFalse;
#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
PBoolean 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;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -