📄 socket.cxx
字号:
PTRACE(3, "PWLib\tAccept on " << sock << " failed with EPROTO - retrying");
}
#else
return ConvertOSError(os_handle = SetNonBlocking(::accept(listener.GetHandle(), addr, (socklen_t *)size)));
#endif
}
#if !defined(P_PTHREADS) && !defined(P_MAC_MPTHREADS) && !defined(__BEOS__)
PChannel::Errors PSocket::Select(SelectList & read,
SelectList & write,
SelectList & except,
const PTimeInterval & timeout)
{
PINDEX i, j;
PINDEX nextfd = 0;
int maxfds = 0;
Errors lastError = NoError;
PThread * unblockThread = PThread::Current();
P_fd_set fds[3];
SelectList * list[3] = { &read, &write, &except };
for (i = 0; i < 3; i++) {
for (j = 0; j < list[i]->GetSize(); j++) {
PSocket & socket = (*list[i])[j];
if (!socket.IsOpen())
lastError = NotOpen;
else {
int h = socket.GetHandle();
fds[i] += h;
if (h > maxfds)
maxfds = h;
}
socket.px_selectMutex.Wait();
socket.px_selectThread = unblockThread;
}
}
if (lastError == NoError) {
P_timeval tval = timeout;
int result = ::select(maxfds+1,
(fd_set *)fds[0],
(fd_set *)fds[1],
(fd_set *)fds[2],
tval);
int osError;
(void)ConvertOSError(result, lastError, osError);
}
for (i = 0; i < 3; i++) {
for (j = 0; j < list[i]->GetSize(); j++) {
PSocket & socket = (*list[i])[j];
socket.px_selectThread = NULL;
socket.px_selectMutex.Signal();
if (lastError == NoError) {
int h = socket.GetHandle();
if (h < 0)
lastError = Interrupted;
else if (!fds[i].IsPresent(h))
list[i]->RemoveAt(j--);
}
}
}
return lastError;
}
#else
PChannel::Errors PSocket::Select(SelectList & read,
SelectList & write,
SelectList & except,
const PTimeInterval & timeout)
{
PINDEX i, j;
int maxfds = 0;
Errors lastError = NoError;
PThread * unblockThread = PThread::Current();
int unblockPipe = unblockThread->unblockPipe[0];
P_fd_set fds[3];
SelectList * list[3] = { &read, &write, &except };
for (i = 0; i < 3; i++) {
for (j = 0; j < list[i]->GetSize(); j++) {
PSocket & socket = (*list[i])[j];
if (!socket.IsOpen())
lastError = NotOpen;
else {
int h = socket.GetHandle();
fds[i] += h;
if (h > maxfds)
maxfds = h;
}
socket.px_selectMutex.Wait();
socket.px_selectThread = unblockThread;
}
}
int result = -1;
if (lastError == NoError) {
fds[0] += unblockPipe;
if (unblockPipe > maxfds)
maxfds = unblockPipe;
P_timeval tval = timeout;
do {
result = ::select(maxfds+1, (fd_set *)fds[0], (fd_set *)fds[1], (fd_set *)fds[2], tval);
} while (result < 0 && errno == EINTR);
int osError;
if (ConvertOSError(result, lastError, osError)) {
if (fds[0].IsPresent(unblockPipe)) {
PTRACE(6, "PWLib\tSelect unblocked fd=" << unblockPipe);
BYTE ch;
::read(unblockPipe, &ch, 1);
lastError = Interrupted;
}
}
}
for (i = 0; i < 3; i++) {
for (j = 0; j < list[i]->GetSize(); j++) {
PSocket & socket = (*list[i])[j];
socket.px_selectThread = NULL;
socket.px_selectMutex.Signal();
if (lastError == NoError) {
int h = socket.GetHandle();
if (h < 0)
lastError = Interrupted;
else if (!fds[i].IsPresent(h))
list[i]->RemoveAt(j--);
}
}
}
return lastError;
}
#endif
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_addr = dw;
}
return *this;
}
PIPSocket::Address::operator DWORD() const
{
return version != 4 ? 0 : (DWORD)v.four.s_addr;
}
BYTE PIPSocket::Address::Byte1() const
{
return *(((BYTE *)&v.four.s_addr)+0);
}
BYTE PIPSocket::Address::Byte2() const
{
return *(((BYTE *)&v.four.s_addr)+1);
}
BYTE PIPSocket::Address::Byte3() const
{
return *(((BYTE *)&v.four.s_addr)+2);
}
BYTE PIPSocket::Address::Byte4() const
{
return *(((BYTE *)&v.four.s_addr)+3);
}
PIPSocket::Address::Address(BYTE b1, BYTE b2, BYTE b3, BYTE b4)
{
version = 4;
BYTE * p = (BYTE *)&v.four.s_addr;
p[0] = b1;
p[1] = b2;
p[2] = b3;
p[3] = b4;
}
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
Address addr = hostname;
if (addr.IsLoopback()) // Is 127.0.0.1
return TRUE;
if (!addr.IsValid())
return FALSE;
if (!GetHostAddress(hostname, addr))
return FALSE;
#if P_HAS_IPV6
{
FILE * file;
int dummy;
int addr6[16];
char ifaceName[255];
BOOL found = FALSE;
if ((file = fopen("/proc/net/if_inet6", "r")) != NULL) {
while (!found && (fscanf(file, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x %x %x %x %x %255s\n",
&addr6[0], &addr6[1], &addr6[2], &addr6[3],
&addr6[4], &addr6[5], &addr6[6], &addr6[7],
&addr6[8], &addr6[9], &addr6[10], &addr6[11],
&addr6[12], &addr6[13], &addr6[14], &addr6[15],
&dummy, &dummy, &dummy, &dummy, ifaceName) != EOF)) {
Address ip6addr(
psprintf("%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
addr6[0], addr6[1], addr6[2], addr6[3],
addr6[4], addr6[5], addr6[6], addr6[7],
addr6[8], addr6[9], addr6[10], addr6[11],
addr6[12], addr6[13], addr6[14], addr6[15]
)
);
found = (ip6addr *= addr);
}
fclose(file);
}
if (found)
return TRUE;
}
#endif
PUDPSocket sock;
// check IPV4 addresses
int ifNum;
#ifdef SIOCGIFNUM
PAssert(::ioctl(sock.GetHandle(), SIOCGIFNUM, &ifNum) >= 0, "could not do ioctl for ifNum");
#else
ifNum = 100;
#endif
PBYTEArray buffer;
struct ifconf ifConf;
ifConf.ifc_len = ifNum * sizeof(ifreq);
ifConf.ifc_req = (struct ifreq *)buffer.GetPointer(ifConf.ifc_len);
if (ioctl(sock.GetHandle(), SIOCGIFCONF, &ifConf) >= 0) {
#ifndef SIOCGIFNUM
ifNum = ifConf.ifc_len / sizeof(ifreq);
#endif
int num = 0;
for (num = 0; num < ifNum; num++) {
ifreq * ifName = ifConf.ifc_req + num;
struct ifreq ifReq;
strcpy(ifReq.ifr_name, ifName->ifr_name);
if (ioctl(sock.GetHandle(), SIOCGIFFLAGS, &ifReq) >= 0) {
int flags = ifReq.ifr_flags;
if (ioctl(sock.GetHandle(), SIOCGIFADDR, &ifReq) >= 0) {
if ((flags & IFF_UP) && (addr *= Address(((sockaddr_in *)&ifReq.ifr_addr)->sin_addr)))
return TRUE;
}
}
}
}
return FALSE;
}
////////////////////////////////////////////////////////////////
//
// PTCPSocket
//
BOOL PTCPSocket::Read(void * buf, PINDEX maxLen)
{
lastReadCount = 0;
// wait until select indicates there is data to read, or until
// a timeout occurs
if (!PXSetIOBlock(PXReadBlock, readTimeout))
return FALSE;
// attempt to read out of band data
char buffer[32];
int ooblen;
while ((ooblen = ::recv(os_handle, buffer, sizeof(buffer), MSG_OOB)) > 0)
OnOutOfBand(buffer, ooblen);
// attempt to read non-out of band data
int r = ::recv(os_handle, (char *)buf, maxLen, 0);
if (!ConvertOSError(r, LastReadError))
return FALSE;
lastReadCount = r;
return lastReadCount > 0;
}
#if P_HAS_RECVMSG
int PSocket::os_recvfrom(
void * buf, // Data to be written as URGENT TCP data.
PINDEX len, // Number of bytes pointed to by <CODE>buf</CODE>.
int flags,
sockaddr * addr, // Address from which the datagram was received.
PINDEX * addrlen)
{
lastReadCount = 0;
if (!PXSetIOBlock(PXReadBlock, readTimeout))
return FALSE;
// if we don't care what interface the packet arrives on, then don't bother getting the information
if (!catchReceiveToAddr) {
int r = ::recvfrom(os_handle, (char *)buf, len, flags, (sockaddr *)addr, (socklen_t *)addrlen);
if (!ConvertOSError(r, LastReadError))
return FALSE;
lastReadCount = r;
return lastReadCount > 0;
}
msghdr readData;
memset(&readData, 0, sizeof(readData));
readData.msg_name = addr;
readData.msg_namelen = *addrlen;
iovec readVector;
readVector.iov_base = buf;
readVector.iov_len = len;
readData.msg_iov = &readVector;
readData.msg_iovlen = 1;
char auxdata[50];
readData.msg_control = auxdata;
readData.msg_controllen = sizeof(auxdata);
// read a packet
int r = ::recvmsg(os_handle, &readData, 0);
if (!ConvertOSError(r, LastReadError))
return FALSE;
lastReadCount = r;
if (r >= 0) {
struct cmsghdr * cmsg;
for (cmsg = CMSG_FIRSTHDR(&readData); cmsg != NULL; cmsg = CMSG_NXTHDR(&readData,cmsg)) {
if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_PKTINFO) {
in_pktinfo * info = (in_pktinfo *)CMSG_DATA(cmsg);
SetLastReceiveAddr(&info->ipi_spec_dst, sizeof(in_addr));
break;
}
}
}
return lastReadCount > 0;
}
#else
BOOL PSocket::os_recvfrom(
void * buf, // Data to be written as URGENT TCP data.
PINDEX len, // Number of bytes pointed to by <CODE>buf</CODE>.
int flags,
sockaddr * addr, // Address from which the datagram was received.
PINDEX * addrlen)
{
lastReadCount = 0;
if (!PXSetIOBlock(PXReadBlock, readTimeout))
return FALSE;
// attempt to read non-out of band data
int r = ::recvfrom(os_handle, (char *)buf, len, flags, (sockaddr *)addr, (socklen_t *)addrlen);
if (!ConvertOSError(r, LastReadError))
return FALSE;
lastReadCount = r;
return lastReadCount > 0;
}
#endif
BOOL PSocket::os_sendto(
const void * buf, // Data to be written as URGENT TCP data.
PINDEX len, // Number of bytes pointed to by <CODE>buf</CODE>.
int flags,
sockaddr * addr, // Address to which the datagram is sent.
PINDEX addrlen)
{
lastWriteCount = 0;
if (!IsOpen())
return SetErrorValues(NotOpen, EBADF, LastWriteError);
// attempt to read data
int result;
for (;;) {
if (addr != NULL)
result = ::sendto(os_handle, (char *)buf, len, flags, (sockaddr *)addr, addrlen);
else
result = ::send(os_handle, (char *)buf, len, flags);
if (result > 0)
break;
if (errno != EWOULDBLOCK)
return ConvertOSError(-1, LastWriteError);
if (!PXSetIOBlock(PXWriteBlock, writeTimeout))
return FALSE;
}
#if !defined(P_PTHREADS) && !defined(P_MAC_MPTHREADS)
PThread::Yield(); // Starvation prevention
#endif
lastWriteCount = result;
return ConvertOSError(0, LastWriteError);
}
BOOL PSocket::Read(void * buf, PINDEX len)
{
if (os_handle < 0)
return SetErrorValues(NotOpen, EBADF, LastReadError);
if (!PXSetIOBlock(PXReadBlock, readTimeout))
return FALSE;
if (ConvertOSError(lastReadCount = ::recv(os_handle, (char *)buf, len, 0)))
return lastReadCount > 0;
lastReadCount = 0;
return FALSE;
}
//////////////////////////////////////////////////////////////////
//
// PEthSocket
//
PEthSocket::PEthSocket(PINDEX, PINDEX, PINDEX)
{
medium = MediumUnknown;
filterMask = FilterDirected|FilterBroadcast;
filterType = TypeAll;
fakeMacHeader = FALSE;
ipppInterface = FALSE;
}
PEthSocket::~PEthSocket()
{
Close();
}
BOOL PEthSocket::Connect(const PString & interfaceName)
{
Close();
fakeMacHeader = FALSE;
ipppInterface = FALSE;
if (strncmp("eth", interfaceName, 3) == 0)
medium = Medium802_3;
else if (strncmp("lo", interfaceName, 2) == 0)
medium = MediumLoop;
else if (strncmp("sl", interfaceName, 2) == 0) {
medium = MediumWan;
fakeMacHeader = TRUE;
}
else if (strncmp("ppp", interfaceName, 3) == 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -