xwords/relay/states.cpp

130 lines
4.7 KiB
C++
Raw Normal View History

/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* Copyright 2005 by Eric House (fixin@peak.org). All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "assert.h"
#include "states.h"
#include "xwrelay_priv.h"
typedef struct StateTable {
XW_RELAY_STATE stateStart;
XW_RELAY_EVENT stateEvent;
XW_RELAY_ACTION stateAction;
XW_RELAY_STATE stateEnd; /* Do I need this? Or does the code that
performs the action determine the state? */
} StateTable;
StateTable g_stateTable[] = {
/* Initial msg comes in. Managing object created in init state, sends response */
{ XW_ST_INITED, XW_EVENT_CONNECTMSG, XW_ACTION_SENDRSP, XW_ST_CONNECTING },
/* Another connect msg comes in */
{ XW_ST_CONNECTING, XW_EVENT_CONNECTMSG, XW_ACTION_SENDRSP, XW_ST_CONNECTING },
/* Fwd message comes in, tells us we're now fully connected */
{ XW_ST_CONNECTING, XW_EVENT_FORWARDMSG, XW_ACTION_FWD, XW_ST_ALLCONNECTED },
{ XW_ST_CONNECTING, XW_EVENT_HEARTMSG, XW_ACTION_NOTEHEART, XW_ST_CONNECTING },
/* Timeout before all connected */
{ XW_ST_CONNECTING, XW_EVENT_CONNTIMER, XW_ACTION_DISCONNECTALL, XW_ST_DEAD },
{ XW_ST_CONNECTING, XW_EVENT_HEARTTIMER, XW_ACTION_CHECKHEART, XW_ST_HEARTCHECK_CONNECTING },
/* This is the entry we'll use most of the time */
{ XW_ST_ALLCONNECTED, XW_EVENT_FORWARDMSG, XW_ACTION_FWD, XW_ST_ALLCONNECTED },
/* Heartbeat arrived */
{ XW_ST_ALLCONNECTED, XW_EVENT_HEARTMSG, XW_ACTION_NOTEHEART, XW_ST_ALLCONNECTED },
/* Heartbeat timer means check for dead connections. Post event to self if there's a problem. */
{ XW_ST_ALLCONNECTED, XW_EVENT_HEARTTIMER, XW_ACTION_CHECKHEART, XW_ST_HEARTCHECK_CONNECTED },
{ XW_ST_HEARTCHECK_CONNECTING, XW_EVENT_HEARTOK, XW_ACTION_HEARTOK, XW_ST_CONNECTING },
{ XW_ST_HEARTCHECK_CONNECTING, XW_EVENT_HEARTFAILED, XW_ACTION_DISCONNECTALL, XW_ST_DEAD },
{ XW_ST_HEARTCHECK_CONNECTED, XW_EVENT_HEARTOK, XW_ACTION_HEARTOK, XW_ST_ALLCONNECTED },
{ XW_ST_HEARTCHECK_CONNECTED, XW_EVENT_HEARTFAILED, XW_ACTION_DISCONNECTALL, XW_ST_DEAD },
/* Reconnect. Just like a connect but cookieID is supplied. Can it
happen in the middle of a game when state is XW_ST_ALLCONNECTED? */
/* Marks end of table */
{ XW_ST_NONE, XW_EVENT_NONE, XW_ACTION_NONE, XW_ST_NONE }
};
int
getFromTable( XW_RELAY_STATE curState, XW_RELAY_EVENT curEvent,
XW_RELAY_ACTION* takeAction, XW_RELAY_STATE* nextState )
{
StateTable* stp = g_stateTable;
while ( stp->stateStart != XW_ST_NONE ) {
if ( stp->stateStart == curState && stp->stateEvent == curEvent ) {
*takeAction = stp->stateAction;
*nextState = stp->stateEnd;
return 1;
}
++stp;
}
logf( "unable to find transition from %s on event %s",
stateString(curState), eventString(curEvent) );
assert(0);
return 0;
} /* getFromTable */
#define CASESTR(s) case s: return #s
char*
stateString( XW_RELAY_STATE state )
{
switch( state ) {
CASESTR(XW_ST_NONE);
CASESTR(XW_ST_INITED);
CASESTR(XW_ST_CONNECTING);
CASESTR(XW_ST_ALLCONNECTED);
CASESTR(XW_ST_WAITING_RECON);
CASESTR(XW_ST_SENDING_DISCON);
CASESTR(XW_ST_DISCONNECTED);
CASESTR(XW_ST_HEARTCHECK_CONNECTING);
CASESTR(XW_ST_HEARTCHECK_CONNECTED);
CASESTR(XW_ST_DEAD);
}
assert(0);
return "";
}
char*
eventString( XW_RELAY_EVENT evt )
{
switch( evt ) {
CASESTR(XW_EVENT_NONE);
CASESTR(XW_EVENT_CONNECTMSG);
CASESTR(XW_EVENT_RECONNECTMSG);
CASESTR(XW_EVENT_FORWARDMSG);
CASESTR(XW_EVENT_HEARTMSG);
CASESTR(XW_EVENT_HEARTTIMER);
CASESTR(XW_EVENT_DISCONTIMER);
CASESTR(XW_EVENT_CONNTIMER);
CASESTR(XW_EVENT_HEARTOK);
CASESTR(XW_EVENT_HEARTFAILED);
}
assert(0);
return "";
}
#undef CASESTR