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 + -
显示快捷键?