gsocket.cpp

来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 1,551 行 · 第 1/3 页

CPP
1,551
字号
/* -------------------------------------------------------------------------
 * Project:     GSocket (Generic Socket)
 * Name:        gsocket.cpp
 * Copyright:   (c) Guilhem Lavaux
 * Licence:     wxWindows Licence
 * Author:      Guillermo Rodriguez Garcia <guille@iies.es>
 * Purpose:     GSocket main MSW file
 * Licence:     The wxWindows licence
 * CVSID:       $Id: gsocket.cpp,v 1.18.2.1 2006/02/22 01:55:41 KH Exp $
 * -------------------------------------------------------------------------
 */

// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
    #pragma hdrstop
#endif

#ifdef _MSC_VER
   /* RPCNOTIFICATION_ROUTINE in rasasync.h (included from winsock.h),
    * warning: conditional expression is constant.
    */
#  pragma warning(disable:4115)
   /* FD_SET,
    * warning: named type definition in parentheses.
    */
#  pragma warning(disable:4127)
   /* GAddress_UNIX_GetPath,
    * warning: unreferenced formal parameter.
    */
#  pragma warning(disable:4100)

#ifdef __WXWINCE__
    /* windows.h results in tons of warnings at max warning level */
#   ifdef _MSC_VER
#       pragma warning(push, 1)
#   endif
#   include <windows.h>
#   ifdef _MSC_VER
#       pragma warning(pop)
#       pragma warning(disable:4514)
#   endif
#endif

#endif /* _MSC_VER */

#if defined(__CYGWIN__)
    //CYGWIN gives annoying warning about runtime stuff if we don't do this
#   define USE_SYS_TYPES_FD_SET
#   include <sys/types.h>
#endif

#include <winsock.h>

#ifndef __GSOCKET_STANDALONE__
#   include "wx/platform.h"
#   include "wx/setup.h"
#endif

#if wxUSE_SOCKETS || defined(__GSOCKET_STANDALONE__)

#ifndef __GSOCKET_STANDALONE__
#  include "wx/msw/gsockmsw.h"
#  include "wx/gsocket.h"
#else
#  include "gsockmsw.h"
#  include "gsocket.h"
#endif /* __GSOCKET_STANDALONE__ */

#ifndef __WXWINCE__
#include <assert.h>
#else
#define assert(x)
#ifndef isdigit
#define isdigit(x) (x > 47 && x < 58)
#endif
#include "wx/msw/wince/net.h"
#endif

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <ctype.h>

/* if we use configure for MSW WX_SOCKLEN_T will be already defined */
#ifndef WX_SOCKLEN_T
#  define WX_SOCKLEN_T int
#endif

/* Table of GUI-related functions. We must call them indirectly because
 * of wxBase and GUI separation: */

static GSocketGUIFunctionsTable *gs_gui_functions;

class GSocketGUIFunctionsTableNull: public GSocketGUIFunctionsTable
{
public:
    virtual bool OnInit();
    virtual void OnExit();
    virtual bool CanUseEventLoop();
    virtual bool Init_Socket(GSocket *socket);
    virtual void Destroy_Socket(GSocket *socket);
    virtual void Enable_Events(GSocket *socket);
    virtual void Disable_Events(GSocket *socket);
};

bool GSocketGUIFunctionsTableNull::OnInit()
{   return true; }
void GSocketGUIFunctionsTableNull::OnExit()
{}
bool GSocketGUIFunctionsTableNull::CanUseEventLoop()
{   return false; }
bool GSocketGUIFunctionsTableNull::Init_Socket(GSocket *WXUNUSED(socket))
{   return true; }
void GSocketGUIFunctionsTableNull::Destroy_Socket(GSocket *WXUNUSED(socket))
{}
void GSocketGUIFunctionsTableNull::Enable_Events(GSocket *WXUNUSED(socket))
{}
void GSocketGUIFunctionsTableNull::Disable_Events(GSocket *WXUNUSED(socket))
{}
/* Global initialisers */

void GSocket_SetGUIFunctions(GSocketGUIFunctionsTable *guifunc)
{
  gs_gui_functions = guifunc;
}

int GSocket_Init(void)
{
  WSADATA wsaData;

  if (!gs_gui_functions)
  {
    static GSocketGUIFunctionsTableNull table;
    gs_gui_functions = &table;
  }
  if ( !gs_gui_functions->OnInit() )
  {
    return 0;
  }

  /* Initialize WinSocket */
  return (WSAStartup((1 << 8) | 1, &wsaData) == 0);
}

void GSocket_Cleanup(void)
{
  if (gs_gui_functions)
  {
      gs_gui_functions->OnExit();
  }

  /* Cleanup WinSocket */
  WSACleanup();
}

/* Constructors / Destructors for GSocket */

GSocket::GSocket()
{
  int i;

  m_fd              = INVALID_SOCKET;
  for (i = 0; i < GSOCK_MAX_EVENT; i++)
  {
    m_cbacks[i]     = NULL;
  }
  m_detected        = 0;
  m_local           = NULL;
  m_peer            = NULL;
  m_error           = GSOCK_NOERROR;
  m_server          = false;
  m_stream          = true;
  m_non_blocking    = false;
  m_timeout.tv_sec  = 10 * 60;  /* 10 minutes */
  m_timeout.tv_usec = 0;
  m_establishing    = false;
  m_reusable        = false;

  assert(gs_gui_functions);
  /* Per-socket GUI-specific initialization */
  m_ok = gs_gui_functions->Init_Socket(this);
}

void GSocket::Close()
{
    gs_gui_functions->Disable_Events(this);
    closesocket(m_fd);
    m_fd = INVALID_SOCKET;
}

GSocket::~GSocket()
{
  assert(this);

  /* Per-socket GUI-specific cleanup */
  gs_gui_functions->Destroy_Socket(this);

  /* Check that the socket is really shutdowned */
  if (m_fd != INVALID_SOCKET)
    Shutdown();

  /* Destroy private addresses */
  if (m_local)
    GAddress_destroy(m_local);

  if (m_peer)
    GAddress_destroy(m_peer);
}

/* GSocket_Shutdown:
 *  Disallow further read/write operations on this socket, close
 *  the fd and disable all callbacks.
 */
void GSocket::Shutdown()
{
  int evt;

  assert(this);

  /* If socket has been created, shutdown it */
  if (m_fd != INVALID_SOCKET)
  {
    shutdown(m_fd, 2);
    Close();
  }

  /* Disable GUI callbacks */
  for (evt = 0; evt < GSOCK_MAX_EVENT; evt++)
    m_cbacks[evt] = NULL;

  m_detected = GSOCK_LOST_FLAG;
}

/* Address handling */

/* GSocket_SetLocal:
 * GSocket_GetLocal:
 * GSocket_SetPeer:
 * GSocket_GetPeer:
 *  Set or get the local or peer address for this socket. The 'set'
 *  functions return GSOCK_NOERROR on success, an error code otherwise.
 *  The 'get' functions return a pointer to a GAddress object on success,
 *  or NULL otherwise, in which case they set the error code of the
 *  corresponding GSocket.
 *
 *  Error codes:
 *    GSOCK_INVSOCK - the socket is not valid.
 *    GSOCK_INVADDR - the address is not valid.
 */
GSocketError GSocket::SetLocal(GAddress *address)
{
  assert(this);

  /* the socket must be initialized, or it must be a server */
  if (m_fd != INVALID_SOCKET && !m_server)
  {
    m_error = GSOCK_INVSOCK;
    return GSOCK_INVSOCK;
  }

  /* check address */
  if (address == NULL || address->m_family == GSOCK_NOFAMILY)
  {
    m_error = GSOCK_INVADDR;
    return GSOCK_INVADDR;
  }

  if (m_local)
    GAddress_destroy(m_local);

  m_local = GAddress_copy(address);

  return GSOCK_NOERROR;
}

GSocketError GSocket::SetPeer(GAddress *address)
{
  assert(this);

  /* check address */
  if (address == NULL || address->m_family == GSOCK_NOFAMILY)
  {
    m_error = GSOCK_INVADDR;
    return GSOCK_INVADDR;
  }

  if (m_peer)
    GAddress_destroy(m_peer);

  m_peer = GAddress_copy(address);

  return GSOCK_NOERROR;
}

GAddress *GSocket::GetLocal()
{
  GAddress *address;
  struct sockaddr addr;
  WX_SOCKLEN_T size = sizeof(addr);
  GSocketError err;

  assert(this);

  /* try to get it from the m_local var first */
  if (m_local)
    return GAddress_copy(m_local);

  /* else, if the socket is initialized, try getsockname */
  if (m_fd == INVALID_SOCKET)
  {
    m_error = GSOCK_INVSOCK;
    return NULL;
  }

  if (getsockname(m_fd, &addr, &size) == SOCKET_ERROR)
  {
    m_error = GSOCK_IOERR;
    return NULL;
  }

  /* got a valid address from getsockname, create a GAddress object */
  if ((address = GAddress_new()) == NULL)
  {
     m_error = GSOCK_MEMERR;
     return NULL;
  }

  if ((err = _GAddress_translate_from(address, &addr, size)) != GSOCK_NOERROR)
  {
     GAddress_destroy(address);
     m_error = err;
     return NULL;
  }

  return address;
}

GAddress *GSocket::GetPeer()
{
  assert(this);

  /* try to get it from the m_peer var */
  if (m_peer)
    return GAddress_copy(m_peer);

  return NULL;
}

/* Server specific parts */

/* GSocket_SetServer:
 *  Sets up this socket as a server. The local address must have been
 *  set with GSocket_SetLocal() before GSocket_SetServer() is called.
 *  Returns GSOCK_NOERROR on success, one of the following otherwise:
 *
 *  Error codes:
 *    GSOCK_INVSOCK - the socket is in use.
 *    GSOCK_INVADDR - the local address has not been set.
 *    GSOCK_IOERR   - low-level error.
 */
GSocketError GSocket::SetServer()
{
  u_long arg = 1;

  assert(this);

  /* must not be in use */
  if (m_fd != INVALID_SOCKET)
  {
    m_error = GSOCK_INVSOCK;
    return GSOCK_INVSOCK;
  }

  /* the local addr must have been set */
  if (!m_local)
  {
    m_error = GSOCK_INVADDR;
    return GSOCK_INVADDR;
  }

  /* Initialize all fields */
  m_server   = true;
  m_stream   = true;

  /* Create the socket */
  m_fd = socket(m_local->m_realfamily, SOCK_STREAM, 0);

  if (m_fd == INVALID_SOCKET)
  {
    m_error = GSOCK_IOERR;
    return GSOCK_IOERR;
  }

  ioctlsocket(m_fd, FIONBIO, (u_long FAR *) &arg);
  gs_gui_functions->Enable_Events(this);

  /* allow a socket to re-bind if the socket is in the TIME_WAIT
     state after being previously closed.
   */
  if (m_reusable) {
    setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, (const char*)&arg, sizeof(u_long));
  }

  /* Bind to the local address,
   * retrieve the actual address bound,
   * and listen up to 5 connections.
   */
  if ((bind(m_fd, m_local->m_addr, m_local->m_len) != 0) ||
      (getsockname(m_fd,
                   m_local->m_addr,
                   (WX_SOCKLEN_T *)&m_local->m_len) != 0) ||
      (listen(m_fd, 5) != 0))
  {
    Close();
    m_error = GSOCK_IOERR;
    return GSOCK_IOERR;
  }

  return GSOCK_NOERROR;
}

/* GSocket_WaitConnection:
 *  Waits for an incoming client connection. Returns a pointer to
 *  a GSocket object, or NULL if there was an error, in which case
 *  the last error field will be updated for the calling GSocket.
 *
 *  Error codes (set in the calling GSocket)
 *    GSOCK_INVSOCK    - the socket is not valid or not a server.
 *    GSOCK_TIMEDOUT   - timeout, no incoming connections.
 *    GSOCK_WOULDBLOCK - the call would block and the socket is nonblocking.
 *    GSOCK_MEMERR     - couldn't allocate memory.
 *    GSOCK_IOERR      - low-level error.
 */
GSocket *GSocket::WaitConnection()
{
  GSocket *connection;
  struct sockaddr from;
  WX_SOCKLEN_T fromlen = sizeof(from);
  GSocketError err;
  u_long arg = 1;

  assert(this);

  /* Reenable CONNECTION events */
  m_detected &= ~GSOCK_CONNECTION_FLAG;

  /* If the socket has already been created, we exit immediately */
  if (m_fd == INVALID_SOCKET || !m_server)
  {
    m_error = GSOCK_INVSOCK;
    return NULL;
  }

  /* Create a GSocket object for the new connection */
  connection = GSocket_new();

  if (!connection)
  {
    m_error = GSOCK_MEMERR;
    return NULL;
  }

  /* Wait for a connection (with timeout) */
  if (Input_Timeout() == GSOCK_TIMEDOUT)
  {
    delete connection;
    /* m_error set by _GSocket_Input_Timeout */
    return NULL;
  }

  connection->m_fd = accept(m_fd, &from, &fromlen);

  if (connection->m_fd == INVALID_SOCKET)
  {
    if (WSAGetLastError() == WSAEWOULDBLOCK)
      m_error = GSOCK_WOULDBLOCK;
    else
      m_error = GSOCK_IOERR;

    delete connection;
    return NULL;
  }

  /* Initialize all fields */
  connection->m_server   = false;
  connection->m_stream   = true;

  /* Setup the peer address field */
  connection->m_peer = GAddress_new();
  if (!connection->m_peer)
  {
    delete connection;
    m_error = GSOCK_MEMERR;
    return NULL;
  }
  err = _GAddress_translate_from(connection->m_peer, &from, fromlen);
  if (err != GSOCK_NOERROR)
  {
    GAddress_destroy(connection->m_peer);
    delete connection;
    m_error = err;
    return NULL;
  }

  ioctlsocket(connection->m_fd, FIONBIO, (u_long FAR *) &arg);
  gs_gui_functions->Enable_Events(connection);

  return connection;
}

/* GSocket_SetReusable:
*  Simply sets the m_resuable flag on the socket. GSocket_SetServer will
*  make the appropriate setsockopt() call.
*  Implemented as a GSocket function because clients (ie, wxSocketServer)

⌨️ 快捷键说明

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