예제 #1
0
파일: stream.c 프로젝트: Droppe/nanomsg
void nn_stream_init (struct nn_stream *self, struct nn_epbase *epbase,
    struct nn_usock *usock)
{
    int rc;
    int protocol;
    size_t sz;
    struct nn_iobuf iobuf;

    /*  Redirect the underlying socket's events to this state machine. */
    self->usock = usock;
    self->sink = &nn_stream_state_start;
    self->original_sink = nn_usock_setsink (usock, &self->sink);

    /*  Initialise the pipe to communicate with the user. */
    rc = nn_pipebase_init (&self->pipebase, &nn_stream_pipebase_vfptr, epbase);
    nn_assert (rc == 0);

    nn_msg_init (&self->inmsg, 0);
    nn_msg_init (&self->outmsg, 0);

    /*  Start the header timeout timer. */
    nn_timer_init (&self->hdr_timeout, &self->sink, usock->cp);
    nn_timer_start (&self->hdr_timeout, 1000);

    /*  Send the protocol header. */
    sz = sizeof (protocol);
    nn_epbase_getopt (epbase, NN_SOL_SOCKET, NN_PROTOCOL, &protocol, &sz);
    errnum_assert (rc == 0, -rc);
    nn_assert (sz == sizeof (protocol));
    memcpy (self->protohdr, "\0\0SP\0\0\0\0", 8);
    nn_puts (self->protohdr + 4, (uint16_t) protocol);
    iobuf.iov_base = self->protohdr;
    iobuf.iov_len = 8;
    nn_usock_send (usock, &iobuf, 1);
}
예제 #2
0
void nn_req_init (struct nn_req *self,
    const struct nn_sockbase_vfptr *vfptr, void *hint)
{
    nn_req_handle hndl;

    nn_xreq_init (&self->xreq, vfptr, hint);
    nn_fsm_init_root (&self->fsm, nn_req_handler, nn_req_shutdown,
        nn_sockbase_getctx (&self->xreq.sockbase));
    self->state = NN_REQ_STATE_IDLE;

    /*  Start assigning request IDs beginning with a random number. This way
        there should be no key clashes even if the executable is re-started. */
    nn_random_generate (&self->lastid, sizeof (self->lastid));

    self->task.sent_to = NULL;

    nn_msg_init (&self->task.request, 0);
    nn_msg_init (&self->task.reply, 0);
    nn_timer_init (&self->task.timer, NN_REQ_SRC_RESEND_TIMER, &self->fsm);
    self->resend_ivl = NN_REQ_DEFAULT_RESEND_IVL;

    /*  For now, handle is empty. */
    memset (&hndl, 0, sizeof (hndl));
    nn_task_init (&self->task, self->lastid, hndl);

    /*  Start the state machine. */
    nn_fsm_start (&self->fsm);
}
예제 #3
0
void nn_stcp_init(struct nn_stcp *self,int32_t src,struct nn_epbase *epbase,struct nn_fsm *owner)
{
    nn_fsm_init(&self->fsm,nn_stcp_handler,nn_stcp_shutdown,src,self,owner);
    self->state = NN_STCP_STATE_IDLE;
    nn_streamhdr_init(&self->streamhdr,NN_STCP_SRC_STREAMHDR,&self->fsm);
    self->usock = NULL;
    self->usock_owner.src = -1;
    self->usock_owner.fsm = NULL;
    nn_pipebase_init(&self->pipebase,&nn_stcp_pipebase_vfptr,epbase);
    self->instate = -1;
    nn_msg_init(&self->inmsg,0);
    self->outstate = -1;
    nn_msg_init(&self->outmsg,0);
    nn_fsm_event_init(&self->done);
}
예제 #4
0
파일: stream.c 프로젝트: Droppe/nanomsg
static void nn_stream_received (const struct nn_cp_sink **self,
    struct nn_usock *usock)
{
    struct nn_stream *stream;
    uint64_t size;

    stream = nn_cont (self, struct nn_stream, sink);
    switch (stream->instate) {
    case NN_STREAM_INSTATE_HDR:
        size = nn_getll (stream->inhdr);
        nn_msg_term (&stream->inmsg);
        nn_msg_init (&stream->inmsg, (size_t) size);
        if (!size) {
            nn_pipebase_received (&stream->pipebase);
            break;
        }
        stream->instate = NN_STREAM_INSTATE_BODY;
        nn_usock_recv (stream->usock, nn_chunkref_data (&stream->inmsg.body),
            (size_t) size);
        break;
    case NN_STREAM_INSTATE_BODY:
        nn_pipebase_received (&stream->pipebase);
        break;
    default:
        nn_assert (0);
    }
}
예제 #5
0
파일: stream.c 프로젝트: Droppe/nanomsg
static void nn_stream_sent (const struct nn_cp_sink **self,
    struct nn_usock *usock)
{
    struct nn_stream *stream;

    stream = nn_cont (self, struct nn_stream, sink);
    nn_pipebase_sent (&stream->pipebase);
    nn_msg_term (&stream->outmsg);
    nn_msg_init (&stream->outmsg, 0);
}
예제 #6
0
static int32_t nn_stcp_recv(struct nn_pipebase *self,struct nn_msg *msg)
{
    struct nn_stcp *stcp;
    stcp = nn_cont(self,struct nn_stcp, pipebase);
    nn_assert_state(stcp, NN_STCP_STATE_ACTIVE);
    nn_assert(stcp->instate == NN_STCP_INSTATE_HASMSG);
    nn_msg_mv(msg,&stcp->inmsg); // Move received message to the user
    nn_msg_init(&stcp->inmsg,0);
    stcp->instate = NN_STCP_INSTATE_HDR; // Start receiving new message
    nn_usock_recv(stcp->usock,stcp->inhdr,sizeof(stcp->inhdr),NULL);
    return 0;
}
예제 #7
0
파일: global.c 프로젝트: kaostao/nanomsg
int nn_send (int s, const void *buf, size_t len, int flags)
{
    int rc;
    struct nn_msg msg;
    void *chunk;
    int nnmsg;

    NN_BASIC_CHECKS;

    if (nn_slow (!buf && len)) {
        errno = EFAULT;
        return -1;
    }

    /*  Create a message object. */
    if (len == NN_MSG) {
        chunk = *(void**) buf;
        if (nn_slow (chunk == NULL)) {
            errno = EFAULT;
            return -1;
        }
        len = nn_chunk_size (chunk);
        nn_msg_init_chunk (&msg, chunk);
        nnmsg = 1;
    }
    else {
        nn_msg_init (&msg, len);
        memcpy (nn_chunkref_data (&msg.body), buf, len);
        nnmsg = 0;
    }

    /*  Send it further down the stack. */
    rc = nn_sock_send (self.socks [s], &msg, flags);
    if (nn_slow (rc < 0)) {

        /*  If we are dealing with user-supplied buffer, detach it from
            the message object. */
        if (nnmsg)
            nn_chunkref_init (&msg.body, 0);

        nn_msg_term (&msg);
        errno = -rc;
        return -1;
    }
    nn_sock_stat_increment (self.socks [s], NN_STAT_MESSAGES_SENT, 1);
    nn_sock_stat_increment (self.socks [s], NN_STAT_BYTES_SENT, len);

    return (int) len;
}
예제 #8
0
파일: stream.c 프로젝트: Droppe/nanomsg
static int nn_stream_recv (struct nn_pipebase *self, struct nn_msg *msg)
{
    struct nn_stream *stream;

    stream = nn_cont (self, struct nn_stream, pipebase);

    /*  Move message content to the user-supplied structure. */
    nn_msg_mv (msg, &stream->inmsg);
    nn_msg_init (&stream->inmsg, 0);

    /* Start receiving new message. */ 
    stream->instate = NN_STREAM_INSTATE_HDR;
    nn_usock_recv (stream->usock, stream->inhdr, 8);

    return 0;
}
예제 #9
0
static int nn_slibfabric_recv (struct nn_pipebase *self, struct nn_msg *msg)
{
    struct nn_slibfabric *slibfabric;

    slibfabric = nn_cont (self, struct nn_slibfabric, pipebase);

    nn_assert_state (slibfabric, NN_SLIBFABRIC_STATE_ACTIVE);
    nn_assert (slibfabric->instate == NN_SLIBFABRIC_INSTATE_HASMSG);

    /*  Move received message to the user. */
    nn_msg_mv (msg, &slibfabric->inmsg);
    nn_msg_init (&slibfabric->inmsg, 0);

    /*  Start receiving new message. */
    slibfabric->instate = NN_SLIBFABRIC_INSTATE_HDR;
    nn_usock_recv (slibfabric->usock, slibfabric->inhdr, sizeof (slibfabric->inhdr), NULL);

    return 0;
}
예제 #10
0
파일: sipc.c 프로젝트: CPB9/nanomsg
static int nn_sipc_recv (struct nn_pipebase *self, struct nn_msg *msg)
{
    struct nn_sipc *sipc;

    sipc = nn_cont (self, struct nn_sipc, pipebase);

    nn_assert_state (sipc, NN_SIPC_STATE_ACTIVE);
    nn_assert (sipc->instate == NN_SIPC_INSTATE_HASMSG);

    /*  Move received message to the user. */
    nn_msg_mv (msg, &sipc->inmsg);
    nn_msg_init (&sipc->inmsg, 0);

    /*  Start receiving new message. */
    sipc->instate = NN_SIPC_INSTATE_HDR;
    nn_usock_recv (sipc->usock, sipc->inhdr, sizeof (sipc->inhdr));

    return 0;
}
예제 #11
0
파일: surveyor.c 프로젝트: tpopen/nanomsg
static void nn_surveyor_init (struct nn_surveyor *self,
    const struct nn_sockbase_vfptr *vfptr, void *hint)
{
    nn_xsurveyor_init (&self->xsurveyor, vfptr, hint);
    nn_fsm_init_root (&self->fsm, nn_surveyor_handler,
        nn_sockbase_getctx (&self->xsurveyor.sockbase));
    self->state = NN_SURVEYOR_STATE_IDLE;

    /*  Start assigning survey IDs beginning with a random number. This way
        there should be no key clashes even if the executable is re-started. */
    nn_random_generate (&self->surveyid, sizeof (self->surveyid));

    nn_timer_init (&self->timer, NN_SURVEYOR_SRC_DEADLINE_TIMER, &self->fsm);
    nn_msg_init (&self->tosend, 0);
    self->deadline = NN_SURVEYOR_DEFAULT_DEADLINE;

    /*  Start the state machine. */
    nn_fsm_start (&self->fsm);
}
예제 #12
0
파일: ctx.c 프로젝트: jjrdn/nanomsg
int nn_send (int s, const void *buf, size_t len, int flags)
{
    int rc;
    struct nn_msg msg;
    struct nn_chunk *ch;

    NN_BASIC_CHECKS;

#if defined NN_LATENCY_MONITOR
    nn_latmon_measure (NN_LATMON_SEND);
#endif

    if (nn_slow (!buf && len)) {
        errno = EFAULT;
        return -1;
    }

    /*  Create a message object. */
    if (len == NN_MSG) {
        ch = nn_chunk_from_data (*(void**) buf);
        if (nn_slow (ch == NULL)) {
            errno = EFAULT;
            return -1;
        }
        len = nn_chunk_size (ch);
        nn_msg_init_chunk (&msg, ch);
    }
    else {
        nn_msg_init (&msg, len);
        memcpy (nn_chunkref_data (&msg.body), buf, len);
    }

    /*  Send it further down the stack. */
    rc = nn_sock_send (self.socks [s], &msg, flags);
    if (nn_slow (rc < 0)) {
        nn_msg_term (&msg);
        errno = -rc;
        return -1;
    }

    return (int) len;
}
예제 #13
0
파일: sws.c 프로젝트: threatstack/nanomsg
void nn_sws_init (struct nn_sws *self, int src,
    struct nn_epbase *epbase, struct nn_fsm *owner)
{
    nn_fsm_init (&self->fsm, nn_sws_handler, nn_sws_shutdown,
        src, self, owner);
    self->state = NN_SWS_STATE_IDLE;
    nn_wshdr_init (&self->wshdr, NN_SWS_SRC_HANDSHAKE, &self->fsm);
    self->usock = NULL;
    self->usock_owner.src = -1;
    self->usock_owner.fsm = NULL;
    nn_pipebase_init (&self->pipebase, &nn_sws_pipebase_vfptr, epbase);
    self->instate = -1;
    nn_list_init (&self->inmsg_array);
    self->outstate = -1;
    nn_msg_init (&self->outmsg, 0);

    self->continuing = 0;

    nn_fsm_event_init (&self->done);
}
예제 #14
0
static int nn_surveyor_send (struct nn_sockbase *self, struct nn_msg *msg)
{
    struct nn_surveyor *surveyor;

    surveyor = nn_cont (self, struct nn_surveyor, xsurveyor.sockbase);

    /*  Generate new survey ID. */
    ++surveyor->surveyid;
    surveyor->surveyid |= 0x80000000;

    /*  Tag the survey body with survey ID. */
    nn_assert (nn_chunkref_size (&msg->sphdr) == 0);
    nn_chunkref_term (&msg->sphdr);
    nn_chunkref_init (&msg->sphdr, 4);
    nn_putl (nn_chunkref_data (&msg->sphdr), surveyor->surveyid);

    /*  Store the survey, so that it can be sent later on. */
    nn_msg_term (&surveyor->tosend);
    nn_msg_mv (&surveyor->tosend, msg);
    nn_msg_init (msg, 0);

    /*  Cancel any ongoing survey, if any. */
    if (nn_slow (nn_surveyor_inprogress (surveyor))) {

        /*  First check whether the survey can be sent at all. */
        if (!(nn_xsurveyor_events (&surveyor->xsurveyor.sockbase) &
              NN_SOCKBASE_EVENT_OUT))
            return -EAGAIN;

        /*  Cancel the current survey. */
        nn_fsm_action (&surveyor->fsm, NN_SURVEYOR_ACTION_CANCEL);

        return 0;
    }

    /*  Notify the state machine that the survey was started. */
    nn_fsm_action (&surveyor->fsm, NN_SURVEYOR_ACTION_START);

    return 0;
}
예제 #15
0
파일: global.c 프로젝트: Amaury/AngstromDB
int nn_send (int s, const void *buf, size_t len, int flags)
{
    int rc;
    struct nn_msg msg;
    void *chunk;

    NN_BASIC_CHECKS;

    if (nn_slow (!buf && len)) {
        errno = EFAULT;
        return -1;
    }

    /*  Create a message object. */
    if (len == NN_MSG) {
        chunk = *(void**) buf;
        if (nn_slow (chunk == NULL)) {
            errno = EFAULT;
            return -1;
        }
        len = nn_chunk_size (chunk);
        nn_msg_init_chunk (&msg, chunk);
    }
    else {
        nn_msg_init (&msg, len);
        memcpy (nn_chunkref_data (&msg.body), buf, len);
    }

    /*  Send it further down the stack. */
    rc = nn_sock_send (self.socks [s], &msg, flags);
    if (nn_slow (rc < 0)) {
        nn_msg_term (&msg);
        errno = -rc;
        return -1;
    }

    return (int) len;
}
예제 #16
0
파일: req.c 프로젝트: javarange/nanomsg
static int nn_req_recv (struct nn_sockbase *self, struct nn_msg *msg)
{
    struct nn_req *req;

    req = nn_cont (self, struct nn_req, xreq.sockbase);

    /*  No request was sent. Waiting for a reply doesn't make sense. */
    if (nn_slow (!nn_req_inprogress (req)))
        return -EFSM;

    /*  If reply was not yet recieved, wait further. */
    if (nn_slow (req->state != NN_REQ_STATE_DONE))
        return -EAGAIN;

    /*  If the reply was already received, just pass it to the caller. */
    nn_msg_mv (msg, &req->reply);
    nn_msg_init (&req->reply, 0);

    /*  Notify the state machine. */
    nn_fsm_action (&req->fsm, NN_REQ_ACTION_RECEIVED);

    return 0;
}
예제 #17
0
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);
    }
}
예제 #18
0
파일: stcp.c 프로젝트: 4Second2None/nanomsg
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);
    }
}
예제 #19
0
파일: sws.c 프로젝트: threatstack/nanomsg
static void nn_sws_handler (struct nn_fsm *self, int src, int type,
    NN_UNUSED void *srcptr)
{
    struct nn_sws *sws;
    int rc;

    sws = nn_cont (self, struct nn_sws, fsm);

    switch (sws->state) {

/******************************************************************************/
/*  IDLE state.                                                               */
/******************************************************************************/
    case NN_SWS_STATE_IDLE:
        switch (src) {

        case NN_FSM_ACTION:
            switch (type) {
            case NN_FSM_START:
                nn_wshdr_start (&sws->wshdr, sws->usock,
                    &sws->pipebase, sws->mode, sws->remote_host);
                sws->state = NN_SWS_STATE_HANDSHAKE;
                return;
            default:
                nn_fsm_bad_action (sws->state, src, type);
            }

        default:
            nn_fsm_bad_source (sws->state, src, type);
        }

/******************************************************************************/
/*  HANDSHAKE state.                                                          */
/******************************************************************************/
    case NN_SWS_STATE_HANDSHAKE:
        switch (src) {

        case NN_SWS_SRC_HANDSHAKE:
            switch (type) {
            case NN_WSHDR_OK:

                /*  Before moving to the active state stop the handshake
                    state machine. */
                nn_wshdr_stop (&sws->wshdr);
                sws->state = NN_SWS_STATE_STOPPING_HANDSHAKE;
                return;

            case NN_WSHDR_ERROR:

                /* Raise the error and move directly to the DONE state.
                   wshdr object will be stopped later on. */
                sws->state = NN_SWS_STATE_DONE;
                nn_fsm_raise (&sws->fsm, &sws->done,
                    NN_SWS_RETURN_CLOSE_HANDSHAKE);
                return;

            default:
                nn_fsm_bad_action (sws->state, src, type);
            }

        default:
            nn_fsm_bad_source (sws->state, src, type);
        }

/******************************************************************************/
/*  STOPPING_HANDSHAKE state.                                                 */
/******************************************************************************/
    case NN_SWS_STATE_STOPPING_HANDSHAKE:
        switch (src) {

        case NN_SWS_SRC_HANDSHAKE:
            switch (type) {
            case NN_WSHDR_STOPPED:

                 /*  Start the pipe. */
                 rc = nn_pipebase_start (&sws->pipebase);
                 if (nn_slow (rc < 0)) {
                    sws->state = NN_SWS_STATE_DONE;
                    nn_fsm_raise (&sws->fsm, &sws->done, NN_SWS_RETURN_ERROR);
                    return;
                 }

                 /*  Start receiving a message in asynchronous manner. */
                 nn_sws_recv_hdr (sws);

                 /*  Mark the pipe as available for sending. */
                 sws->outstate = NN_SWS_OUTSTATE_IDLE;

                 sws->state = NN_SWS_STATE_ACTIVE;
                 return;

            default:
                nn_fsm_bad_action (sws->state, src, type);
            }

        default:
            nn_fsm_bad_source (sws->state, src, type);
        }

/******************************************************************************/
/*  ACTIVE state.                                                             */
/******************************************************************************/
    case NN_SWS_STATE_ACTIVE:
        switch (src) {

        case NN_SWS_SRC_USOCK:
            switch (type) {
            case NN_USOCK_SENT:

                /*  The message is now fully sent. */
                nn_assert (sws->outstate == NN_SWS_OUTSTATE_SENDING);
                sws->outstate = NN_SWS_OUTSTATE_IDLE;
                nn_msg_term (&sws->outmsg);
                nn_msg_init (&sws->outmsg, 0);
                nn_pipebase_sent (&sws->pipebase);
                return;

            case NN_USOCK_RECEIVED:

                switch (sws->instate) {
                case NN_SWS_INSTATE_RECV_HDR:

                    /*  Require RSV1, RSV2, and RSV3 bits to be unset for
                        as per RFC 6455 section 5.2. */
                    if (sws->inhdr [0] & NN_SWS_FRAME_BITMASK_RSV1 ||
                        sws->inhdr [0] & NN_SWS_FRAME_BITMASK_RSV2 ||
                        sws->inhdr [0] & NN_SWS_FRAME_BITMASK_RSV3) {
                        nn_sws_fail_conn (sws, NN_SWS_CLOSE_ERR_PROTO,
                            "RSV1, RSV2, and RSV3 must be unset.");
                        return;
                    }

                    sws->is_final_frame = sws->inhdr [0] &
                        NN_SWS_FRAME_BITMASK_FIN;
     
                    /*  Communication from client to server must be masked.
                        Communication from server to client must be unmasked. */
                    if (sws->mode == NN_WS_SERVER) {
                        nn_assert (sws->inhdr [1] &
                            NN_SWS_FRAME_BITMASK_MASKED);
                        sws->ext_hdr_len = 4;
                    }
                    else {
                        nn_assert (!(sws->inhdr [1] &
                            NN_SWS_FRAME_BITMASK_MASKED));
                        sws->ext_hdr_len = 0;
                    }

                    sws->opcode = sws->inhdr [0] &
                        NN_SWS_FRAME_BITMASK_OPCODE;
                    sws->payload_ctl = sws->inhdr [1] &
                        NN_SWS_FRAME_BITMASK_LENGTH;

                    /*  Prevent unexpected continuation frame. */
                    if (!sws->continuing &&
                        sws->opcode == NN_WS_OPCODE_FRAGMENT) {
                        nn_sws_fail_conn (sws, NN_SWS_CLOSE_ERR_PROTO,
                            "No message to continue.");
                        return;
                    }

                    /*  Preserve initial message opcode and RSV bits in case
                        this is a fragmented message. */
                    if (!sws->continuing)
                        sws->inmsg_hdr = sws->inhdr [0] |
                        NN_SWS_FRAME_BITMASK_FIN;

                    if (sws->payload_ctl <= 0x7d) {
                        sws->ext_hdr_len += NN_SWS_FRAME_SIZE_PAYLOAD_0;
                    }
                    else if (sws->payload_ctl <= 0xffff) {
                        sws->ext_hdr_len += NN_SWS_FRAME_SIZE_PAYLOAD_16;
                    }
                    else {
                        sws->ext_hdr_len += NN_SWS_FRAME_SIZE_PAYLOAD_63;
                    }

                    switch (sws->opcode) {

                    case NN_WS_OPCODE_BINARY:

                        sws->is_control_frame = 0;

                        if (sws->continuing) {
                            nn_sws_fail_conn (sws, NN_SWS_CLOSE_ERR_PROTO,
                                "Expected continuation frame opcode.");
                            return;
                        }

                        if (!sws->is_final_frame)
                            sws->continuing = 1;

                        if (sws->ext_hdr_len == 0 && sws->payload_ctl == 0) {
                            /*  Only a remote server could send a 2-byte msg;
                                sanity-check that this endpoint is a client. */
                            nn_assert (sws->mode == NN_WS_CLIENT);

                            sws->inmsg_current_chunk_len = 0;

                            if (sws->continuing) {
                                /*  This frame was empty, but continue
                                    next frame in fragmented sequence. */
                                nn_sws_recv_hdr (sws);
                                return;
                            }
                            else {
                                /*  Special case when there is no payload,
                                    mask, or additional frames. */
                                sws->instate = NN_SWS_INSTATE_RECVD_CHUNKED;
                                nn_pipebase_received (&sws->pipebase);
                                return;
                            }
                            }
                        /*  Continue to receive extended header+payload. */
                        break;

                    case NN_WS_OPCODE_FRAGMENT:

                        sws->is_control_frame = 0;
                        sws->continuing = !sws->is_final_frame;

                        if (sws->ext_hdr_len == 0 && sws->payload_ctl == 0) {
                            /*  Only a remote server could send a 2-byte msg;
                                sanity-check that this endpoint is a client. */
                            nn_assert (sws->mode == NN_WS_CLIENT);

                            sws->inmsg_current_chunk_len = 0;

                            if (sws->continuing) {
                                /*  This frame was empty, but continue
                                    next frame in fragmented sequence. */
                                nn_sws_recv_hdr (sws);
                                return;
                            }
                            else {
                                /*  Special case when there is no payload,
                                    mask, or additional frames. */
                                sws->instate = NN_SWS_INSTATE_RECVD_CHUNKED;
                                nn_pipebase_received (&sws->pipebase);
                                return;
                            }
                        }
                        /*  Continue to receive extended header+payload. */
                        break;
                    
                    case NN_WS_OPCODE_CLOSE:
                        /*  RFC 6455 section 5.5.1. */
                        sws->is_control_frame = 1;
                        if (!sws->is_final_frame) {
                            /*  As per RFC 6455 section 5.4, fragmentation of
                                control frames is not allowed; on receipt the
                                endpoint MUST close connection immediately. */
                            nn_sws_fail_conn (sws, NN_SWS_CLOSE_ERR_PROTO,
                                "Cannot fragment control message (FIN=0).");
                            return;
                        }

                        if (sws->payload_ctl > NN_SWS_MAX_SMALL_PAYLOAD) {
                            /*  As per RFC 6455 section 5.4, large payloads on
                                control frames is not allowed, and on receipt
                                the endpoint MUST close connection
                                immediately. */
                            nn_sws_fail_conn (sws, NN_SWS_CLOSE_ERR_PROTO,
                                "Control frame payload exceeds allowable length.");
                            return;
                        }

                        if (sws->payload_ctl == 1) {
                            /*  As per RFC 6455 section 5.5.1, if a payload is
                                to accompany a close frame, the first two bytes
                                MUST be the close code. */
                            nn_sws_fail_conn (sws, NN_SWS_CLOSE_ERR_PROTO,
                                "Expected 2byte close code.");
                            return;
                        }

                        if (sws->ext_hdr_len == 0 && sws->payload_ctl == 0) {
                            /*  Special case when there is no payload,
                                mask, or additional frames. */
                            sws->inmsg_current_chunk_len = 0;
                            sws->instate = NN_SWS_INSTATE_RECVD_CONTROL;
                            nn_pipebase_received (&sws->pipebase);
                            return;
                        }
                        /*  Continue to receive extended header+payload. */
                        break;
                    
                    default:
                        /*  Client sent an invalid opcode; as per RFC 6455
                            section 10.7, close connection with code. */
                        nn_sws_fail_conn (sws, NN_SWS_CLOSE_ERR_PROTO,
                                "Invalid opcode.");
                        return;

                    }

                    if (sws->ext_hdr_len == 0) {
                        /*  Only a remote server could send a 2-byte msg;
                            sanity-check that this endpoint is a client. */
                        nn_assert (sws->mode == NN_WS_CLIENT);

                        /*  In the case of no additional header, the payload
                            is known to not exceed this threshold. */
                        nn_assert (sws->payload_ctl <= 0x7d);

                        /*  In the case of no additional header, the payload
                            is known to not exceed this threshold. */
                        nn_assert (sws->payload_ctl > 0);

                        sws->instate = NN_SWS_INSTATE_RECV_PAYLOAD;
                        sws->inmsg_current_chunk_len = sws->payload_ctl;


                        /*  Use scatter/gather array for application messages,
                            and a fixed-width buffer for control messages. This
                            is convenient since control messages can be
                            interspersed between chunked application msgs. */
                        if (sws->is_control_frame) {
                            sws->inmsg_current_chunk_buf = sws->inmsg_control;
                        }
                        else {
                            sws->inmsg_chunks++;
                            sws->inmsg_total_size += sws->inmsg_current_chunk_len;
                            sws->inmsg_current_chunk_buf =
                                nn_msg_chunk_new (sws->inmsg_current_chunk_len,
                                &sws->inmsg_array);
                        }

                        nn_usock_recv (sws->usock, sws->inmsg_current_chunk_buf,
                            sws->inmsg_current_chunk_len, NULL);
                        return;
                    }
                    else {
                        /*  Continue receiving the rest of the header frame. */
                        sws->instate = NN_SWS_INSTATE_RECV_HDREXT;
                        nn_usock_recv (sws->usock,
                            sws->inhdr + NN_SWS_FRAME_SIZE_INITIAL,
                            sws->ext_hdr_len,
                            NULL);
                        return;
                    }

                case NN_SWS_INSTATE_RECV_HDREXT:
                    nn_assert (sws->ext_hdr_len > 0);

                    if (sws->payload_ctl <= 0x7d) {
                        sws->inmsg_current_chunk_len = sws->payload_ctl;
                        if (sws->mode == NN_WS_SERVER) {
                            memcpy (sws->mask,
                               sws->inhdr + NN_SWS_FRAME_SIZE_INITIAL, 4);
                        }
                    }
                    else if (sws->payload_ctl == 0xffff) {
                        sws->inmsg_current_chunk_len =
                            nn_gets (sws->inhdr + NN_SWS_FRAME_SIZE_INITIAL);
                        if (sws->mode == NN_WS_SERVER) {
                            memcpy (sws->mask, sws->inhdr +
                                NN_SWS_FRAME_SIZE_INITIAL +
                                NN_SWS_FRAME_SIZE_PAYLOAD_16, 4);
                        }
                    }
                    else {
                        sws->inmsg_current_chunk_len =
                            (size_t) nn_getll (sws->inhdr +
                            NN_SWS_FRAME_SIZE_INITIAL);
                        if (sws->mode == NN_WS_SERVER) {
                            memcpy (sws->mask, sws->inhdr +
                                NN_SWS_FRAME_SIZE_INITIAL +
                                NN_SWS_FRAME_SIZE_PAYLOAD_63, 4);
                        }
                    }

                    /*  Handle zero-length message bodies. */
                    if (sws->inmsg_current_chunk_len == 0)
                    {
                        if (sws->is_final_frame) {
                            sws->instate = (sws->is_control_frame ?
                                NN_SWS_INSTATE_RECVD_CONTROL :
                                NN_SWS_INSTATE_RECVD_CHUNKED);
                            nn_pipebase_received (&sws->pipebase);
                            return;
                        }
                        else {
                            nn_sws_recv_hdr (sws);
                            return;
                        }
                    }

                    nn_assert (sws->inmsg_current_chunk_len > 0);

                    /*  Use scatter/gather array for application messages,
                        and a fixed-width buffer for control messages. This
                        is convenient since control messages can be
                        interspersed between chunked application msgs. */
                    if (sws->is_control_frame) {
                        sws->inmsg_current_chunk_buf = sws->inmsg_control;
                    }
                    else {
                        sws->inmsg_chunks++;
                        sws->inmsg_total_size += sws->inmsg_current_chunk_len;
                        sws->inmsg_current_chunk_buf =
                            nn_msg_chunk_new (sws->inmsg_current_chunk_len,
                            &sws->inmsg_array);
                    }

                    sws->instate = NN_SWS_INSTATE_RECV_PAYLOAD;
                    nn_usock_recv (sws->usock, sws->inmsg_current_chunk_buf,
                        sws->inmsg_current_chunk_len, NULL);
                    return;

                case NN_SWS_INSTATE_RECV_PAYLOAD:

                    /*  Unmask if necessary. */
                    if (sws->mode == NN_WS_SERVER) {
                        nn_sws_mask_payload (sws->inmsg_current_chunk_buf,
                            sws->inmsg_current_chunk_len, sws->mask, NULL);
                    }

                    switch (sws->opcode) {

                    case NN_WS_OPCODE_BINARY:
                    case NN_WS_OPCODE_FRAGMENT:
                        if (sws->is_final_frame) {
                            sws->instate = NN_SWS_INSTATE_RECVD_CHUNKED;
                            nn_pipebase_received (&sws->pipebase);
                        }
                        else {
                            nn_sws_recv_hdr (sws);
                        }
                        return;

                    case NN_WS_OPCODE_CLOSE:

                        /*  If the payload is not even long enough for the
                            required 2-octet Close Code, the connection
                            should have been failed upstream. */
                        nn_assert (sws->inmsg_current_chunk_len >= 2);
                        
                        nn_sws_validate_close_handshake (sws);
                        return;

                    default:
                        /*  This should have been prevented upstream. */
                        nn_assert (0);
                        return;
                    } 

                default:
                    nn_fsm_error ("Unexpected socket instate",
                        sws->state, src, type);
                }

            case NN_USOCK_SHUTDOWN:
                nn_pipebase_stop (&sws->pipebase);
                sws->state = NN_SWS_STATE_BROKEN_CONNECTION;
                return;

            case NN_USOCK_ERROR:
                nn_pipebase_stop (&sws->pipebase);
                sws->state = NN_SWS_STATE_DONE;
                nn_fsm_raise (&sws->fsm, &sws->done, NN_SWS_RETURN_ERROR);
                return;

            default:
                nn_fsm_bad_action (sws->state, src, type);
            }

            break;

        default:
            nn_fsm_bad_source (sws->state, src, type);
        }

/******************************************************************************/
/*  CLOSING_CONNECTION state.                                                 */
/*  Wait for acknowledgement closing handshake was successfully sent.         */
/******************************************************************************/
    case NN_SWS_STATE_CLOSING_CONNECTION:
        switch (src) {

        case NN_SWS_SRC_USOCK:
            switch (type) {
            case NN_USOCK_SENT:
                /*  Wait for acknowledgement closing handshake was sent
                    to peer. */
                nn_assert (sws->outstate == NN_SWS_OUTSTATE_SENDING);
                sws->outstate = NN_SWS_OUTSTATE_IDLE;
                sws->state = NN_SWS_STATE_DONE;
                nn_fsm_raise (&sws->fsm, &sws->done,
                    NN_SWS_RETURN_CLOSE_HANDSHAKE);
                return;
            case NN_USOCK_SHUTDOWN:
                return;
            case NN_USOCK_ERROR:
                sws->state = NN_SWS_STATE_DONE;
                nn_fsm_raise (&sws->fsm, &sws->done, NN_SWS_RETURN_ERROR);
                return;
            default:
                nn_fsm_bad_action (sws->state, src, type);
            }

        default:
            nn_fsm_bad_source (sws->state, src, type);
        }

/******************************************************************************/
/*  SHUTTING_DOWN state.                                                      */
/*  The underlying connection is closed. We are just waiting that underlying  */
/*  usock being closed                                                        */
/******************************************************************************/
    case NN_SWS_STATE_BROKEN_CONNECTION:
        switch (src) {

        case NN_SWS_SRC_USOCK:
            switch (type) {
            case NN_USOCK_ERROR:
                sws->state = NN_SWS_STATE_DONE;
                nn_fsm_raise (&sws->fsm, &sws->done, NN_SWS_RETURN_ERROR);
                return;
            default:
                nn_fsm_bad_action (sws->state, src, type);
            }

        default:
            nn_fsm_bad_source (sws->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_SWS_STATE_DONE:
        nn_fsm_bad_source (sws->state, src, type);

/******************************************************************************/
/*  Invalid state.                                                            */
/******************************************************************************/
    default:
        nn_fsm_bad_state (sws->state, src, type);
    }
}
예제 #20
0
파일: sws.c 프로젝트: threatstack/nanomsg
static int nn_sws_recv (struct nn_pipebase *self, struct nn_msg *msg)
{
    struct nn_sws *sws;
    struct nn_iovec iov [1];
    struct nn_list_item *it;
    struct msg_chunk *ch;
    int pos;
    size_t len;

    sws = nn_cont (self, struct nn_sws, pipebase);

    nn_assert_state (sws, NN_SWS_STATE_ACTIVE);

    switch (sws->instate) {
    case NN_SWS_INSTATE_FAILING:

        /*  Prevent further send/recv operations on this connection. */
        nn_pipebase_stop (self);
        sws->instate = NN_SWS_INSTATE_CLOSED;

        /*  Inform user this connection has been failed. */
        nn_msg_init (msg, 1);
        *(uint8_t *) nn_chunkref_data (&msg->body) = 0x7f |
            NN_SWS_FRAME_BITMASK_FIN;

        iov [0].iov_base = sws->fail_msg;
        iov [0].iov_len = sws->fail_msg_len;

        /*  TODO: Consider queueing and unconditionally sending close
            handshake rather than skipping it. */
        /*  RFC 6455 7.1.7 - try to send helpful Closing Handshake only if
            the socket is not currently sending. If it's still busy sending,
            forcibly close this connection, since it's not readily deterministic
            how much time that action could take to complete, or if the peer is
            even healthy enough to receive. Rationale: try to be nice, but be
            mindful of self-preservation! */
        if (sws->outstate == NN_SWS_OUTSTATE_IDLE) {
            nn_usock_send (sws->usock, iov, 1);
            sws->outstate = NN_SWS_OUTSTATE_SENDING;
            sws->state = NN_SWS_STATE_CLOSING_CONNECTION;
        }
        else {
            sws->state = NN_SWS_STATE_DONE;
            nn_fsm_raise (&sws->fsm, &sws->done,
                NN_SWS_RETURN_CLOSE_HANDSHAKE);
        }
        return 0;
    
    case NN_SWS_INSTATE_RECVD_CHUNKED:

        /*  This library should not deliver fragmented messages to the
            application, so it's expected that this is the final frame. */
        nn_assert (sws->is_final_frame);

        len = sws->inmsg_total_size;

        nn_msg_init (msg, len);

        /*  Reassemble incoming message scatter array. */
        while (!nn_list_empty (&sws->inmsg_array)) {
            it = nn_list_begin (&sws->inmsg_array);
            ch = nn_cont (it, struct msg_chunk, item);
            memcpy (((uint8_t*) nn_chunkref_data (&msg->body)) + pos,
                nn_chunkref_data (&ch->chunk),
                nn_chunkref_size (&ch->chunk));
            pos += nn_chunkref_size (&ch->chunk);
            nn_msg_chunk_term (ch, &sws->inmsg_array);
        }

        nn_assert (pos == len);
        nn_assert (nn_list_empty (&sws->inmsg_array));

        /*  No longer collecting scatter array of incoming msg chunks. */
        sws->continuing = 0;

        nn_sws_recv_hdr (sws);

        return 0;

    case NN_SWS_INSTATE_RECVD_CONTROL:

        /*  This library should not deliver fragmented messages to the user, so
        it's expected that this is the final frame. */
        nn_assert (sws->is_final_frame);

        len = sws->inmsg_current_chunk_len + sizeof (sws->inmsg_hdr);

        nn_msg_init (msg, len);

        /*  Relay opcode, RSV and FIN bits to the user in order to
            interpret payload. */
        memcpy (nn_chunkref_data (&msg->body),
            &sws->inhdr, sizeof (sws->inmsg_hdr));
        pos = sizeof (sws->inmsg_hdr);

        memcpy (((uint8_t*) nn_chunkref_data (&msg->body)) + pos,
            sws->inmsg_control, sws->inmsg_current_chunk_len);

        /*  If a closing handshake was just transferred to the application,
            discontinue continual, async receives. */
        if (sws->opcode == NN_WS_OPCODE_CLOSE) {
            sws->instate = NN_SWS_INSTATE_CLOSED;
        }
        else {
            nn_sws_recv_hdr (sws);
        }

        return 0;

    default:
        /*  Unexpected state. */
        nn_assert (0);
        return 0;
    }
}
예제 #21
0
파일: global.c 프로젝트: Amaury/AngstromDB
int nn_sendmsg (int s, const struct nn_msghdr *msghdr, int flags)
{
    int rc;
    size_t sz;
    int i;
    struct nn_iovec *iov;
    struct nn_msg msg;
    void *chunk;

    NN_BASIC_CHECKS;

    if (nn_slow (!msghdr)) {
        errno = EINVAL;
        return -1;
    }

    if (nn_slow (msghdr->msg_iovlen < 0)) {
        errno = EMSGSIZE;
        return -1;
    }

    if (msghdr->msg_iovlen == 1 && msghdr->msg_iov [0].iov_len == NN_MSG) {
        chunk = *(void**) msghdr->msg_iov [0].iov_base;
        if (nn_slow (chunk == NULL)) {
            errno = EFAULT;
            return -1;
        }
        sz = nn_chunk_size (chunk);
        nn_msg_init_chunk (&msg, chunk);
    }
    else {

        /*  Compute the total size of the message. */
        sz = 0;
        for (i = 0; i != msghdr->msg_iovlen; ++i) {
            iov = &msghdr->msg_iov [i];
            if (nn_slow (iov->iov_len == NN_MSG)) {
               errno = EINVAL;
               return -1;
            }
            if (nn_slow (!iov->iov_base && iov->iov_len)) {
                errno = EFAULT;
                return -1;
            }
            if (nn_slow (sz + iov->iov_len < sz)) {
                errno = EINVAL;
                return -1;
            }
            sz += iov->iov_len;
        }

        /*  Create a message object from the supplied scatter array. */
        nn_msg_init (&msg, sz);
        sz = 0;
        for (i = 0; i != msghdr->msg_iovlen; ++i) {
            iov = &msghdr->msg_iov [i];
            memcpy (((uint8_t*) nn_chunkref_data (&msg.body)) + sz,
                iov->iov_base, iov->iov_len);
            sz += iov->iov_len;
        }
    }

    /*  Add ancillary data to the message. */
    if (msghdr->msg_control) {
        if (msghdr->msg_controllen == NN_MSG) {
            chunk = *((void**) msghdr->msg_control);
            nn_chunkref_term (&msg.hdr);
            nn_chunkref_init_chunk (&msg.hdr, chunk);
        }
        else {

            /*  TODO: Copy the control data to the message. */
            nn_assert (0);
        }
    }

    /*  Send it further down the stack. */
    rc = nn_sock_send (self.socks [s], &msg, flags);
    if (nn_slow (rc < 0)) {
        nn_msg_term (&msg);
        errno = -rc;
        return -1;
    }

    return (int) sz;
}
예제 #22
0
파일: global.c 프로젝트: TTimo/nanomsg
int nn_sendmsg (int s, const struct nn_msghdr *msghdr, int flags)
{
    int rc;
    size_t sz;
    size_t spsz;
    int i;
    struct nn_iovec *iov;
    struct nn_msg msg;
    void *chunk;
    int nnmsg;
    struct nn_cmsghdr *cmsg;

    NN_BASIC_CHECKS;

    if (nn_slow (!msghdr)) {
        errno = EINVAL;
        return -1;
    }

    if (nn_slow (msghdr->msg_iovlen < 0)) {
        errno = EMSGSIZE;
        return -1;
    }

    if (msghdr->msg_iovlen == 1 && msghdr->msg_iov [0].iov_len == NN_MSG) {
        chunk = *(void**) msghdr->msg_iov [0].iov_base;
        if (nn_slow (chunk == NULL)) {
            errno = EFAULT;
            return -1;
        }
        sz = nn_chunk_size (chunk);
        nn_msg_init_chunk (&msg, chunk);
        nnmsg = 1;
    }
    else {

        /*  Compute the total size of the message. */
        sz = 0;
        for (i = 0; i != msghdr->msg_iovlen; ++i) {
            iov = &msghdr->msg_iov [i];
            if (nn_slow (iov->iov_len == NN_MSG)) {
               errno = EINVAL;
               return -1;
            }
            if (nn_slow (!iov->iov_base && iov->iov_len)) {
                errno = EFAULT;
                return -1;
            }
            if (nn_slow (sz + iov->iov_len < sz)) {
                errno = EINVAL;
                return -1;
            }
            sz += iov->iov_len;
        }

        /*  Create a message object from the supplied scatter array. */
        nn_msg_init (&msg, sz);
        sz = 0;
        for (i = 0; i != msghdr->msg_iovlen; ++i) {
            iov = &msghdr->msg_iov [i];
            memcpy (((uint8_t*) nn_chunkref_data (&msg.body)) + sz,
                iov->iov_base, iov->iov_len);
            sz += iov->iov_len;
        }

        nnmsg = 0;
    }

    /*  Add ancillary data to the message. */
    if (msghdr->msg_control) {

        /*  Copy all headers. */
        /*  TODO: SP_HDR should not be copied here! */
        if (msghdr->msg_controllen == NN_MSG) {
            chunk = *((void**) msghdr->msg_control);
            nn_chunkref_term (&msg.hdrs);
            nn_chunkref_init_chunk (&msg.hdrs, chunk);
        }
        else {
            nn_chunkref_term (&msg.hdrs);
            nn_chunkref_init (&msg.hdrs, msghdr->msg_controllen);
            memcpy (nn_chunkref_data (&msg.hdrs),
                msghdr->msg_control, msghdr->msg_controllen);
        }

        /* Search for SP_HDR property. */
        cmsg = NN_CMSG_FIRSTHDR (msghdr);
        while (cmsg) {
            if (cmsg->cmsg_level == PROTO_SP && cmsg->cmsg_type == SP_HDR) {
                /*  Copy body of SP_HDR property into 'sphdr'. */
                nn_chunkref_term (&msg.sphdr);
                spsz = cmsg->cmsg_len - NN_CMSG_SPACE (0);
                nn_chunkref_init (&msg.sphdr, spsz);
                memcpy (nn_chunkref_data (&msg.sphdr),
                    NN_CMSG_DATA (cmsg), spsz);
                break;
            }
            cmsg = NN_CMSG_NXTHDR (msghdr, cmsg);
        }
    }

    /*  Send it further down the stack. */
    rc = nn_sock_send (self.socks [s], &msg, flags);
    if (nn_slow (rc < 0)) {

        /*  If we are dealing with user-supplied buffer, detach it from
            the message object. */
        if (nnmsg)
            nn_chunkref_init (&msg.body, 0);

        nn_msg_term (&msg);
        errno = -rc;
        return -1;
    }

    /*  Adjust the statistics. */
    nn_sock_stat_increment (self.socks [s], NN_STAT_MESSAGES_SENT, 1);
    nn_sock_stat_increment (self.socks [s], NN_STAT_BYTES_SENT, sz);

    return (int) sz;
}