Listing 4: Relay loop with a finite state machine
class PacketRelay { StreamSocket& sock1; StreamSocket& sock2; char sock1_name[80]; // Socket names for easy reference char sock2_name[80]; // (name cache) char * buffer; enum { IO_buffer_size=12000 }; BOOL done; static PacketRelay * the_PacketRelay; void intr_enable(void); void intr_disable(void); // Finite State Machine "Actors" enum StatusCode {OK=0, NoData, Eof, Failed}; // what Actors return enum SOCK_ID { id_sock1, id_sock2 }; typedef StatusCode (*Actor)(PacketRelay * _this, const SOCK_ID id); // Meaning write to another socket and // keep the log StatusCode relay_socket(const SOCK_ID id); BOOL done_loop; StatusCode is_loop_done(const SOCK_ID id) { return done_loop ? Eof : OK; } StatusCode set_loop_done(const SOCK_ID id) { done_loop = TRUE; return OK; } StatusCode reset_loop_done(const SOCK_ID id) { done_loop = FALSE; return OK;} StatusCode set_finished(const SOCK_ID id) { done = TRUE; return OK;} // Relay Finite State Machine struct FSMAction { Actor actor; SOCK_ID socket_to_use; short next_state[Eof+1]; }; static FSMAction FSMProgram []; public: PacketRelay(StreamSocket& _sock1, StreamSocket& _sock2); ~PacketRelay(void); BOOL q_done(void) const { return done; } static int relay(void); // That's what relays (if anything) }; PacketRelay * PacketRelay::the_PacketRelay = 0; // Here is the FSM relay program PacketRelay::FSMAction PacketRelay::FSMProgram [] = { /* 0 */ {0, id_sock1, {0,0,0}}, // Dummy (stop) state // State What to do on which socket OK ND EOF /* 1 */ { (Actor)&relay_socket, id_sock1, {2, 3, 5} }, // start state /* 2 */ { (Actor)&relay_socket, id_sock2, {1, 4, 6} }, /* 3 */ { (Actor)&set_loop_done, id_sock1, {2, -1, -1} }, /* 4 */ { (Actor)&is_loop_done, id_sock1, {1, 0, 0} }, /* 5 */ { (Actor)&relay_socket, id_sock2, {5, 7, 7} }, /* 6 */ { (Actor)&relay_socket, id_sock1, {6, 7, 7} }, /* 7 */ { (Actor)&set_finished, id_sock1, {0, 0, 0} } }; // This is where it relays: the Finite // State Machine // Start with the state #1, do the action and // pick up the next state based on the action's // return code. Keep doing it until hit the // stop state (pc=0) int PacketRelay::relay(void) { PacketRelay& me = *the_PacketRelay; if( me.done ) return 0; int pc; // "Program" counter for(pc=1; pc != 0; ) { assert( pc > 0 ); const FSMAction& action = FSMProgram[pc]; StatusCode result = action.actor(&me,action.socket_to_use); if( result == Failed ) return me.done = TRUE, 0; pc = action.next_state[result]; } return 0; } //End of File