From a3b326205a467d8707f50e95eff5517d223bccb8 Mon Sep 17 00:00:00 2001 From: ehouse Date: Sun, 20 Sep 2009 19:00:54 +0000 Subject: [PATCH] Do a better job of handling failure to connect or loss of connection: look for errors coming with FD_CONNECT message, look for FD_CLOSE message, and inform relay when connection is lost so its reconnect logic is triggered. This seems at least to handle the case where I kill the relay mid-game. --- xwords4/wince/cemain.c | 9 ++++++-- xwords4/wince/cesockwr.c | 47 +++++++++++++++++++++++++++++----------- xwords4/wince/cesockwr.h | 6 ++--- 3 files changed, 44 insertions(+), 18 deletions(-) diff --git a/xwords4/wince/cemain.c b/xwords4/wince/cemain.c index 5188a1be1..307a5dd04 100755 --- a/xwords4/wince/cemain.c +++ b/xwords4/wince/cemain.c @@ -3026,11 +3026,15 @@ got_data_proc( XP_U8* data, XP_U16 len, void* closure ) } /* got_data_proc */ static void -sock_state_change( void* closure, CeConnState state ) +sock_state_change( void* closure, CeConnState oldState, CeConnState newState ) { CEAppGlobals* globals = (CEAppGlobals*)closure; - globals->socketState = state; + globals->socketState = newState; InvalidateRect( globals->hWnd, &globals->relayStatusR, TRUE /* erase */ ); + + if ( newState < oldState ) { + comms_transportFailed( globals->game.comms ); + } } #endif @@ -3174,6 +3178,7 @@ ce_util_userError( XW_UtilCtxt* uc, UtilErrID id ) break; case ERR_RELAY_BASE + XWRELAY_ERROR_HEART_OTHER: case ERR_RELAY_BASE + XWRELAY_ERROR_LOST_OTHER: + case ERR_RELAY_BASE + XWRELAY_ERROR_OTHER_DISCON: resID = IDS_XWRELAY_ERROR_HEART_OTHER; break; /* Same string as above for now */ diff --git a/xwords4/wince/cesockwr.c b/xwords4/wince/cesockwr.c index 17156c579..76f5040f5 100755 --- a/xwords4/wince/cesockwr.c +++ b/xwords4/wince/cesockwr.c @@ -137,7 +137,9 @@ send_packet_if( CeSocketWrapper* self ) { const XP_U8* packet; XP_U16 len; - if ( self->socket != -1 && bqGet( &self->queueOut, &packet, &len ) ) { + if ( self->socket == -1 ) { + XP_LOGF( "%s: have no socket", __func__ ); + } else if ( bqGet( &self->queueOut, &packet, &len ) ) { if ( sendLenAndData( self, packet, len ) ) { /* successful send. Remove our copy */ bqRemoveOne( &self->queueOut ); @@ -154,7 +156,7 @@ stateChanged( CeSocketWrapper* self, CeConnState newState ) XP_LOGF( "%s: %s -> %s", __func__, ConnState2Str( curState ), ConnState2Str( newState ) ); - (*self->stateProc)( self->closure, newState ); + (*self->stateProc)( self->closure, curState, newState ); switch( newState ) { case CE_IPST_START: @@ -188,7 +190,8 @@ connectSocket( CeSocketWrapper* self ) /* Put socket in non-blocking mode */ if ( 0 != WSAAsyncSelect( sock, self->hWnd, XWWM_SOCKET_EVT, - FD_READ | FD_WRITE | FD_CONNECT ) ) { + FD_READ | FD_WRITE | FD_CONNECT + | FD_CLOSE ) ) { XP_WARNF( "WSAAsyncSelect failed" ); } @@ -201,7 +204,7 @@ connectSocket( CeSocketWrapper* self ) sizeof(name), NULL, NULL, NULL, NULL ) ) { self->socket = sock; - stateChanged( self, CE_IPST_CONNECTED ); + stateChanged( self, CE_IPST_CONNECTING ); } else if ( WSAEWOULDBLOCK == WSAGetLastError() ) { stateChanged( self, CE_IPST_CONNECTING ); } else { @@ -239,9 +242,12 @@ closeConnection( CeSocketWrapper* self ) closesocket( self->socket ); self->socket = -1; } - - stateChanged( self, CE_IPST_START ); } + + bqRemoveAll( &self->queueOut ); + + XP_ASSERT( self->socket == -1 ); + stateChanged( self, CE_IPST_START ); } /* closeConnection */ static void @@ -438,17 +444,28 @@ ce_sockwrap_event( CeSocketWrapper* self, WPARAM wParam, LPARAM lParam ) } if ( 0 != (FD_CONNECT & event) ) { - XP_LOGF( "%s: got FD_CONNECT", __func__ ); + int err = WSAGETSELECTERROR(lParam); + XP_LOGF( "%s: got FD_CONNECT; err=%d", __func__, err ); event &= ~FD_CONNECT; - self->socket = socket; - stateChanged( self, CE_IPST_CONNECTED ); + if ( 0 == err ) { + XP_ASSERT( self->socket == -1 || self->socket == socket ); + self->socket = socket; + stateChanged( self, CE_IPST_CONNECTED ); + } else { + closeConnection( self ); + } + } + + if ( 0 != (FD_CLOSE & event) ) { + event &= ~FD_CLOSE; + closeConnection( self ); } if ( 0 != event ) { XP_WARNF( "%s: unexpected bits left: 0x%lx", __func__, event ); } return draw; -} +} /* ce_sockwrap_event */ XP_S16 ce_sockwrap_send( CeSocketWrapper* self, const XP_U8* buf, XP_U16 len, @@ -457,8 +474,8 @@ ce_sockwrap_send( CeSocketWrapper* self, const XP_U8* buf, XP_U16 len, XP_S16 nSent = -1; /* error */ XP_LOGF( "%s(len=%d)", __func__, len ); - /* If the address has changed, we need to close the connection. Send - thread will take care of opening it again. */ + /* If the address has changed, we need to close the connection, then call + getHostAddr() to kick off the async reconnect process. */ XP_ASSERT( addr->conType == COMMS_CONN_RELAY ); if ( 0 != XP_STRCMP( addr->u.ip_relay.hostName, self->addrRec.u.ip_relay.hostName ) @@ -468,9 +485,13 @@ ce_sockwrap_send( CeSocketWrapper* self, const XP_U8* buf, XP_U16 len, closeConnection( self ); XP_MEMCPY( &self->addrRec, addr, sizeof(self->addrRec) ); - getHostAddr( self ); } + if ( CE_IPST_START == self->connState ) { + getHostAddr( self ); /* kicks off connection process */ + } + /* What if we're stuck in some other state? Kick those here too? */ + if ( bqAdd( &self->queueOut, buf, len ) ) { send_packet_if( self ); nSent = len; diff --git a/xwords4/wince/cesockwr.h b/xwords4/wince/cesockwr.h index 424258ce9..2ba133da2 100755 --- a/xwords4/wince/cesockwr.h +++ b/xwords4/wince/cesockwr.h @@ -34,11 +34,11 @@ typedef enum { typedef struct CeSocketWrapper CeSocketWrapper; /* forward */ typedef XP_Bool (*DataRecvProc)( XP_U8* data, XP_U16 len, void* closure ); -typedef void (*StateChangeProc)( void* closure, CeConnState state ); +typedef void (*StateChangeProc)( void* closure, CeConnState oldState, + CeConnState newState ); CeSocketWrapper* ce_sockwrap_new( MPFORMAL HWND hWnd, DataRecvProc dataCB, - StateChangeProc stateCB, - void* globals ); + StateChangeProc stateCB, void* globals ); void ce_sockwrap_delete( CeSocketWrapper* self ); void ce_sockwrap_hostname( CeSocketWrapper* self, WPARAM wParam, LPARAM lParam );