void nn_streamhdr_start (struct nn_streamhdr *self, struct nn_usock *usock, struct nn_pipebase *pipebase) { size_t sz; int protocol; /* Take ownership of the underlying socket. */ nn_assert (self->usock == NULL && self->usock_owner.fsm == NULL); self->usock_owner.src = NN_STREAMHDR_SRC_USOCK; self->usock_owner.fsm = &self->fsm; nn_usock_swap_owner (usock, &self->usock_owner); self->usock = usock; self->pipebase = pipebase; /* Get the protocol identifier. */ sz = sizeof (protocol); nn_pipebase_getopt (pipebase, NN_SOL_SOCKET, NN_PROTOCOL, &protocol, &sz); nn_assert (sz == sizeof (protocol)); /* Compose the protocol header. */ memcpy (self->protohdr, "\0SP\0\0\0\0\0", 8); nn_puts (self->protohdr + 4, (uint16_t) protocol); /* Launch the state machine. */ nn_fsm_start (&self->fsm); }
void nn_pipe_getopt (struct nn_pipe *self, int level, int option, void *optval, size_t *optvallen) { struct nn_pipebase *pipebase; pipebase = (struct nn_pipebase*) self; nn_pipebase_getopt (pipebase, level, option, optval, optvallen); }
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); } }