⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 socket.cxx

📁 opal的ptlib c++源程序 可以从官方网站上下载
💻 CXX
📖 第 1 页 / 共 3 页
字号:
/*
 * 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): ______________________________________.
 *
 * $Revision: 19008 $
 * $Author: rjongbloed $
 * $Date: 2007-11-29 09:17:41 +0000 (Thu, 29 Nov 2007) $
 */

#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"
#pragma implementation "qos.h"


#include <ptlib.h>
#include <ptlib/sockets.h>

#include <map>
#include <ptlib/pstring.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
#endif

#if defined(P_FREEBSD) || defined(P_OPENBSD) || defined(P_NETBSD) || defined(P_SOLARIS) || defined(P_MACOSX) || defined(P_MACOS) || defined(P_IRIX) || defined(P_VXWORKS) || defined(P_RTEMS) || defined(P_QNX)
#define ifr_netmask ifr_addr

#include <net/if_dl.h>
#include <net/if_types.h>
#include <net/route.h>

#include <netinet/in.h>
#if !defined(P_QNX)
#include <netinet/if_ether.h>
#endif

#define ROUNDUP(a) \
        ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))

#endif

#if defined(P_FREEBSD) || defined(P_OPENBSD) || defined(P_NETBSD) || defined(P_MACOSX) || defined(P_MACOS) || defined(P_QNX)
#include <sys/sysctl.h>
#endif

#ifdef P_RTEMS
#include <bsp.h>
#endif

#ifdef __BEOS__
#include <posix/sys/ioctl.h> // for FIONBIO
#include <be/bone/net/if.h> // for ifconf
#include <be/bone/sys/sockio.h> // for SIOCGI*
#endif

#if defined(P_FREEBSD) || defined(P_OPENBSD) || defined(P_NETBSD) || defined(P_MACOSX) || defined(P_VXWORKS) || defined(P_RTEMS) || defined(P_QNX)
// Define _SIZEOF_IFREQ for platforms (eg OpenBSD) which do not have it.
#ifndef _SIZEOF_ADDR_IFREQ
#define _SIZEOF_ADDR_IFREQ(ifr) \
  ((ifr).ifr_addr.sa_len > sizeof(struct sockaddr) ? \
  (sizeof(struct ifreq) - sizeof(struct sockaddr) + \
  (ifr).ifr_addr.sa_len) : sizeof(struct ifreq))
#endif
#endif

int PX_NewHandle(const char *, int);

#ifdef P_VXWORKS
// VxWorks variant of inet_ntoa() allocates INET_ADDR_LEN bytes via malloc
// BUT DOES NOT FREE IT !!!  Use inet_ntoa_b() instead.
#define INET_ADDR_LEN      18
extern "C" void inet_ntoa_b(struct in_addr inetAddress, char *pString);
#endif // P_VXWORKS

//////////////////////////////////////////////////////////////////////////////
// P_fd_set

void P_fd_set::Construct()
{
  max_fd = PProcess::Current().GetMaxHandles();
  set = (fd_set *)malloc((max_fd+7)>>3);
}


void P_fd_set::Zero()
{
  if (PAssertNULL(set) != NULL)
    memset(set, 0, (max_fd+7)>>3);
}


//////////////////////////////////////////////////////////////////////////////

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);

  return PXClose();
}


static int SetNonBlocking(int fd)
{
  if (fd < 0)
    return -1;

  // Set non-blocking so we can use select calls to break I/O block on close
  int cmd = 1;
#if defined(P_VXWORKS)
  if (::ioctl(fd, FIONBIO, &cmd) == 0)
#else
  if (::ioctl(fd, FIONBIO, &cmd) == 0 && ::fcntl(fd, F_SETFD, 1) == 0)
#endif
    return fd;

  ::close(fd);
  return -1;
}


int PSocket::os_socket(int af, int type, int protocol)
{
  // attempt to create a socket
  return SetNonBlocking(PX_NewHandle(GetClass(), ::socket(af, type, protocol)));
}


PBoolean PSocket::os_connect(struct sockaddr * addr, PINDEX size)
{
  int val;
  do {
    val = ::connect(os_handle, addr, size);
  } while (val != 0 && errno == EINTR);
  if (val == 0 || errno != EINPROGRESS)
    return ConvertOSError(val);

  if (!PXSetIOBlock(PXConnectBlock, readTimeout))
    return PFalse;

  // 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) {
    errno = optval;
    return ConvertOSError(-1);
  }

  return PTrue;
}


PBoolean PSocket::os_accept(PSocket & listener, struct sockaddr * addr, PINDEX * size)
{
  if (!listener.PXSetIOBlock(PXAcceptBlock, listener.GetReadTimeout()))
    return SetErrorValues(listener.GetErrorCode(), listener.GetErrorNumber());

#if defined(E_PROTO)
  for (;;) {
    int new_fd = ::accept(listener.GetHandle(), addr, (socklen_t *)size);
    if (new_fd >= 0)
      return ConvertOSError(os_handle = SetNonBlocking(new_fd));

    if (errno != EPROTO)
      return ConvertOSError(-1);

    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[i].Wait();
      socket.px_selectThread[i] = 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[i] = NULL;
      socket.px_selectMutex[i].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[i].Wait();
      socket.px_selectThread[i] = 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[i] = NULL;
      socket.px_selectMutex[i].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;
}

PBoolean PIPSocket::IsLocalHost(const PString & hostname)
{
  if (hostname.IsEmpty())
    return PTrue;

  if (hostname *= "localhost")
    return PTrue;

  // lookup the host address using inet_addr, assuming it is a "." address
  Address addr = hostname;
  if (addr.IsLoopback())  // Is 127.0.0.1
    return PTrue;
  if (!addr.IsValid())
    return PFalse;

  if (!GetHostAddress(hostname, addr))
    return PFalse;

#if P_HAS_IPV6
  {
    FILE * file;
    int dummy;
    int addr6[16];
    char ifaceName[255];
    PBoolean found = PFalse;
    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 PTrue;
  }
#endif

  // check IPV4 addresses
  PUDPSocket sock;
  
  PBYTEArray buffer;
  struct ifconf ifConf;

#ifdef SIOCGIFNUM
  int ifNum;
  PAssert(::ioctl(sock.GetHandle(), SIOCGIFNUM, &ifNum) >= 0, "could not do ioctl for ifNum");
  ifConf.ifc_len = ifNum * sizeof(ifreq);
#else
  ifConf.ifc_len = 100 * sizeof(ifreq); // That's a LOT of interfaces!
#endif

  ifConf.ifc_req = (struct ifreq *)buffer.GetPointer(ifConf.ifc_len);
  
  if (ioctl(sock.GetHandle(), SIOCGIFCONF, &ifConf) >= 0) {
    void * ifEndList = (char *)ifConf.ifc_req + ifConf.ifc_len;
    ifreq * ifName = ifConf.ifc_req;

    while (ifName < ifEndList) {
      struct ifreq ifReq;
      memcpy(&ifReq, ifName, sizeof(ifreq));
      
      if (ioctl(sock.GetHandle(), SIOCGIFFLAGS, &ifReq) >= 0) {
        int flags = ifReq.ifr_flags;
        if ((flags & IFF_UP) && ioctl(sock.GetHandle(), SIOCGIFADDR, &ifReq) >= 0) {
          sockaddr_in * sin = (sockaddr_in *)&ifReq.ifr_addr;
          PIPSocket::Address address = sin->sin_addr;
          if (addr *= address)
            return PTrue;
        }
      }
      
#if defined(P_FREEBSD) || defined(P_OPENBSD) || defined(P_NETBSD) || defined(P_MACOSX) || defined(P_VXWORKS) || defined(P_RTEMS) || defined(P_QNX)
      // move the ifName pointer along to the next ifreq entry
      ifName = (struct ifreq *)((char *)ifName + _SIZEOF_ADDR_IFREQ(*ifName));
#else
      ifName++;
#endif
    }
  }
  
  return PFalse;
}


////////////////////////////////////////////////////////////////
//
//  PTCPSocket
//
PBoolean 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 PFalse;

  // 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 PFalse;

  lastReadCount = r;
  return lastReadCount > 0;
}


#if P_HAS_RECVMSG

PBoolean 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 PFalse;

  // 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 PFalse;

    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;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -