static void nn_stcp_handler(struct nn_fsm *self,int32_t src,int32_t type,NN_UNUSED void *srcptr) { int32_t rc,opt; struct nn_stcp *stcp; uint64_t size; size_t opt_sz = sizeof(opt); stcp = nn_cont(self,struct nn_stcp,fsm); switch (stcp->state) { /******************************************************************************/ /* IDLE state. */ /******************************************************************************/ case NN_STCP_STATE_IDLE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_FSM_START: //printf("streamhdr start\n"); nn_streamhdr_start(&stcp->streamhdr,stcp->usock,&stcp->pipebase); stcp->state = NN_STCP_STATE_PROTOHDR; return; default: nn_fsm_bad_action (stcp->state,src,type); } default: nn_fsm_bad_source (stcp->state, src, type); } /******************************************************************************/ /* PROTOHDR state. */ /******************************************************************************/ case NN_STCP_STATE_PROTOHDR: switch ( src ) { case NN_STCP_SRC_STREAMHDR: switch ( type ) { case NN_STREAMHDR_OK: // Before moving to the active state stop the streamhdr state machine nn_streamhdr_stop(&stcp->streamhdr); stcp->state = NN_STCP_STATE_STOPPING_STREAMHDR; return; case NN_STREAMHDR_ERROR: // Raise the error and move directly to the DONE state. streamhdr object will be stopped later on stcp->state = NN_STCP_STATE_DONE; nn_fsm_raise(&stcp->fsm,&stcp->done,NN_STCP_ERROR); return; default: nn_fsm_bad_action (stcp->state, src, type); } default: nn_fsm_bad_source(stcp->state,src,type); } /******************************************************************************/ /* STOPPING_STREAMHDR state. */ /******************************************************************************/ case NN_STCP_STATE_STOPPING_STREAMHDR: switch ( src ) { case NN_STCP_SRC_STREAMHDR: switch ( type ) { case NN_STREAMHDR_STOPPED: /* Start the pipe. */ rc = nn_pipebase_start(&stcp->pipebase); if ( nn_slow (rc < 0) ) { stcp->state = NN_STCP_STATE_DONE; nn_fsm_raise(&stcp->fsm, &stcp->done, NN_STCP_ERROR); return; } // Start receiving a message in asynchronous manner stcp->instate = NN_STCP_INSTATE_HDR; nn_usock_recv(stcp->usock,&stcp->inhdr,sizeof(stcp->inhdr),NULL); //printf("STCP recv.[%d %d %d %d]\n",stcp->inhdr[0],stcp->inhdr[1],stcp->inhdr[2],stcp->inhdr[3]); // Mark the pipe as available for sending stcp->outstate = NN_STCP_OUTSTATE_IDLE; stcp->state = NN_STCP_STATE_ACTIVE; return; default: nn_fsm_bad_action (stcp->state, src, type); } default: nn_fsm_bad_source (stcp->state, src, type); } /******************************************************************************/ /* ACTIVE state. */ /******************************************************************************/ case NN_STCP_STATE_ACTIVE: switch ( src ) { case NN_STCP_SRC_USOCK: switch ( type ) { case NN_USOCK_SENT: // The message is now fully sent nn_assert (stcp->outstate == NN_STCP_OUTSTATE_SENDING); stcp->outstate = NN_STCP_OUTSTATE_IDLE; nn_msg_term(&stcp->outmsg); nn_msg_init(&stcp->outmsg,0); nn_pipebase_sent(&stcp->pipebase); return; case NN_USOCK_RECEIVED: switch ( stcp->instate ) { case NN_STCP_INSTATE_HDR: // Message header was received. Check that message size is acceptable by comparing with NN_RCVMAXSIZE; if it's too large, drop the connection size = nn_getll(stcp->inhdr); nn_pipebase_getopt(&stcp->pipebase,NN_SOL_SOCKET,NN_RCVMAXSIZE,&opt,&opt_sz); if ( opt != -1 && size > opt ) { stcp->state = NN_STCP_STATE_DONE; nn_fsm_raise(&stcp->fsm,&stcp->done,NN_STCP_ERROR); return; } // Allocate memory for the message nn_msg_term(&stcp->inmsg); nn_msg_init(&stcp->inmsg,(size_t)size); // Special case when size of the message body is 0 if ( !size ) { printf("STCP: zero size pipebase recv\n"); stcp->instate = NN_STCP_INSTATE_HASMSG; nn_pipebase_received (&stcp->pipebase); return; } // Start receiving the message body stcp->instate = NN_STCP_INSTATE_BODY; nn_usock_recv (stcp->usock,nn_chunkref_data(&stcp->inmsg.body),(size_t)size,NULL); return; case NN_STCP_INSTATE_BODY: // Message body was received. Notify the owner that it can receive it stcp->instate = NN_STCP_INSTATE_HASMSG; nn_pipebase_received(&stcp->pipebase); return; default: nn_fsm_error("Unexpected socket instate",stcp->state,src,type); } case NN_USOCK_SHUTDOWN: nn_pipebase_stop(&stcp->pipebase); stcp->state = NN_STCP_STATE_SHUTTING_DOWN; return; case NN_USOCK_ERROR: nn_pipebase_stop(&stcp->pipebase); stcp->state = NN_STCP_STATE_DONE; nn_fsm_raise(&stcp->fsm,&stcp->done,NN_STCP_ERROR); return; default: nn_fsm_bad_action(stcp->state,src,type); } default: nn_fsm_bad_source(stcp->state,src,type); } /******************************************************************************/ /* SHUTTING_DOWN state. */ /* The underlying connection is closed. We are just waiting that underlying */ /* usock being closed */ /******************************************************************************/ case NN_STCP_STATE_SHUTTING_DOWN: switch (src) { case NN_STCP_SRC_USOCK: switch (type) { case NN_USOCK_ERROR: stcp->state = NN_STCP_STATE_DONE; nn_fsm_raise (&stcp->fsm, &stcp->done, NN_STCP_ERROR); return; default: nn_fsm_bad_action (stcp->state, src, type); } default: nn_fsm_bad_source (stcp->state, src, type); } /******************************************************************************/ /* DONE state. */ /* The underlying connection is closed. There's nothing that can be done in */ /* this state except stopping the object. */ /******************************************************************************/ case NN_STCP_STATE_DONE: nn_fsm_bad_source (stcp->state, src, type); /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_fsm_bad_state (stcp->state, src, type); } }
static void nn_stcp_handler (struct nn_fsm *self, int src, int type, void *srcptr) { int rc; struct nn_stcp *stcp; uint64_t size; stcp = nn_cont (self, struct nn_stcp, fsm); switch (stcp->state) { /******************************************************************************/ /* IDLE state. */ /******************************************************************************/ case NN_STCP_STATE_IDLE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_FSM_START: nn_streamhdr_start (&stcp->streamhdr, stcp->usock, &stcp->pipebase); stcp->state = NN_STCP_STATE_PROTOHDR; return; default: nn_fsm_bad_action (stcp->state, src, type); } default: nn_fsm_bad_source (stcp->state, src, type); } /******************************************************************************/ /* PROTOHDR state. */ /******************************************************************************/ case NN_STCP_STATE_PROTOHDR: switch (src) { case NN_STCP_SRC_STREAMHDR: switch (type) { case NN_STREAMHDR_OK: /* Before moving to the active state stop the streamhdr state machine. */ nn_streamhdr_stop (&stcp->streamhdr); stcp->state = NN_STCP_STATE_STOPPING_STREAMHDR; return; case NN_STREAMHDR_ERROR: /* Raise the error and move directly to the DONE state. streamhdr object will be stopped later on. */ stcp->state = NN_STCP_STATE_DONE; nn_fsm_raise (&stcp->fsm, &stcp->done, NN_STCP_ERROR); return; default: nn_fsm_bad_action (stcp->state, src, type); } default: nn_fsm_bad_source (stcp->state, src, type); } /******************************************************************************/ /* STOPPING_STREAMHDR state. */ /******************************************************************************/ case NN_STCP_STATE_STOPPING_STREAMHDR: switch (src) { case NN_STCP_SRC_STREAMHDR: switch (type) { case NN_STREAMHDR_STOPPED: /* Start the pipe. */ rc = nn_pipebase_start (&stcp->pipebase); errnum_assert (rc == 0, -rc); /* Start receiving a message in asynchronous manner. */ stcp->instate = NN_STCP_INSTATE_HDR; nn_usock_recv (stcp->usock, &stcp->inhdr, sizeof (stcp->inhdr)); /* Mark the pipe as available for sending. */ stcp->outstate = NN_STCP_OUTSTATE_IDLE; stcp->state = NN_STCP_STATE_ACTIVE; return; default: nn_fsm_bad_action (stcp->state, src, type); } default: nn_fsm_bad_source (stcp->state, src, type); } /******************************************************************************/ /* ACTIVE state. */ /******************************************************************************/ case NN_STCP_STATE_ACTIVE: switch (src) { case NN_STCP_SRC_USOCK: switch (type) { case NN_USOCK_SENT: /* The message is now fully sent. */ nn_assert (stcp->outstate == NN_STCP_OUTSTATE_SENDING); stcp->outstate = NN_STCP_OUTSTATE_IDLE; nn_msg_term (&stcp->outmsg); nn_msg_init (&stcp->outmsg, 0); nn_pipebase_sent (&stcp->pipebase); return; case NN_USOCK_RECEIVED: switch (stcp->instate) { case NN_STCP_INSTATE_HDR: /* Message header was received. Allocate memory for the message. */ size = nn_getll (stcp->inhdr); nn_msg_term (&stcp->inmsg); nn_msg_init (&stcp->inmsg, (size_t) size); /* Special case when size of the message body is 0. */ if (!size) { stcp->instate = NN_STCP_INSTATE_HASMSG; nn_pipebase_received (&stcp->pipebase); return; } /* Start receiving the message body. */ stcp->instate = NN_STCP_INSTATE_BODY; nn_usock_recv (stcp->usock, nn_chunkref_data (&stcp->inmsg.body), (size_t) size); return; case NN_STCP_INSTATE_BODY: /* Message body was received. Notify the owner that it can receive it. */ stcp->instate = NN_STCP_INSTATE_HASMSG; nn_pipebase_received (&stcp->pipebase); return; default: nn_fsm_error("Unexpected socket instate", stcp->state, src, type); } case NN_USOCK_SHUTDOWN: nn_pipebase_stop (&stcp->pipebase); stcp->state = NN_STCP_STATE_SHUTTING_DOWN; return; case NN_USOCK_ERROR: nn_pipebase_stop (&stcp->pipebase); stcp->state = NN_STCP_STATE_DONE; nn_fsm_raise (&stcp->fsm, &stcp->done, NN_STCP_ERROR); return; default: nn_fsm_bad_action (stcp->state, src, type); } default: nn_fsm_bad_source (stcp->state, src, type); } /******************************************************************************/ /* SHUTTING_DOWN state. */ /* The underlying connection is closed. We are just waiting that underlying */ /* usock being closed */ /******************************************************************************/ case NN_STCP_STATE_SHUTTING_DOWN: switch (src) { case NN_STCP_SRC_USOCK: switch (type) { case NN_USOCK_ERROR: stcp->state = NN_STCP_STATE_DONE; nn_fsm_raise (&stcp->fsm, &stcp->done, NN_STCP_ERROR); return; default: nn_fsm_bad_action (stcp->state, src, type); } default: nn_fsm_bad_source (stcp->state, src, type); } /******************************************************************************/ /* DONE state. */ /* The underlying connection is closed. There's nothing that can be done in */ /* this state except stopping the object. */ /******************************************************************************/ case NN_STCP_STATE_DONE: nn_fsm_bad_source (stcp->state, src, type); /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_fsm_bad_state (stcp->state, src, type); } }