📄 socket.cxx
字号:
/*
* socket.cxx
*
* Berkley sockets classes implementation
*
* 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): ______________________________________.
*
* $Log: socket.cxx,v $
* Revision 1.46 1999/11/18 13:45:21 craigs
* Removed obsolete declaration of iostream semaphore
*
* Revision 1.45 1999/10/30 13:43:01 craigs
* Added correct method of aborting socket operations asynchronously
*
* Revision 1.44 1999/09/27 01:04:42 robertj
* BeOS support changes.
*
* Revision 1.43 1999/09/12 07:06:23 craigs
* Added support for getting Solaris interface info
*
* Revision 1.42 1999/09/10 02:31:19 craigs
* Added interface table routines
*
* Revision 1.41 1999/09/03 02:26:25 robertj
* Changes to aid in breaking I/O locks on thread termination. Still needs more work esp in BSD!
*
* Revision 1.40 1999/05/01 03:52:20 robertj
* Fixed various egcs warnings.
*
* Revision 1.39 1999/03/02 05:41:59 robertj
* More BeOS changes
*
* Revision 1.38 1999/02/26 04:10:39 robertj
* More BeOS port changes
*
* Revision 1.37 1999/02/22 13:26:54 robertj
* BeOS port changes.
*
* Revision 1.36 1998/11/30 21:51:58 robertj
* New directory structure.
*
* Revision 1.35 1998/11/24 09:39:22 robertj
* FreeBSD port.
*
* Revision 1.34 1998/11/22 08:11:37 craigs
* *** empty log message ***
*
* Revision 1.33 1998/11/14 10:37:38 robertj
* Changed semantics of os_sendto to return TRUE if ANY bytes are sent.
*
* Revision 1.32 1998/10/16 01:16:55 craigs
* Added Yield to help with cooperative multithreading.
*
* Revision 1.31 1998/10/11 02:23:16 craigs
* Fixed problem with socket writes not correctly detecting EOF
*
* Revision 1.30 1998/09/24 08:21:11 robertj
* Fixed warning on GNU 6 library.
*
* Revision 1.29 1998/09/24 07:55:51 robertj
* Fixed warning on solaris build.
*
* Revision 1.28 1998/09/24 04:13:49 robertj
* Added open software license.
*
* Revision 1.27 1998/09/18 05:46:00 robertj
* Fixed incorrectly returning success on a connect() error other than a timeout.
*
* Revision 1.26 1998/09/08 11:31:51 robertj
* Fixed ippp bug on very full packets.
*
* Revision 1.25 1998/09/08 09:54:31 robertj
* Fixed ppp and ippp compatibility.
*
* Revision 1.24 1998/09/08 05:15:14 robertj
* Fixed problem in Windows requiring snmpapi.dll for PEthSocket class.
*
* Revision 1.23 1998/08/27 01:13:20 robertj
* Changes to resolve signedness in GNU C library v6
* Remove Linux EthSocket stuff from Sun build, still needs implementing.
*
* Revision 1.22 1998/08/21 05:30:59 robertj
* Ethernet socket implementation.
*
*/
#pragma implementation "sockets.h"
#pragma implementation "socket.h"
#pragma implementation "ipsock.h"
#pragma implementation "udpsock.h"
#pragma implementation "tcpsock.h"
#pragma implementation "ipdsock.h"
#pragma implementation "ethsock.h"
#include <ptlib.h>
#include <ptlib/sockets.h>
#ifdef SIOCGENADDR
#define SIO_Get_MAC_Address SIOCGENADDR
#define ifr_macaddr ifr_ifru.ifru_enaddr
#else
#define SIO_Get_MAC_Address SIOCGIFHWADDR
#define ifr_macaddr ifr_hwaddr.sa_data
#endif
PSocket::~PSocket()
{
os_close();
}
int PSocket::os_close()
{
if (os_handle < 0)
return -1;
// send a shutdown to the other end
::shutdown(os_handle, 2);
#ifdef __BEOS__
#ifndef BE_THREADS
// abort any I/O block using this os_handle
PProcess::Current().PXAbortIOBlock(os_handle);
#endif
int retval = ::closesocket(os_handle);
os_handle = -1;
return retval;
#else
return PXClose();
#endif
}
int PSocket::os_socket(int af, int type, int protocol)
{
// attempt to create a socket
int handle;
if ((handle = ::socket(af, type, protocol)) >= 0) {
return handle;
}
else
return -1;
}
int PSocket::os_connect(struct sockaddr * addr, PINDEX size)
{
int val = ::connect(os_handle, addr, size);
if (val == 0)
return 0;
if (errno != EINPROGRESS)
return -1;
// wait for the connect to occur, or not
val = PThread::Current()->PXBlockOnIO(os_handle, PXConnectBlock, readTimeout);
// check the response
if (val < 0)
return -1;
if (val == 0) {
errno = ECONNREFUSED;
return -1;
}
#ifndef __BEOS__
// A successful select() call does not necessarily mean the socket connected OK.
int optval = -1;
socklen_t optlen = sizeof(optval);
getsockopt(os_handle, SOL_SOCKET, SO_ERROR, (char *)&optval, (int *)(unsigned int *)&optlen); // casted by Jurjan
if (optval == 0)
return 0;
errno = optval;
#endif //!__BEOS__
return -1;
}
int PSocket::os_accept(int sock, struct sockaddr * addr, PINDEX * size,
const PTimeInterval & timeout)
{
if (!PXSetIOBlock(PXAcceptBlock, sock, timeout)) {
errno = EINTR;
return -1;
}
#if defined(E_PROTO)
while (1) {
int new_fd = ::accept(sock, addr, (socklen_t *)size);
if ((new_fd >= 0) || (errno != EPROTO))
return new_fd;
//PError << "accept on " << sock << " failed with EPROTO - retrying" << endl;
}
#else
return ::accept(sock, addr, (int *)(unsigned int *)(socklen_t *)size); // casted by Jurjan
#endif
}
#ifndef P_PTHREADS // VxWorks
int PSocket::os_select(int maxHandle,
fd_set & readBits,
fd_set & writeBits,
fd_set & exceptionBits,
const PIntArray & osHandles,
const PTimeInterval & timeout)
{
struct timeval * tptr = NULL;
int stat = PThread::Current()->PXBlockOnIO(maxHandle,
readBits,
writeBits,
exceptionBits,
timeout,
osHandles);
if (stat <= 0){
return stat;
}
struct timeval tout = {0, 0};
tptr = &tout;
return ::select(maxHandle, &readBits, &writeBits, &exceptionBits, tptr);
}
#else
int PSocket::os_select(int width,
fd_set & readBits,
fd_set & writeBits,
fd_set & exceptionBits,
const PIntArray & ,
const PTimeInterval & timeout)
{
struct timeval * tptr = NULL;
struct timeval timeout_val;
if (timeout != PMaxTimeInterval) {
if (timeout.GetMilliSeconds() < 1000L*60L*60L*24L) {
timeout_val.tv_usec = (timeout.GetMilliSeconds() % 1000) * 1000;
timeout_val.tv_sec = timeout.GetSeconds();
tptr = &timeout_val;
}
}
int termPipe = PThread::Current()->termPipe[0];
FD_SET(termPipe, &readBits);
width = PMAX(width, termPipe+1);
do {
int result = ::select(width, &readBits, &writeBits, &exceptionBits, tptr);
if (result >= 0) {
if (FD_ISSET(termPipe, &readBits)) {
FD_CLR(termPipe, &readBits);
if (result == 1) {
BYTE ch;
::read(termPipe, &ch, 1);
FD_CLR(termPipe, &readBits);
errno = EINTR;
return -1;
}
}
return result;
}
} while (errno == EINTR);
return -1;
}
#endif
PIPSocket::Address::Address(DWORD dw)
{
s_addr = dw;
}
PIPSocket::Address & PIPSocket::Address::operator=(DWORD dw)
{
s_addr = dw;
return *this;
}
PIPSocket::Address::operator DWORD() const
{
return (DWORD)s_addr;
}
BYTE PIPSocket::Address::Byte1() const
{
return *(((BYTE *)&s_addr)+0);
}
BYTE PIPSocket::Address::Byte2() const
{
return *(((BYTE *)&s_addr)+1);
}
BYTE PIPSocket::Address::Byte3() const
{
return *(((BYTE *)&s_addr)+2);
}
BYTE PIPSocket::Address::Byte4() const
{
return *(((BYTE *)&s_addr)+3);
}
PIPSocket::Address::Address(BYTE b1, BYTE b2, BYTE b3, BYTE b4)
{
BYTE * p = (BYTE *)&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 == 16777343) // Is 127.0.0.1
return TRUE;
if (addr == (DWORD)-1)
return FALSE;
if (!GetHostAddress(hostname, addr))
return FALSE;
PUDPSocket sock;
//#ifndef __BEOS__ // changed by Jurjan
#if !defined(__BEOS__) && !defined(P_VXWORKS)
// get number of interfaces
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;
}
}
}
}
#endif //!__BEOS__
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)) {
lastError = Timeout;
return FALSE;
}
#ifndef __BEOS__
// 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);
#endif // !__BEOS__
// attempt to read non-out of band data
if (ConvertOSError(lastReadCount = ::recv(os_handle, (char *)buf, maxLen, 0)))
return lastReadCount > 0;
lastReadCount = 0;
return FALSE;
}
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)
{
if (!PXSetIOBlock(PXReadBlock, readTimeout)) {
lastError = Timeout;
lastReadCount = 0;
return FALSE;
}
// attempt to read non-out of band data
if (ConvertOSError(lastReadCount =
::recvfrom(os_handle, (char *)buf, len, flags, (sockaddr *)addr, (int *)(unsigned int *)(socklen_t *)addrlen))) // casted by Jurjan
return lastReadCount > 0;
lastReadCount = 0;
return FALSE;
}
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()) {
lastError = NotOpen;
return FALSE;
}
// attempt to read data
int writeResult;
if (addr != NULL) {
writeResult = ::sendto(os_handle, (char *)buf, len, flags, (sockaddr *)addr, addrlen);
}
else
writeResult = ::send(os_handle, (char *)buf, len, flags);
if (writeResult > 0) {
PThread::Yield(); // gaat niet verder
lastWriteCount = writeResult;
return TRUE;
}
if (errno != EWOULDBLOCK)
return ConvertOSError(-1);
if (!PXSetIOBlock(PXWriteBlock, writeTimeout)) {
lastError = Timeout;
return FALSE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -