mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2024-12-27 09:58:45 +01:00
Beginning of rewrite of socket code for communication with relay,
replacing dedicated threads for read and write with non-blocking sockets driven from the main window proc. So far it can do a round-trip against the relay on win32, and compiles but isn't tested on wince.
This commit is contained in:
parent
50bd5e875b
commit
95a93191be
5 changed files with 359 additions and 125 deletions
|
@ -52,7 +52,8 @@ messageToStr( UINT message )
|
|||
CASE_STR( WM_TIMER );
|
||||
CASE_STR( WM_DESTROY );
|
||||
CASE_STR( XWWM_TIME_RQST );
|
||||
CASE_STR( XWWM_PACKET_ARRIVED );
|
||||
CASE_STR( XWWM_HOSTNAME_ARRIVED );
|
||||
CASE_STR( XWWM_SOCKET_EVT );
|
||||
CASE_STR( WM_DRAWITEM );
|
||||
CASE_STR( WM_NEXTDLGCTL );
|
||||
CASE_STR( WM_CTLCOLORSTATIC );
|
||||
|
|
|
@ -54,6 +54,7 @@
|
|||
#include "cesvdgms.h"
|
||||
#include "cedraw.h"
|
||||
#include "cesms.h"
|
||||
#include "cesockwr.h"
|
||||
|
||||
#include "dbgutil.h"
|
||||
|
||||
|
@ -862,15 +863,19 @@ ceInitAndStartBoard( CEAppGlobals* globals, XP_Bool newGame,
|
|||
board_invalAll( globals->game.board );
|
||||
InvalidateRect( globals->hWnd, NULL, TRUE /* erase */ );
|
||||
|
||||
#ifdef XWFEATURE_RELAY
|
||||
if ( newGame && globals->gameInfo.serverRole == SERVER_ISCLIENT ) {
|
||||
XWStreamCtxt* stream;
|
||||
XP_ASSERT( !!globals->game.comms );
|
||||
stream = make_generic_stream( globals );
|
||||
stream_setOnCloseProc( stream, ce_send_on_close );
|
||||
server_initClientConnection( globals->game.server, stream );
|
||||
/* #ifdef XWFEATURE_RELAY */
|
||||
/* if ( newGame && globals->gameInfo.serverRole == SERVER_ISCLIENT ) { */
|
||||
/* XWStreamCtxt* stream; */
|
||||
/* XP_ASSERT( !!globals->game.comms ); */
|
||||
/* stream = make_generic_stream( globals ); */
|
||||
/* stream_setOnCloseProc( stream, ce_send_on_close ); */
|
||||
/* server_initClientConnection( globals->game.server, stream ); */
|
||||
/* } */
|
||||
/* #endif */
|
||||
|
||||
if ( !!globals->game.comms ) {
|
||||
comms_start( globals->game.comms );
|
||||
}
|
||||
#endif
|
||||
|
||||
ceSetLeftSoftkey( globals, ID_MOVE_TURNDONE );
|
||||
|
||||
|
@ -1861,6 +1866,9 @@ ceSaveAndExit( CEAppGlobals* globals )
|
|||
{
|
||||
(void)ceSaveCurGame( globals, XP_TRUE );
|
||||
ceSavePrefs( globals );
|
||||
if ( !!globals->socketWrap ) {
|
||||
ce_sockwrap_delete( globals->socketWrap );
|
||||
}
|
||||
DestroyWindow(globals->hWnd);
|
||||
} /* ceSaveAndExit */
|
||||
|
||||
|
@ -2025,25 +2033,6 @@ checkFireLateKeyTimer( CEAppGlobals* globals )
|
|||
return drop;
|
||||
} /* checkFireLateKeyTimer */
|
||||
|
||||
#ifndef XWFEATURE_STANDALONE_ONLY
|
||||
static XP_Bool
|
||||
processPacket( CEAppGlobals* globals, XWStreamCtxt* instream )
|
||||
{
|
||||
XP_Bool draw = XP_FALSE;
|
||||
|
||||
XP_ASSERT( globals->game.comms != NULL );
|
||||
|
||||
if ( comms_checkIncomingStream( globals->game.comms,
|
||||
instream, NULL ) ) {
|
||||
draw = server_receiveMessage( globals->game.server, instream );
|
||||
}
|
||||
stream_destroy( instream );
|
||||
ce_util_requestTime( &globals->util );
|
||||
|
||||
return draw;
|
||||
} /* processPacket */
|
||||
#endif
|
||||
|
||||
static XP_Bool
|
||||
checkPenDown( CEAppGlobals* globals )
|
||||
{
|
||||
|
@ -2551,8 +2540,12 @@ WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|||
break;
|
||||
|
||||
#ifndef XWFEATURE_STANDALONE_ONLY
|
||||
case XWWM_PACKET_ARRIVED:
|
||||
draw = processPacket( globals, (XWStreamCtxt*)lParam );
|
||||
case XWWM_HOSTNAME_ARRIVED:
|
||||
ce_sockwrap_hostname( globals->socketWrap, wParam, lParam );
|
||||
break;
|
||||
|
||||
case XWWM_SOCKET_EVT:
|
||||
draw = ce_sockwrap_event( globals->socketWrap, wParam, lParam );
|
||||
break;
|
||||
#endif
|
||||
|
||||
|
@ -2824,22 +2817,24 @@ wince_snprintf( XP_UCHAR* buf, XP_U16 len, const XP_UCHAR* format, ... )
|
|||
} /* wince_snprintf */
|
||||
|
||||
#if defined XWFEATURE_RELAY || defined XWFEATURE_BLUETOOTH
|
||||
static void
|
||||
static XP_Bool
|
||||
got_data_proc( XP_U8* data, XP_U16 len, void* closure )
|
||||
{
|
||||
/* Remember that this gets called by the reader thread, not by the one
|
||||
running the window loop. */
|
||||
CEAppGlobals* globals = (CEAppGlobals*)closure;
|
||||
BOOL posted;
|
||||
XWStreamCtxt* stream;
|
||||
XP_Bool draw;
|
||||
|
||||
stream = make_generic_stream( globals );
|
||||
stream_putBytes( stream, data, len );
|
||||
|
||||
assertOnTop( globals->hWnd );
|
||||
posted = PostMessage( globals->hWnd, XWWM_PACKET_ARRIVED,
|
||||
0, (DWORD)stream );
|
||||
XP_ASSERT( posted );
|
||||
XP_ASSERT( !!globals->game.comms );
|
||||
if ( comms_checkIncomingStream( globals->game.comms, stream, NULL ) ) {
|
||||
draw = server_receiveMessage( globals->game.server, stream );
|
||||
}
|
||||
stream_destroy( stream );
|
||||
ce_util_requestTime( &globals->util );
|
||||
|
||||
return draw;
|
||||
} /* got_data_proc */
|
||||
#endif
|
||||
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
#include "game.h"
|
||||
#include "util.h"
|
||||
#include "mempool.h"
|
||||
#include "cesockwr.h"
|
||||
|
||||
#define LCROSSWORDS_DIR_NODBG L"Crosswords"
|
||||
#define CE_GAMEFILE_VERSION1 0x01 /* means draw gets to save/restore */
|
||||
|
@ -110,7 +109,7 @@ enum {
|
|||
N_CACHED_PATHS
|
||||
};
|
||||
|
||||
typedef struct CEAppGlobals {
|
||||
typedef struct _CEAppGlobals {
|
||||
HINSTANCE hInst;
|
||||
HDC hdc; /* to pass drawing ctxt to draw code */
|
||||
HWND hWnd;
|
||||
|
@ -158,7 +157,7 @@ typedef struct CEAppGlobals {
|
|||
#ifdef KEYBOARD_NAV
|
||||
XP_Bool keyDown;
|
||||
#endif
|
||||
CeSocketWrapper* socketWrap;
|
||||
struct CeSocketWrapper* socketWrap;
|
||||
|
||||
CEAppPrefs appPrefs;
|
||||
|
||||
|
@ -188,8 +187,8 @@ typedef struct CEAppGlobals {
|
|||
enum {
|
||||
XWWM_TIME_RQST = WM_APP
|
||||
,XWWM_REM_SEL
|
||||
,XWWM_PACKET_ARRIVED
|
||||
|
||||
,XWWM_HOSTNAME_ARRIVED
|
||||
,XWWM_SOCKET_EVT
|
||||
};
|
||||
|
||||
#define CE_NUM_EDITABLE_COLORS CE_BLACK_COLOR
|
||||
|
|
394
wince/cesockwr.c
394
wince/cesockwr.c
|
@ -1,4 +1,4 @@
|
|||
/* -*-mode: C; fill-column: 77; c-basic-offset: 4; -*- */
|
||||
/* -*- compile-command: "make -j TARGET_OS=win32 DEBUG=TRUE" -*- */
|
||||
/*
|
||||
* Copyright 2005-2009 by Eric House (xwords@eehouse.org). All rights
|
||||
* reserved.
|
||||
|
@ -19,12 +19,14 @@
|
|||
*/
|
||||
#ifndef XWFEATURE_STANDALONE_ONLY
|
||||
|
||||
#include <winsock2.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "cesockwr.h"
|
||||
#include "cemain.h"
|
||||
#include "cedebug.h"
|
||||
#include "debhacks.h"
|
||||
|
||||
#include <winsock.h>
|
||||
|
||||
/* This object owns all network activity: sending and receiving packets. It
|
||||
maintains two threads, one to send and the other to listen. Incoming
|
||||
|
@ -39,31 +41,41 @@ enum { WRITER_THREAD,
|
|||
N_THREADS };
|
||||
|
||||
typedef enum {
|
||||
CE_IP_NONE, /* shouldn't be used */
|
||||
CE_IP_UNCONNECTED,
|
||||
CE_IP_CONNECTED
|
||||
} CE_CONNSTATE;
|
||||
CE_IPST_START
|
||||
,CE_IPST_RESOLVINGHOST
|
||||
,CE_IPST_HOSTRESOLVED
|
||||
,CE_IPST_CONNECTING
|
||||
,CE_IPST_CONNECTED
|
||||
} CeConnState;
|
||||
|
||||
#define MAX_QUEUE_SIZE 3
|
||||
|
||||
struct CeSocketWrapper {
|
||||
struct CeSocketWrapper {
|
||||
WSADATA wsaData;
|
||||
DataRecvProc dataProc;
|
||||
void* dataClosure;
|
||||
CEAppGlobals* globals;
|
||||
|
||||
union {
|
||||
HOSTENT hent;
|
||||
XP_U8 hostNameBuf[MAXGETHOSTSTRUCT];
|
||||
} hostNameUnion;
|
||||
HANDLE getHostTask;
|
||||
|
||||
/* Outgoing queue */
|
||||
XP_U8* packets[MAX_QUEUE_SIZE];
|
||||
XP_U16 lens[MAX_QUEUE_SIZE];
|
||||
XP_U16 nPackets;
|
||||
|
||||
/* Incoming */
|
||||
char in_buf[512]; /* char is what WSARecv wants */
|
||||
XP_U16 in_offset;
|
||||
|
||||
CommsAddrRec addrRec;
|
||||
|
||||
SOCKET socket;
|
||||
CE_CONNSTATE connState;
|
||||
|
||||
HANDLE queueAddEvent;
|
||||
HANDLE socketConnEvent;
|
||||
CeConnState connState;
|
||||
|
||||
HANDLE queueMutex;
|
||||
HANDLE threads[N_THREADS];
|
||||
|
||||
#ifdef DEBUG
|
||||
XP_U16 nSent;
|
||||
|
@ -72,6 +84,28 @@ typedef enum {
|
|||
MPSLOT
|
||||
};
|
||||
|
||||
#ifdef DEBUG
|
||||
static const char*
|
||||
ConnState2Str( CeConnState connState )
|
||||
{
|
||||
#define CASESTR(s) case (s): return #s
|
||||
switch( connState ) {
|
||||
CASESTR( CE_IPST_START );
|
||||
CASESTR( CE_IPST_RESOLVINGHOST );
|
||||
CASESTR( CE_IPST_HOSTRESOLVED );
|
||||
CASESTR( CE_IPST_CONNECTING );
|
||||
CASESTR( CE_IPST_CONNECTED );
|
||||
}
|
||||
#undef CASESTR
|
||||
return "<unknown>";
|
||||
}
|
||||
#else
|
||||
# define ConnState2Str(s)
|
||||
#endif
|
||||
|
||||
static XP_Bool connectIfNot( CeSocketWrapper* self );
|
||||
|
||||
|
||||
/* queue_packet: Place packet on queue using semaphore. Return false
|
||||
* if no room or fail for some other reason.
|
||||
*/
|
||||
|
@ -96,8 +130,9 @@ queue_packet( CeSocketWrapper* self, XP_U8* packet, XP_U16 len )
|
|||
__func__, self->nPackets );
|
||||
|
||||
/* signal the writer thread */
|
||||
SetEvent( self->queueAddEvent );
|
||||
success = XP_TRUE;
|
||||
/* XP_LOGF( "%s: calling SetEvent(%p)", __func__, self->queueAddEvent ); */
|
||||
/* SetEvent( self->queueAddEvent ); */
|
||||
/* success = XP_TRUE; */
|
||||
}
|
||||
|
||||
if ( !ReleaseMutex( self->queueMutex ) ) {
|
||||
|
@ -184,62 +219,99 @@ sendLenAndData( CeSocketWrapper* self, XP_U8* packet, XP_U16 len )
|
|||
return success;
|
||||
} /* sendLenAndData */
|
||||
|
||||
static void
|
||||
send_packet_if( CeSocketWrapper* self )
|
||||
{
|
||||
XP_U8* packet;
|
||||
XP_U16 len;
|
||||
if ( get_packet( self, &packet, &len ) ) {
|
||||
if ( sendLenAndData( self, packet, len ) ) {
|
||||
/* successful send. Remove our copy */
|
||||
remove_packet( self );
|
||||
XP_FREE( self->mpool, packet );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
stateChanged( CeSocketWrapper* self, CeConnState newState )
|
||||
{
|
||||
CeConnState curState = self->connState;
|
||||
self->connState = newState;
|
||||
|
||||
XP_LOGF( "%s: %s -> %s", __func__, ConnState2Str( curState ),
|
||||
ConnState2Str( newState ) );
|
||||
|
||||
switch( newState ) {
|
||||
case CE_IPST_START:
|
||||
break;
|
||||
case CE_IPST_RESOLVINGHOST:
|
||||
break;
|
||||
case CE_IPST_HOSTRESOLVED:
|
||||
connectIfNot( self );
|
||||
break;
|
||||
case CE_IPST_CONNECTING:
|
||||
break;
|
||||
case CE_IPST_CONNECTED:
|
||||
send_packet_if( self );
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static XP_Bool
|
||||
connectSocket( CeSocketWrapper* self )
|
||||
{
|
||||
SOCKET sock;
|
||||
|
||||
/* first look up the ip address */
|
||||
if ( self->addrRec.u.ip_relay.ipAddr == 0 ) {
|
||||
struct hostent* ent;
|
||||
ent = MS(gethostbyname)( self->addrRec.u.ip_relay.hostName );
|
||||
if ( ent != NULL ) {
|
||||
XP_U32 tmp;
|
||||
XP_MEMCPY( &tmp, &ent->h_addr_list[0][0],
|
||||
sizeof(self->addrRec.u.ip_relay.ipAddr) );
|
||||
self->addrRec.u.ip_relay.ipAddr = XP_NTOHL( tmp );
|
||||
} else {
|
||||
logLastError( "gethostbyname" );
|
||||
}
|
||||
}
|
||||
|
||||
if ( self->addrRec.u.ip_relay.ipAddr != 0 ) {
|
||||
sock = MS(socket)( AF_INET, SOCK_STREAM, IPPROTO_IP );
|
||||
sock = WSASocket( AF_INET, SOCK_STREAM, IPPROTO_IP,
|
||||
NULL, 0, WSA_FLAG_OVERLAPPED );
|
||||
XP_LOGF( "got socket %d", sock );
|
||||
|
||||
if ( sock != INVALID_SOCKET ) {
|
||||
struct sockaddr_in name;
|
||||
struct sockaddr_in name = {0};
|
||||
|
||||
/* Put socket in non-blocking mode */
|
||||
if ( 0 != WSAAsyncSelect( sock, self->globals->hWnd,
|
||||
XWWM_SOCKET_EVT,
|
||||
FD_READ | FD_WRITE | FD_CONNECT ) ) {
|
||||
XP_WARNF( "WSAAsyncSelect failed" );
|
||||
}
|
||||
|
||||
name.sin_family = AF_INET;
|
||||
name.sin_port = XP_HTONS( self->addrRec.u.ip_relay.port );
|
||||
name.sin_addr.S_un.S_addr = XP_HTONL(self->addrRec.u.ip_relay.ipAddr);
|
||||
|
||||
if ( SOCKET_ERROR != MS(connect)( sock, (struct sockaddr *)&name,
|
||||
sizeof(name) ) ) {
|
||||
self->connState = CE_IP_CONNECTED;
|
||||
XP_LOGF( "%s: calling WSAConnect", __func__ );
|
||||
if ( SOCKET_ERROR != WSAConnect( sock, (struct sockaddr *)&name,
|
||||
sizeof(name), NULL, NULL,
|
||||
NULL, NULL ) ) {
|
||||
self->socket = sock;
|
||||
|
||||
/* Let the reader thread know there's now a socket to listen
|
||||
on */
|
||||
SetEvent( self->socketConnEvent );
|
||||
|
||||
stateChanged( self, CE_IPST_CONNECTED );
|
||||
} else if ( WSAEWOULDBLOCK == WSAGetLastError() ) {
|
||||
stateChanged( self, CE_IPST_CONNECTING );
|
||||
} else {
|
||||
logLastError( "connect" );
|
||||
int err = WSAGetLastError();
|
||||
XP_LOGF( "%s:%d: WSAGetLastError=>%d", __func__, __LINE__, err );
|
||||
}
|
||||
} else {
|
||||
logLastError( "socket" );
|
||||
int err = WSAGetLastError();
|
||||
XP_LOGF( "%s:%d: WSAGetLastError=>%d", __func__, __LINE__, err );
|
||||
}
|
||||
}
|
||||
|
||||
return self->connState == CE_IP_CONNECTED;
|
||||
XP_LOGF( "%d", self->connState == CE_IPST_CONNECTED );
|
||||
return self->connState == CE_IPST_CONNECTED;
|
||||
} /* connectSocket */
|
||||
|
||||
static XP_Bool
|
||||
connectIfNot( CeSocketWrapper* self )
|
||||
{
|
||||
XP_Bool success = self->connState == CE_IP_CONNECTED;
|
||||
LOG_FUNC();
|
||||
XP_Bool success = self->connState == CE_IPST_CONNECTED;
|
||||
|
||||
if ( !success ) {
|
||||
if ( !success && CE_IPST_HOSTRESOLVED == self->connState ) {
|
||||
success = connectSocket( self );
|
||||
}
|
||||
return success;
|
||||
|
@ -248,17 +320,18 @@ connectIfNot( CeSocketWrapper* self )
|
|||
static void
|
||||
closeConnection( CeSocketWrapper* self )
|
||||
{
|
||||
if ( self->connState >= CE_IP_UNCONNECTED ) {
|
||||
if ( self->connState >= CE_IPST_CONNECTED ) {
|
||||
|
||||
if ( self->socket != -1 ) {
|
||||
MS(closesocket)( self->socket );
|
||||
}
|
||||
|
||||
self->socket = -1;
|
||||
self->connState = CE_IP_UNCONNECTED;
|
||||
stateChanged( self, CE_IPST_START );
|
||||
}
|
||||
} /* closeConnection */
|
||||
|
||||
#if 0
|
||||
static DWORD
|
||||
WriterThreadProc( LPVOID lpParameter )
|
||||
{
|
||||
|
@ -290,7 +363,9 @@ WriterThreadProc( LPVOID lpParameter )
|
|||
ExitThread(0); /* docs say to exit this way */
|
||||
return 0;
|
||||
} /* WriterThreadProc */
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/* Read until we get the number of bytes sought or until an error's
|
||||
received. */
|
||||
static XP_Bool
|
||||
|
@ -331,7 +406,9 @@ read_bytes_blocking( CeSocketWrapper* self, XP_U8* buf, XP_U16 len )
|
|||
XP_ASSERT( len == 0 );
|
||||
return len == 0;
|
||||
} /* read_bytes_blocking */
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
static DWORD
|
||||
ReaderThreadProc( LPVOID lpParameter )
|
||||
{
|
||||
|
@ -355,42 +432,62 @@ ReaderThreadProc( LPVOID lpParameter )
|
|||
break; /* bad socket */
|
||||
}
|
||||
|
||||
(*self->dataProc)( buf, len, self->dataClosure );
|
||||
(*self->dataProc)( buf, len, self->globals );
|
||||
}
|
||||
}
|
||||
|
||||
ExitThread(0); /* docs say to exit this way */
|
||||
return 0;
|
||||
} /* ReaderThreadProc */
|
||||
#endif
|
||||
|
||||
static void
|
||||
getHostAddr( CeSocketWrapper* self )
|
||||
{
|
||||
if ( self->addrRec.u.ip_relay.hostName[0] ) {
|
||||
XP_LOGF( "%s: calling WSAAsyncGetHostByName(%s)",
|
||||
__func__, self->addrRec.u.ip_relay.hostName );
|
||||
self->getHostTask
|
||||
= WSAAsyncGetHostByName( self->globals->hWnd,
|
||||
XWWM_HOSTNAME_ARRIVED,
|
||||
self->addrRec.u.ip_relay.hostName,
|
||||
(char*)&self->hostNameUnion,
|
||||
sizeof(self->hostNameUnion) );
|
||||
if ( NULL == self->getHostTask ) {
|
||||
int err = WSAGetLastError();
|
||||
XP_LOGF( "%s: WSAGetLastError=>%d", __func__, err );
|
||||
}
|
||||
|
||||
stateChanged( self, CE_IPST_RESOLVINGHOST );
|
||||
}
|
||||
}
|
||||
|
||||
CeSocketWrapper*
|
||||
ce_sockwrap_new( MPFORMAL DataRecvProc proc, void* closure )
|
||||
ce_sockwrap_new( MPFORMAL DataRecvProc proc, CEAppGlobals* globals )
|
||||
{
|
||||
CeSocketWrapper* self = XP_MALLOC( mpool, sizeof(*self) );
|
||||
XP_MEMSET( self, 0, sizeof(*self) );
|
||||
CeSocketWrapper* self = NULL;
|
||||
|
||||
self->dataProc = proc;
|
||||
self->dataClosure = closure;
|
||||
MPASSIGN(self->mpool, mpool );
|
||||
self->socket = -1;
|
||||
WSADATA wsaData;
|
||||
int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
|
||||
if (iResult != NO_ERROR) {
|
||||
XP_WARNF("Error at WSAStartup()\n");
|
||||
} else {
|
||||
|
||||
self->queueMutex = CreateMutex( NULL, FALSE, NULL );
|
||||
XP_ASSERT( self->queueMutex != NULL );
|
||||
self = XP_MALLOC( mpool, sizeof(*self) );
|
||||
XP_MEMSET( self, 0, sizeof(*self) );
|
||||
|
||||
self->queueAddEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
|
||||
self->socketConnEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
|
||||
|
||||
/* I have no idea why these casts are necessary to prevent warnings. All
|
||||
sigs look right to me. */
|
||||
self->threads[WRITER_THREAD] =
|
||||
CreateThread( NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE)WriterThreadProc,
|
||||
self, 0, NULL );
|
||||
self->threads[READER_THREAD] =
|
||||
CreateThread( NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE)ReaderThreadProc,
|
||||
self, 0, NULL );
|
||||
self->wsaData = wsaData;
|
||||
|
||||
self->dataProc = proc;
|
||||
self->globals = globals;
|
||||
MPASSIGN(self->mpool, mpool );
|
||||
self->socket = -1;
|
||||
|
||||
self->queueMutex = CreateMutex( NULL, FALSE, NULL );
|
||||
XP_ASSERT( self->queueMutex != NULL );
|
||||
|
||||
getHostAddr( self );
|
||||
}
|
||||
return self;
|
||||
} /* ce_sockwrap_new */
|
||||
|
||||
|
@ -399,23 +496,156 @@ ce_sockwrap_delete( CeSocketWrapper* self )
|
|||
{
|
||||
/* This isn't a good thing to do. Better to signal them to exit
|
||||
some other way */
|
||||
TerminateThread( self->threads[WRITER_THREAD], 0 );
|
||||
TerminateThread( self->threads[READER_THREAD], 0 );
|
||||
|
||||
WaitForMultipleObjects( N_THREADS, self->threads, TRUE, INFINITE );
|
||||
|
||||
closeConnection( self );
|
||||
|
||||
CloseHandle( self->threads[WRITER_THREAD] );
|
||||
CloseHandle( self->threads[READER_THREAD] );
|
||||
CloseHandle( self->queueMutex );
|
||||
|
||||
CloseHandle( self->queueAddEvent );
|
||||
CloseHandle( self->socketConnEvent );
|
||||
WSACleanup();
|
||||
|
||||
XP_FREE( self->mpool, self );
|
||||
} /* ce_sockwrap_delete */
|
||||
|
||||
void
|
||||
ce_sockwrap_hostname( CeSocketWrapper* self, WPARAM wParam, LPARAM lParam )
|
||||
{
|
||||
LOG_FUNC();
|
||||
DWORD err = WSAGETASYNCERROR( lParam );
|
||||
|
||||
XP_ASSERT( CE_IPST_RESOLVINGHOST == self->connState );
|
||||
|
||||
if ( 0 == err ) {
|
||||
HANDLE comp = (HANDLE)wParam;
|
||||
XP_ASSERT( comp == self->getHostTask );
|
||||
|
||||
XP_U32 tmp;
|
||||
XP_MEMCPY( &tmp, &self->hostNameUnion.hent.h_addr_list[0][0],
|
||||
sizeof(tmp) );
|
||||
self->addrRec.u.ip_relay.ipAddr = XP_NTOHL( tmp );
|
||||
|
||||
XP_LOGF( "got address: %d.%d.%d.%d",
|
||||
(int)((tmp>>0) & 0xFF),
|
||||
(int)((tmp>>8) & 0xFF),
|
||||
(int)((tmp>>16) & 0xFF),
|
||||
(int)((tmp>>24) & 0xFF) );
|
||||
|
||||
stateChanged( self, CE_IPST_HOSTRESOLVED );
|
||||
} else {
|
||||
XP_LOGF( "%s: async operation failed: %ld", __func__, err );
|
||||
/* WSAENETDOWN */
|
||||
/* WSAENOBUFS */
|
||||
/* WSAEFAULT */
|
||||
/* WSAHOST_NOT_FOUND */
|
||||
/* WSATRY_AGAIN */
|
||||
/* WSANO_RECOVERY */
|
||||
/* WSANO_DATA */
|
||||
}
|
||||
|
||||
LOG_RETURN_VOID();
|
||||
} /* ce_sockwrap_hostname */
|
||||
|
||||
/* MSDN: When one of the nominated network events occurs on the specified
|
||||
socket s, the application window hWnd receives message wMsg. The wParam
|
||||
parameter identifies the socket on which a network event has occurred. The
|
||||
low word of lParam specifies the network event that has occurred. The high
|
||||
word of lParam contains any error code. The error code be any error as
|
||||
defined in Winsock2.h.
|
||||
*/
|
||||
|
||||
static XP_Bool
|
||||
dispatch_if_complete( CeSocketWrapper* self, XP_U16 nBytesRecvd )
|
||||
{
|
||||
XP_U16 lenInBuffer = nBytesRecvd + self->in_offset;
|
||||
XP_U16 msgLen;
|
||||
XP_Bool draw = XP_FALSE;
|
||||
if ( lenInBuffer >= sizeof(msgLen) ) {
|
||||
XP_MEMCPY( &msgLen, self->in_buf, sizeof(msgLen) );
|
||||
msgLen = XP_NTOHS( msgLen );
|
||||
|
||||
XP_LOGF( "%s: at least we have len: %d", __func__, msgLen );
|
||||
|
||||
/* We know the length of the full buffer. Do we have it? */
|
||||
if ( lenInBuffer >= (msgLen + sizeof(msgLen)) ) {
|
||||
XP_U16 lenLeft, lenUsed;
|
||||
|
||||
/* first send */
|
||||
XP_LOGF( "%s: sending %d bytes to dataProc", __func__, msgLen );
|
||||
draw = (*self->dataProc)( (XP_U8*)&self->in_buf[sizeof(msgLen)],
|
||||
msgLen, self->globals );
|
||||
|
||||
/* then move down any additional bytes */
|
||||
lenUsed = msgLen + sizeof(msgLen);
|
||||
XP_ASSERT( lenInBuffer >= lenUsed );
|
||||
lenLeft = lenInBuffer - lenUsed;
|
||||
if ( lenLeft > 0 ) {
|
||||
XP_MEMCPY( self->in_buf, &self->in_buf[lenUsed], lenLeft );
|
||||
}
|
||||
|
||||
self->in_offset = 0;
|
||||
nBytesRecvd = lenLeft; /* will set below */
|
||||
}
|
||||
}
|
||||
|
||||
self->in_offset += nBytesRecvd;
|
||||
return draw;
|
||||
} /* dispatch_if_complete */
|
||||
|
||||
static XP_U16
|
||||
read_from_socket( CeSocketWrapper* self )
|
||||
{
|
||||
WSABUF wsabuf;
|
||||
DWORD flags = 0;
|
||||
DWORD nBytesRecvd = 0;
|
||||
|
||||
wsabuf.buf = &self->in_buf[self->in_offset];
|
||||
wsabuf.len = sizeof(self->in_buf) - self->in_offset;
|
||||
|
||||
int err = WSARecv( self->socket, &wsabuf, 1, &nBytesRecvd,
|
||||
&flags, NULL, NULL );
|
||||
if ( 0 == err ) {
|
||||
XP_LOGF( "%s: got %ld bytes", __func__, nBytesRecvd );
|
||||
} else {
|
||||
XP_ASSERT( err == SOCKET_ERROR );
|
||||
err = WSAGetLastError();
|
||||
XP_LOGF( "%s: WSARecv=>%d", __func__, err );
|
||||
}
|
||||
|
||||
XP_ASSERT( nBytesRecvd < 0xFFFF );
|
||||
return (XP_U16)nBytesRecvd;
|
||||
} /* read_from_socket */
|
||||
|
||||
XP_Bool
|
||||
ce_sockwrap_event( CeSocketWrapper* self, WPARAM wParam, LPARAM lParam )
|
||||
{
|
||||
SOCKET socket = (SOCKET)wParam;
|
||||
long event = (long)LOWORD(lParam);
|
||||
XP_Bool draw = XP_FALSE;
|
||||
|
||||
if ( 0 != (FD_READ & event) ) {
|
||||
XP_U16 nReceived;
|
||||
XP_LOGF( "%s: got FD_READ", __func__ );
|
||||
nReceived = read_from_socket( self );
|
||||
if ( nReceived > 0 ) {
|
||||
draw = dispatch_if_complete( self, nReceived );
|
||||
}
|
||||
event &= ~FD_READ;
|
||||
}
|
||||
if ( 0 != (FD_WRITE & event) ) {
|
||||
event &= ~FD_WRITE;
|
||||
XP_LOGF( "%s: got FD_WRITE", __func__ );
|
||||
}
|
||||
if ( 0 != (FD_CONNECT & event) ) {
|
||||
XP_LOGF( "%s: got FD_CONNECT", __func__ );
|
||||
event &= ~FD_CONNECT;
|
||||
self->socket = socket;
|
||||
stateChanged( self, CE_IPST_CONNECTED );
|
||||
}
|
||||
|
||||
if ( 0 != event ) {
|
||||
XP_WARNF( "%s: unexpected bits left: 0x%lx", __func__, event );
|
||||
}
|
||||
return draw;
|
||||
}
|
||||
|
||||
XP_U16
|
||||
ce_sockwrap_send( CeSocketWrapper* self, const XP_U8* buf, XP_U16 len,
|
||||
const CommsAddrRec* addr )
|
||||
|
@ -425,11 +655,15 @@ ce_sockwrap_send( CeSocketWrapper* self, const XP_U8* buf, XP_U16 len,
|
|||
/* If the address has changed, we need to close the connection. Send
|
||||
thread will take care of opening it again. */
|
||||
XP_ASSERT( addr->conType == COMMS_CONN_RELAY );
|
||||
if ( 0 != XP_STRCMP( addr->u.ip_relay.hostName, self->addrRec.u.ip_relay.hostName )
|
||||
|| 0 != XP_STRCMP( addr->u.ip_relay.cookie, self->addrRec.u.ip_relay.cookie )
|
||||
if ( 0 != XP_STRCMP( addr->u.ip_relay.hostName,
|
||||
self->addrRec.u.ip_relay.hostName )
|
||||
|| 0 != XP_STRCMP( addr->u.ip_relay.cookie,
|
||||
self->addrRec.u.ip_relay.cookie )
|
||||
|| addr->u.ip_relay.port != self->addrRec.u.ip_relay.port ) {
|
||||
closeConnection( self );
|
||||
XP_MEMCPY( &self->addrRec, addr, sizeof(self->addrRec) );
|
||||
|
||||
getHostAddr( self );
|
||||
}
|
||||
|
||||
packet = XP_MALLOC( self->mpool, len );
|
||||
|
|
|
@ -23,14 +23,19 @@
|
|||
|
||||
#include "comms.h"
|
||||
#include "mempool.h"
|
||||
#include "cemain.h"
|
||||
|
||||
typedef struct CeSocketWrapper CeSocketWrapper; /* forward */
|
||||
typedef void (*DataRecvProc)( XP_U8* data, XP_U16 len, void* closure );
|
||||
typedef XP_Bool (*DataRecvProc)( XP_U8* data, XP_U16 len, void* closure );
|
||||
|
||||
|
||||
CeSocketWrapper* ce_sockwrap_new( MPFORMAL DataRecvProc proc, void* closure );
|
||||
CeSocketWrapper* ce_sockwrap_new( MPFORMAL DataRecvProc proc,
|
||||
CEAppGlobals* globals );
|
||||
void ce_sockwrap_delete( CeSocketWrapper* self );
|
||||
|
||||
void ce_sockwrap_hostname( CeSocketWrapper* self, WPARAM wParam, LPARAM lParam );
|
||||
XP_Bool ce_sockwrap_event( CeSocketWrapper* self, WPARAM wParam, LPARAM lParam );
|
||||
|
||||
XP_U16 ce_sockwrap_send( CeSocketWrapper* self, const XP_U8* buf, XP_U16 len,
|
||||
const CommsAddrRec* addr );
|
||||
|
||||
|
|
Loading…
Reference in a new issue