示例#1
0
文件: aws.c 项目: zakharov/nanomsg
static void nn_aws_handler (struct nn_fsm *self, int src, int type,
    NN_UNUSED void *srcptr)
{
    struct nn_aws *aws;
    int val;
    size_t sz;

    aws = nn_cont (self, struct nn_aws, fsm);
    nn_assert (aws);

    switch (aws->state) {

/******************************************************************************/
/*  IDLE state.                                                               */
/*  The state machine wasn't yet started.                                     */
/******************************************************************************/
    case NN_AWS_STATE_IDLE:
        switch (src) {

        case NN_FSM_ACTION:
            switch (type) {
            case NN_FSM_START:
                nn_usock_accept (&aws->usock, aws->listener);
                aws->state = NN_AWS_STATE_ACCEPTING;
                return;
            default:
                nn_fsm_bad_action (aws->state, src, type);
            }

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

/******************************************************************************/
/*  ACCEPTING state.                                                          */
/*  Waiting for incoming connection.                                          */
/******************************************************************************/
    case NN_AWS_STATE_ACCEPTING:
        switch (src) {

        case NN_AWS_SRC_USOCK:
            switch (type) {
            case NN_USOCK_ACCEPTED:
                nn_epbase_clear_error (aws->epbase);

                /*  Set the relevant socket options. */
                sz = sizeof (val);
                nn_epbase_getopt (aws->epbase, NN_SOL_SOCKET, NN_SNDBUF,
                    &val, &sz);
                nn_assert (sz == sizeof (val));
                nn_usock_setsockopt (&aws->usock, SOL_SOCKET, SO_SNDBUF,
                    &val, sizeof (val));
                sz = sizeof (val);
                nn_epbase_getopt (aws->epbase, NN_SOL_SOCKET, NN_RCVBUF,
                    &val, &sz);
                nn_assert (sz == sizeof (val));
                nn_usock_setsockopt (&aws->usock, SOL_SOCKET, SO_RCVBUF,
                    &val, sizeof (val));

                /*   Since the WebSocket handshake must poll, the receive
                     timeout is set to zero. Later, it will be set again
                     to the value specified by the socket option. */
                val = 0;
                sz = sizeof (val);
                nn_usock_setsockopt (&aws->usock, SOL_SOCKET, SO_RCVTIMEO,
                    &val, sizeof (val));

                /*  Return ownership of the listening socket to the parent. */
                nn_usock_swap_owner (aws->listener, &aws->listener_owner);
                aws->listener = NULL;
                aws->listener_owner.src = -1;
                aws->listener_owner.fsm = NULL;
                nn_fsm_raise (&aws->fsm, &aws->accepted, NN_AWS_ACCEPTED);

                /*  Start the sws state machine. */
                nn_usock_activate (&aws->usock);
                nn_sws_start (&aws->sws, &aws->usock, NN_WS_SERVER,
                    NULL, NULL);
                aws->state = NN_AWS_STATE_ACTIVE;

                nn_epbase_stat_increment (aws->epbase,
                    NN_STAT_ACCEPTED_CONNECTIONS, 1);

                return;

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

        case NN_AWS_SRC_LISTENER:
            switch (type) {

            case NN_USOCK_ACCEPT_ERROR:
                nn_epbase_set_error (aws->epbase,
                    nn_usock_geterrno (aws->listener));
                nn_epbase_stat_increment (aws->epbase,
                    NN_STAT_ACCEPT_ERRORS, 1);
                nn_usock_accept (&aws->usock, aws->listener);
                return;

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

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

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

        case NN_AWS_SRC_SWS:
            switch (type) {
            case NN_SWS_RETURN_CLOSE_HANDSHAKE:
                /*  Peer closed connection without intention to reconnect, or
                    local endpoint failed remote because of invalid data. */
                nn_sws_stop (&aws->sws);
                aws->state = NN_AWS_STATE_STOPPING_SWS;
                return;
            case NN_SWS_RETURN_ERROR:
                nn_sws_stop (&aws->sws);
                aws->state = NN_AWS_STATE_STOPPING_SWS;
                nn_epbase_stat_increment (aws->epbase,
                    NN_STAT_BROKEN_CONNECTIONS, 1);
                return;
            default:
                nn_fsm_bad_action (aws->state, src, type);
            }

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

/******************************************************************************/
/*  STOPPING_SWS state.                                                       */
/******************************************************************************/
    case NN_AWS_STATE_STOPPING_SWS:
        switch (src) {

        case NN_AWS_SRC_SWS:
            switch (type) {
            case NN_USOCK_SHUTDOWN:
                return;
            case NN_SWS_RETURN_STOPPED:
                nn_usock_stop (&aws->usock);
                aws->state = NN_AWS_STATE_STOPPING_USOCK;
                return;
            default:
                nn_fsm_bad_action (aws->state, src, type);
            }

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

/******************************************************************************/
/*  STOPPING_USOCK state.                                                     */
/******************************************************************************/
    case NN_AWS_STATE_STOPPING_USOCK:
        switch (src) {

        case NN_AWS_SRC_USOCK:
            switch (type) {
            case NN_USOCK_SHUTDOWN:
                return;
            case NN_USOCK_STOPPED:
                nn_aws_stop (aws);
                return;
            default:
                nn_fsm_bad_action (aws->state, src, type);
            }

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

/******************************************************************************/
/*  Invalid state.                                                            */
/******************************************************************************/
    default:
        nn_fsm_bad_state (aws->state, src, type);
    }
}
示例#2
0
文件: cws.c 项目: 4ker/nanomsg
static void nn_cws_handler (struct nn_fsm *self, int src, int type,
    NN_UNUSED void *srcptr)
{
    struct nn_cws *cws;

    cws = nn_cont (self, struct nn_cws, fsm);

    switch (cws->state) {

/******************************************************************************/
/*  IDLE state.                                                               */
/*  The state machine wasn't yet started.                                     */
/******************************************************************************/
    case NN_CWS_STATE_IDLE:
        switch (src) {

        case NN_FSM_ACTION:
            switch (type) {
            case NN_FSM_START:
                nn_cws_start_resolving (cws);
                return;
            default:
                nn_fsm_bad_action (cws->state, src, type);
            }

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

/******************************************************************************/
/*  RESOLVING state.                                                          */
/*  Name of the host to connect to is being resolved to get an IP address.    */
/******************************************************************************/
    case NN_CWS_STATE_RESOLVING:
        switch (src) {

        case NN_CWS_SRC_DNS:
            switch (type) {
            case NN_DNS_DONE:
                nn_dns_stop (&cws->dns);
                cws->state = NN_CWS_STATE_STOPPING_DNS;
                return;
            default:
                nn_fsm_bad_action (cws->state, src, type);
            }

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

/******************************************************************************/
/*  STOPPING_DNS state.                                                       */
/*  dns object was asked to stop but it haven't stopped yet.                  */
/******************************************************************************/
    case NN_CWS_STATE_STOPPING_DNS:
        switch (src) {

        case NN_CWS_SRC_DNS:
            switch (type) {
            case NN_DNS_STOPPED:
                if (cws->dns_result.error == 0) {
                    nn_cws_start_connecting (cws, &cws->dns_result.addr,
                        cws->dns_result.addrlen);
                    return;
                }
                nn_backoff_start (&cws->retry);
                cws->state = NN_CWS_STATE_WAITING;
                return;
            default:
                nn_fsm_bad_action (cws->state, src, type);
            }

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

/******************************************************************************/
/*  CONNECTING state.                                                         */
/*  Non-blocking connect is under way.                                        */
/******************************************************************************/
    case NN_CWS_STATE_CONNECTING:
        switch (src) {

        case NN_CWS_SRC_USOCK:
            switch (type) {
            case NN_USOCK_CONNECTED:
                nn_sws_start (&cws->sws, &cws->usock, NN_WS_CLIENT,
                    nn_chunkref_data (&cws->resource),
                    nn_chunkref_data (&cws->remote_host), cws->msg_type);
                cws->state = NN_CWS_STATE_ACTIVE;
                cws->peer_gone = 0;
                nn_epbase_stat_increment (&cws->epbase,
                    NN_STAT_INPROGRESS_CONNECTIONS, -1);
                nn_epbase_stat_increment (&cws->epbase,
                    NN_STAT_ESTABLISHED_CONNECTIONS, 1);
                nn_epbase_clear_error (&cws->epbase);
                return;
            case NN_USOCK_ERROR:
                nn_epbase_set_error (&cws->epbase,
                    nn_usock_geterrno (&cws->usock));
                nn_usock_stop (&cws->usock);
                cws->state = NN_CWS_STATE_STOPPING_USOCK;
                nn_epbase_stat_increment (&cws->epbase,
                    NN_STAT_INPROGRESS_CONNECTIONS, -1);
                nn_epbase_stat_increment (&cws->epbase,
                    NN_STAT_CONNECT_ERRORS, 1);
                return;
            default:
                nn_fsm_bad_action (cws->state, src, type);
            }

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

/******************************************************************************/
/*  ACTIVE state.                                                             */
/*  Connection is established and handled by the sws state machine.           */
/******************************************************************************/
    case NN_CWS_STATE_ACTIVE:
        switch (src) {

        case NN_CWS_SRC_SWS:
            switch (type) {
            case NN_SWS_RETURN_CLOSE_HANDSHAKE:
                /*  Peer closed connection without intention to reconnect, or
                    local endpoint failed remote because of invalid data. */
                nn_sws_stop (&cws->sws);
                cws->state = NN_CWS_STATE_STOPPING_SWS;
                cws->peer_gone = 1;
                return;
            case NN_SWS_RETURN_ERROR:
                nn_sws_stop (&cws->sws);
                cws->state = NN_CWS_STATE_STOPPING_SWS;
                nn_epbase_stat_increment (&cws->epbase,
                    NN_STAT_BROKEN_CONNECTIONS, 1);
                return;
            default:
                nn_fsm_bad_action (cws->state, src, type);
            }

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

/******************************************************************************/
/*  STOPPING_SWS state.                                                       */
/*  sws object was asked to stop but it haven't stopped yet.                  */
/******************************************************************************/
    case NN_CWS_STATE_STOPPING_SWS:
        switch (src) {

        case NN_CWS_SRC_SWS:
            switch (type) {
            case NN_USOCK_SHUTDOWN:
                return;
            case NN_SWS_RETURN_STOPPED:
                nn_usock_stop (&cws->usock);
                cws->state = NN_CWS_STATE_STOPPING_USOCK;
                return;
            default:
                nn_fsm_bad_action (cws->state, src, type);
            }

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

/******************************************************************************/
/*  STOPPING_USOCK state.                                                     */
/*  usock object was asked to stop but it haven't stopped yet.                */
/******************************************************************************/
    case NN_CWS_STATE_STOPPING_USOCK:
        switch (src) {

        case NN_CWS_SRC_USOCK:
            switch (type) {
            case NN_USOCK_SHUTDOWN:
                return;
            case NN_USOCK_STOPPED:
                /*  If the peer has confirmed itself gone with a Closing
                    Handshake, or if the local endpoint failed the remote,
                    don't try to reconnect. */
                if (!cws->peer_gone) {
                    nn_backoff_start (&cws->retry);
                    cws->state = NN_CWS_STATE_WAITING;
                }
                return;
            default:
                nn_fsm_bad_action (cws->state, src, type);
            }

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

/******************************************************************************/
/*  WAITING state.                                                            */
/*  Waiting before re-connection is attempted. This way we won't overload     */
/*  the system by continuous re-connection attemps.                           */
/******************************************************************************/
    case NN_CWS_STATE_WAITING:
        switch (src) {

        case NN_CWS_SRC_RECONNECT_TIMER:
            switch (type) {
            case NN_BACKOFF_TIMEOUT:
                nn_backoff_stop (&cws->retry);
                cws->state = NN_CWS_STATE_STOPPING_BACKOFF;
                return;
            default:
                nn_fsm_bad_action (cws->state, src, type);
            }

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

/******************************************************************************/
/*  STOPPING_BACKOFF state.                                                   */
/*  backoff object was asked to stop, but it haven't stopped yet.             */
/******************************************************************************/
    case NN_CWS_STATE_STOPPING_BACKOFF:
        switch (src) {

        case NN_CWS_SRC_RECONNECT_TIMER:
            switch (type) {
            case NN_BACKOFF_STOPPED:
                nn_cws_start_resolving (cws);
                return;
            default:
                nn_fsm_bad_action (cws->state, src, type);
            }

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

/******************************************************************************/
/*  Invalid state.                                                            */
/******************************************************************************/
    default:
        nn_fsm_bad_state (cws->state, src, type);
    }
}