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:
ehouse 2009-01-31 18:06:09 +00:00
parent 50bd5e875b
commit 95a93191be
5 changed files with 359 additions and 125 deletions

View file

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

View file

@ -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

View file

@ -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

View file

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

View file

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