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.
This commit is contained in:
ehouse 2009-09-20 19:00:54 +00:00
parent cd2da3b1c3
commit a3b326205a
3 changed files with 44 additions and 18 deletions

View file

@ -3026,11 +3026,15 @@ got_data_proc( XP_U8* data, XP_U16 len, void* closure )
} /* got_data_proc */ } /* got_data_proc */
static void static void
sock_state_change( void* closure, CeConnState state ) sock_state_change( void* closure, CeConnState oldState, CeConnState newState )
{ {
CEAppGlobals* globals = (CEAppGlobals*)closure; CEAppGlobals* globals = (CEAppGlobals*)closure;
globals->socketState = state; globals->socketState = newState;
InvalidateRect( globals->hWnd, &globals->relayStatusR, TRUE /* erase */ ); InvalidateRect( globals->hWnd, &globals->relayStatusR, TRUE /* erase */ );
if ( newState < oldState ) {
comms_transportFailed( globals->game.comms );
}
} }
#endif #endif
@ -3174,6 +3178,7 @@ ce_util_userError( XW_UtilCtxt* uc, UtilErrID id )
break; break;
case ERR_RELAY_BASE + XWRELAY_ERROR_HEART_OTHER: case ERR_RELAY_BASE + XWRELAY_ERROR_HEART_OTHER:
case ERR_RELAY_BASE + XWRELAY_ERROR_LOST_OTHER: case ERR_RELAY_BASE + XWRELAY_ERROR_LOST_OTHER:
case ERR_RELAY_BASE + XWRELAY_ERROR_OTHER_DISCON:
resID = IDS_XWRELAY_ERROR_HEART_OTHER; resID = IDS_XWRELAY_ERROR_HEART_OTHER;
break; break;
/* Same string as above for now */ /* Same string as above for now */

View file

@ -137,7 +137,9 @@ send_packet_if( CeSocketWrapper* self )
{ {
const XP_U8* packet; const XP_U8* packet;
XP_U16 len; 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 ) ) { if ( sendLenAndData( self, packet, len ) ) {
/* successful send. Remove our copy */ /* successful send. Remove our copy */
bqRemoveOne( &self->queueOut ); bqRemoveOne( &self->queueOut );
@ -154,7 +156,7 @@ stateChanged( CeSocketWrapper* self, CeConnState newState )
XP_LOGF( "%s: %s -> %s", __func__, ConnState2Str( curState ), XP_LOGF( "%s: %s -> %s", __func__, ConnState2Str( curState ),
ConnState2Str( newState ) ); ConnState2Str( newState ) );
(*self->stateProc)( self->closure, newState ); (*self->stateProc)( self->closure, curState, newState );
switch( newState ) { switch( newState ) {
case CE_IPST_START: case CE_IPST_START:
@ -188,7 +190,8 @@ connectSocket( CeSocketWrapper* self )
/* Put socket in non-blocking mode */ /* Put socket in non-blocking mode */
if ( 0 != WSAAsyncSelect( sock, self->hWnd, if ( 0 != WSAAsyncSelect( sock, self->hWnd,
XWWM_SOCKET_EVT, XWWM_SOCKET_EVT,
FD_READ | FD_WRITE | FD_CONNECT ) ) { FD_READ | FD_WRITE | FD_CONNECT
| FD_CLOSE ) ) {
XP_WARNF( "WSAAsyncSelect failed" ); XP_WARNF( "WSAAsyncSelect failed" );
} }
@ -201,7 +204,7 @@ connectSocket( CeSocketWrapper* self )
sizeof(name), NULL, NULL, sizeof(name), NULL, NULL,
NULL, NULL ) ) { NULL, NULL ) ) {
self->socket = sock; self->socket = sock;
stateChanged( self, CE_IPST_CONNECTED ); stateChanged( self, CE_IPST_CONNECTING );
} else if ( WSAEWOULDBLOCK == WSAGetLastError() ) { } else if ( WSAEWOULDBLOCK == WSAGetLastError() ) {
stateChanged( self, CE_IPST_CONNECTING ); stateChanged( self, CE_IPST_CONNECTING );
} else { } else {
@ -239,9 +242,12 @@ closeConnection( CeSocketWrapper* self )
closesocket( self->socket ); closesocket( self->socket );
self->socket = -1; self->socket = -1;
} }
stateChanged( self, CE_IPST_START );
} }
bqRemoveAll( &self->queueOut );
XP_ASSERT( self->socket == -1 );
stateChanged( self, CE_IPST_START );
} /* closeConnection */ } /* closeConnection */
static void static void
@ -438,17 +444,28 @@ ce_sockwrap_event( CeSocketWrapper* self, WPARAM wParam, LPARAM lParam )
} }
if ( 0 != (FD_CONNECT & event) ) { 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; event &= ~FD_CONNECT;
self->socket = socket; if ( 0 == err ) {
stateChanged( self, CE_IPST_CONNECTED ); 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 ) { if ( 0 != event ) {
XP_WARNF( "%s: unexpected bits left: 0x%lx", __func__, event ); XP_WARNF( "%s: unexpected bits left: 0x%lx", __func__, event );
} }
return draw; return draw;
} } /* ce_sockwrap_event */
XP_S16 XP_S16
ce_sockwrap_send( CeSocketWrapper* self, const XP_U8* buf, XP_U16 len, 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_S16 nSent = -1; /* error */
XP_LOGF( "%s(len=%d)", __func__, len ); XP_LOGF( "%s(len=%d)", __func__, len );
/* If the address has changed, we need to close the connection. Send /* If the address has changed, we need to close the connection, then call
thread will take care of opening it again. */ getHostAddr() to kick off the async reconnect process. */
XP_ASSERT( addr->conType == COMMS_CONN_RELAY ); XP_ASSERT( addr->conType == COMMS_CONN_RELAY );
if ( 0 != XP_STRCMP( addr->u.ip_relay.hostName, if ( 0 != XP_STRCMP( addr->u.ip_relay.hostName,
self->addrRec.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 ); closeConnection( self );
XP_MEMCPY( &self->addrRec, addr, sizeof(self->addrRec) ); 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 ) ) { if ( bqAdd( &self->queueOut, buf, len ) ) {
send_packet_if( self ); send_packet_if( self );
nSent = len; nSent = len;

View file

@ -34,11 +34,11 @@ typedef enum {
typedef struct CeSocketWrapper CeSocketWrapper; /* forward */ typedef struct CeSocketWrapper CeSocketWrapper; /* forward */
typedef XP_Bool (*DataRecvProc)( XP_U8* data, XP_U16 len, void* closure ); 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, CeSocketWrapper* ce_sockwrap_new( MPFORMAL HWND hWnd, DataRecvProc dataCB,
StateChangeProc stateCB, StateChangeProc stateCB, void* globals );
void* globals );
void ce_sockwrap_delete( CeSocketWrapper* self ); void ce_sockwrap_delete( CeSocketWrapper* self );
void ce_sockwrap_hostname( CeSocketWrapper* self, WPARAM wParam, LPARAM lParam ); void ce_sockwrap_hostname( CeSocketWrapper* self, WPARAM wParam, LPARAM lParam );