/* *Copyright (c) 1996 by Oracle Corporation. All Rights Reserved. \ $Header: fsm.c 23-aug-96.12:32:00 aswang Exp $ */ /* * Finite State Machines */ #include "tftpdef.h" #ifdef SERVER #include int tnsapi(); #endif #ifdef VMS #include #endif #ifdef CLIENT int recv_ACK(), recv_DATA(), recv_RQERR(); #endif #ifdef SERVER int recv_RRQ(), recv_WRQ(), recv_ACK(), recv_DATA(), recv_DISRQ(); #endif int fsm_error(), fsm_invalid(); int net_recv(); int err_dump(); /* * Finite state machine table * This is a 2-d array indexed by the last opcode sent and the opcode * just received. The result is the address of a function to call to * process the received opcode. */ int (*fsm_ptr [OP_MAX+1][OP_MAX+1] ) () = { #ifdef CLIENT fsm_invalid, /* [sent = 0] [recv = 0] */ fsm_invalid, /* [sent = 0] [recv = OP_RRQ] */ fsm_invalid, /* [sent = 0] [recv = OP_WRQ] */ fsm_invalid, /* [sent = 0] [recv = OP_DATA] */ fsm_invalid, /* [sent = 0] [recv = OP_ACK] */ fsm_invalid, /* [sent = 0] [recv = OP_ERROR] */ fsm_invalid, /* [sent = OP_RRQ] [recv = 0] */ fsm_invalid, /* [sent = OP_RRQ] [recv = OP_RRQ] */ fsm_invalid, /* [sent = OP_RRQ] [recv = OP_WRQ] */ recv_DATA, /* [sent = OP_RRQ] [recv = OP_DATA] */ fsm_invalid, /* [sent = OP_RRQ] [recv = OP_ACK] */ recv_RQERR, /* [sent = OP_RRQ] [recv = OP_ERROR] */ fsm_invalid, /* [sent = OP_WRQ] [recv = 0 ] */ fsm_invalid, /* [sent = OP_WRQ] [recv = OP_RRQ] */ fsm_invalid, /* [sent = OP_WRQ] [recv = OP_WRQ] */ fsm_invalid, /* [sent = OP_WRQ] [recv = OP_DATA] */ recv_ACK, /* [sent = OP_WRQ] [recv = OP_ACK] */ recv_RQERR, /* [sent = OP_WRQ] [recv = OP_ERROR] */ fsm_invalid, /* [sent = OP_DATA] [recv = 0] */ fsm_invalid, /* [sent = OP_DATA] [recv = OP_RRQ] */ fsm_invalid, /* [sent = OP_DATA] [recv = OP_WRQ] */ fsm_invalid, /* [sent = OP_DATA] [recv = OP_DATA] */ recv_ACK, /* [sent = OP_DATA] [recv = OP_ACK] */ fsm_error, /* [sent = OP_DATA] [recv = OP_ERROR] */ fsm_invalid, /* [sent = OP_ACK] [recv = 0] */ fsm_invalid, /* [sent = OP_ACK] [recv = OP_RRQ] */ fsm_invalid, /* [sent = OP_ACK] [recv = OP_WRQ] */ recv_DATA, /* [sent = OP_ACK] [recv = OP_DATA] */ fsm_invalid, /* [sent = OP_ACK] [recv = OP_ACK] */ fsm_error, /* [sent = OP_ACK] [recv = OP_ERROR] */ fsm_invalid, /* [sent = OP_ERROR] [recv = 0] */ fsm_invalid, /* [sent = OP_ERROR] [recv = OP_RRQ] */ fsm_invalid, /* [sent = OP_ERROR] [recv = OP_WRQ] */ fsm_invalid, /* [sent = OP_ERROR] [recv = OP_DATA] */ fsm_invalid, /* [sent = OP_ERROR] [recv = OP_ACK] */ fsm_error /* [sent = OP_ERROR] [recv = OP_ERROR] */ #endif /* CLIENT */ #ifdef SERVER fsm_invalid, /* [sent = 0] [recv = 0] */ recv_RRQ, /* [sent = 0] [recv = OP_RRQ] */ recv_WRQ, /* [sent = 0] [recv = OP_WRQ] */ fsm_invalid, /* [sent = 0] [recv = OP_DATA] */ fsm_invalid, /* [sent = 0] [recv = OP_ACK] */ fsm_invalid, /* [sent = 0] [recv = OP_ERROR] */ fsm_invalid, /* [sent = OP_RRQ] [recv = 0] */ fsm_invalid, /* [sent = OP_RRQ] [recv = OP_RRQ] */ fsm_invalid, /* [sent = OP_RRQ] [recv = OP_WRQ] */ fsm_invalid, /* [sent = OP_RRQ] [recv = OP_DATA] */ fsm_invalid, /* [sent = OP_RRQ] [recv = OP_ACK] */ fsm_invalid, /* [sent = OP_RRQ] [recv = OP_ERROR] */ fsm_invalid, /* [sent = OP_WRQ] [recv = 0] */ fsm_invalid, /* [sent = OP_WRQ] [recv = OP_RRQ] */ fsm_invalid, /* [sent = OP_WRQ] [recv = OP_WRQ] */ fsm_invalid, /* [sent = OP_WRQ] [recv = OP_DATA] */ fsm_invalid, /* [sent = OP_WRQ] [recv = OP_ACK] */ fsm_invalid, /* [sent = OP_WRQ] [recv = OP_ERROR] */ fsm_invalid, /* [sent = OP_DATA] [recv = 0] */ fsm_invalid, /* [sent = OP_DATA] [recv = OP_RRQ] */ fsm_invalid, /* [sent = OP_DATA] [recv = OP_WRQ] */ fsm_invalid, /* [sent = OP_DATA] [recv = OP_DATA] */ recv_ACK, /* [sent = OP_DATA] [recv = OP_ACK] */ fsm_error, /* [sent = OP_DATA] [recv = OP_ERROR] */ fsm_invalid, /* [sent = OP_ACK] [recv = 0] */ fsm_invalid, /* [sent = OP_ACK] [recv = OP_RRQ] */ fsm_invalid, /* [sent = OP_ACK] [recv = OP_WRQ] */ recv_DATA, /* [sent = OP_ACK] [recv = OP_DATA] */ fsm_invalid, /* [sent = OP_ACK] [recv = OP_ACK] */ fsm_error, /* [sent = OP_ACK] [recv = OP_ERROR] */ fsm_invalid, /* [sent = OP_ERROR] [recv = 0] */ fsm_invalid, /* [sent = OP_ERROR] [recv = OP_RRQ] */ fsm_invalid, /* [sent = OP_ERROR] [recv = OP_WRQ] */ fsm_invalid, /* [sent = OP_ERROR] [recv = OP_DATA] */ fsm_invalid, /* [sent = OP_ERROR] [recv = OP_ACK] */ fsm_invalid /* [sent = OP_ERROR] [recv = OP_ERROR] */ #endif /* SERVER */ }; /* * Main loop of finite state machine * * For the client, we are called after either a RRQ or a WRQ has been sent * to the other side. * * For the server, we are called after either a RRQ or a WRQ has been * received from the other side. In this case, the argument will be a 0 * (since nothing has been sent ) but the state table above handles this */ int fsm_loop(opcode) int opcode; { register int nbytes; op_sent = opcode; for (;;) { if ((nbytes = net_recv(recvbuff, MAXBUFF)) < 0) err_dump("net_recv error"); /* * The shortest packet is the disconnect packet, only has two bytes */ if (nbytes < 2) err_dump("receive length = %d bytes", nbytes); op_recv = ldshort(recvbuff); if (op_recv < OP_MIN || op_recv > OP_MAX) { #ifdef SERVER if (op_recv == OP_DISCONNECT) { /* disconnect and exit */ tnsclose(&svrtnshdl); exit(0); } else #endif err_dump("invalid opcode received: %d", op_recv); } /* * we call the appropriate function, passing the address of the receive * buffer and its length. These arguments ignore the received-opcode, * which we have already processed * we assume that the called function will send a response to the * other side. It is the called function's responsibility to * set op_sent to the op-code that it sends to the other side */ if ((*fsm_ptr[op_sent][op_recv])(recvbuff +2, nbytes -2) < 0) { /* * when the called function return -1, this loop is done. * e.g., RRQ or WRQ failed */ #ifndef WIN32 signal(SIGALRM, SIG_DFL); #endif return(0); } } } int fsm_error(ptr, nbytes) char *ptr; int nbytes; { err_dump("error received: op_sent = %d, op_recv = %d", op_sent, op_recv); return(0); } int fsm_invalid(ptr, nbytes) char *ptr; int nbytes; { err_dump("protocol error: op_sent = %d, op_recv = %d", op_sent, op_recv); return(0); }