📄 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.52 2000/06/21 01:01:22 robertj * AIX port, thanks Wolfgang Platzer (wolfgang.platzer@infonova.at). * * Revision 1.51 2000/04/19 00:13:53 robertj * BeOS port changes. * * Revision 1.50 2000/04/07 05:43:48 rogerh * Fix a compilation error in a non-pthreaded function. Found by Kevin Packard * * Revision 1.49 2000/03/17 03:45:40 craigs * Fixed problem with connect call hanging * * Revision 1.48 2000/02/17 23:47:40 robertj * Fixed error in check for SIOCGHWADDR define, thanks Markus Storm. * * Revision 1.47 2000/01/20 08:20:57 robertj * FreeBSD v3 compatibility changes, thanks Roger Hardiman & Motonori Shindo * * 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>#if defined(SIOCGENADDR)#define SIO_Get_MAC_Address SIOCGENADDR#define ifr_macaddr ifr_ifru.ifru_enaddr#elif defined(SIOCGIFHWADDR)#define SIO_Get_MAC_Address SIOCGIFHWADDR#define ifr_macaddr ifr_hwaddr.sa_data#endifPSocket::~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) {#ifndef __BEOS__#ifndef P_PTHREADS// non PThread unixes need non-blocking sockets DWORD cmd = 1; if (!ConvertOSError(::ioctl(handle, FIONBIO, &cmd)) || !ConvertOSError(::fcntl(handle, F_SETFD, 1))) { ::close(handle); return -1; }#endif // close socket on exec if (!ConvertOSError(::fcntl(handle, F_SETFD, 1))) { ::close(handle); return -1; }#endif // !__BEOS__ } return handle;}int PSocket::os_connect(struct sockaddr * addr, PINDEX size){ // need to use non-blocking form of connect, so we can abort it if it fails // but only if not in PThreads, as non-PThreads versions are already non-blocking#ifdef P_PTHREADS DWORD cmd = 1; if (!ConvertOSError(::ioctl(os_handle, FIONBIO, &cmd))) return -1;#endif int val = ::connect(os_handle, addr, size);#ifdef P_PTHREADS cmd = 0; if (!ConvertOSError(::ioctl(os_handle, FIONBIO, &cmd))) return -1;#endif if (val == 0) return 0; if (errno != EINPROGRESS) return -1; // use the os_select call, as that will be aborted by a thread close, whereas PXBlockOnIO cannot fd_set writeFds, emptyFds; FD_ZERO(&writeFds); FD_ZERO(&emptyFds); FD_SET(os_handle, &writeFds); PIntArray handles; handles.SetAt(0, os_handle); val = os_select(os_handle+1, emptyFds, writeFds, emptyFds, handles, writeTimeout); // 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, &optlen); 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, (socklen_t *)size);#endif}#ifndef P_PTHREADSint 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);} #elseint 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;}#endifPIPSocket::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__ // 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, (socklen_t *)addrlen))) return lastReadCount > 0; lastReadCount = 0; return FALSE;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -