Example #1
0
static void nn_cstream_closing_closed (const struct nn_cp_sink **self,
    struct nn_usock *usock)
{
    int rc;
    struct nn_cstream *cstream;
    int sndbuf;
    int rcvbuf;
    size_t sz;

    cstream = nn_cont (self, struct nn_cstream, sink);

    /*  Get the current values of NN_SNDBUF and NN_RCVBUF options. */    
    sz = sizeof (sndbuf);
    nn_epbase_getopt (&cstream->epbase, NN_SOL_SOCKET, NN_SNDBUF, &sndbuf, &sz);
    nn_assert (sz == sizeof (sndbuf));
    sz = sizeof (rcvbuf);
    nn_epbase_getopt (&cstream->epbase, NN_SOL_SOCKET, NN_RCVBUF, &rcvbuf, &sz);
    nn_assert (sz == sizeof (rcvbuf));

    /*  Create new socket. */
    rc = cstream->initsockfn (&cstream->usock, sndbuf, rcvbuf,
        nn_epbase_getcp (&cstream->epbase));
    errnum_assert (rc == 0, -rc);
    nn_usock_setsink (&cstream->usock, &cstream->sink);

    /*  Wait for the specified period. */
    cstream->sink = &nn_cstream_state_waiting;
    nn_timer_start (&cstream->retry_timer,
        nn_cstream_compute_retry_ivl (cstream));
}
Example #2
0
static void nn_ctcp_start_resolving (struct nn_ctcp *self)
{
    const char *addr;
    const char *begin;
    const char *end;
    int ipv4only;
    size_t ipv4onlylen;

    /*  Extract the hostname part from address string. */
    addr = nn_epbase_getaddr (&self->epbase);
    begin = strchr (addr, ';');
    if (!begin)
        begin = addr;
    else
        ++begin;
    end = strrchr (addr, ':');
    nn_assert (end);

    /*  Check whether IPv6 is to be used. */
    ipv4onlylen = sizeof (ipv4only);
    nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_IPV4ONLY,
        &ipv4only, &ipv4onlylen);
    nn_assert (ipv4onlylen == sizeof (ipv4only));

    /*  TODO: Get the actual value of IPV4ONLY option. */
    nn_dns_start (&self->dns, begin, end - begin, ipv4only, &self->dns_result);

    self->state = NN_CTCP_STATE_RESOLVING;
}
Example #3
0
struct nn_binproc *nn_binproc_create (void *hint)
{
    struct nn_binproc *self;
    size_t sz;

    self = nn_alloc (sizeof (struct nn_binproc), "binproc");
    alloc_assert (self);

    nn_epbase_init (&self->epbase, &nn_binproc_vfptr, hint);
    nn_fsm_init_root (&self->fsm, nn_binproc_handler,
        nn_epbase_getctx (&self->epbase));
    self->state = NN_BINPROC_STATE_IDLE;
    nn_list_init (&self->sinprocs);
    nn_list_item_init (&self->item);
    sz = sizeof (self->protocol);
    nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_PROTOCOL,
        &self->protocol, &sz);
    nn_assert (sz == sizeof (self->protocol));
    self->connects = 0;

    /*  Start the state machine. */
    nn_fsm_start (&self->fsm);

    return self;
}
Example #4
0
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);
}
Example #5
0
int nn_cstream_init (struct nn_cstream *self, const char *addr, void *hint,
    int (*initsockfn) (struct nn_usock *sock, int sndbuf, int rcvbuf,
    struct nn_cp *cp), int (*resolvefn) (const char *addr,
    struct sockaddr_storage *ss, socklen_t *sslen))
{
    int rc;
    int sndbuf;
    int rcvbuf;
    size_t sz;

    self->initsockfn = initsockfn;
    self->resolvefn = resolvefn;

    /*  TODO: Check the syntax of the address and return error if it is
        not a valid address string. Don't do any blocking DNS operations
        though! */

    /*  Initialise the base class. */
    nn_epbase_init (&self->epbase, &nn_cstream_epbase_vfptr, addr, hint);

    /*  Get the current values of NN_SNDBUF and NN_RCVBUF options. */    
    sz = sizeof (sndbuf);
    nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_SNDBUF, &sndbuf, &sz);
    nn_assert (sz == sizeof (sndbuf));
    sz = sizeof (rcvbuf);
    nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_RCVBUF, &rcvbuf, &sz);
    nn_assert (sz == sizeof (rcvbuf));

    /*  Open a socket. */
    rc = self->initsockfn (&self->usock, sndbuf, rcvbuf,
        nn_epbase_getcp (&self->epbase));
    errnum_assert (rc == 0, -rc);
    nn_usock_setsink (&self->usock, &self->sink);

    /*  Initialise the retry timer. */
    self->retry_ivl = -1;
    nn_timer_init (&self->retry_timer, &self->sink,
        nn_epbase_getcp (&self->epbase));

    /*  Pretend we were waiting for the re-connect timer and that the timer
        have expired. */
    self->sink = &nn_cstream_state_waiting;
    nn_cstream_waiting_timeout (&self->sink, &self->retry_timer);

    return 0;
}
Example #6
0
static void nn_cipc_start_connecting (struct nn_cipc *self)
{
    int rc;
    struct sockaddr_storage ss;
    struct sockaddr_un *un;
    const char *addr;
    int val;
    size_t sz;

    /*  Try to start the underlying socket. */
    rc = nn_usock_start (&self->usock, AF_UNIX, SOCK_STREAM, 0);
    if (nn_slow (rc < 0)) {
        nn_backoff_start (&self->retry);
        self->state = NN_CIPC_STATE_WAITING;
        return;
    }

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

    /*  Create the IPC address from the address string. */
    addr = nn_epbase_getaddr (&self->epbase);
    memset (&ss, 0, sizeof (ss));
    un = (struct sockaddr_un*) &ss;
    nn_assert (strlen (addr) < sizeof (un->sun_path));
    ss.ss_family = AF_UNIX;
    strncpy (un->sun_path, addr, sizeof (un->sun_path));

    /*  Start connecting. */
    nn_usock_connect (&self->usock, (struct sockaddr*) &ss,
        sizeof (struct sockaddr_un));
    self->state  = NN_CIPC_STATE_CONNECTING;

    nn_epbase_stat_increment (&self->epbase,
        NN_STAT_INPROGRESS_CONNECTIONS, 1);
}
Example #7
0
void nn_ins_item_init (struct nn_ins_item *myself,const struct nn_epbase_vfptr *vfptr, void *hint)
{
    size_t sz;

    nn_epbase_init (&myself->epbase, vfptr, hint);
    nn_list_item_init (&myself->item);
    sz = sizeof (myself->protocol);
    nn_epbase_getopt (&myself->epbase, NN_SOL_SOCKET, NN_PROTOCOL,&myself->protocol, &sz);
    nn_assert (sz == sizeof (myself->protocol));
}
Example #8
0
static void nn_btcp_start_listening (struct nn_btcp *self)
{
    int rc;
    struct sockaddr_storage ss;
    size_t sslen;
    int ipv4only;
    size_t ipv4onlylen;
    const char *addr;
    const char *end;
    const char *pos;
    uint16_t port;

    /*  First, resolve the IP address. */
    addr = nn_epbase_getaddr (&self->epbase);
    memset (&ss, 0, sizeof (ss));

    /*  Parse the port. */
    end = addr + strlen (addr);
    pos = strrchr (addr, ':');
    nn_assert (pos);
    ++pos;
    rc = nn_port_resolve (pos, end - pos);
    nn_assert (rc >= 0);
    port = rc;

    /*  Parse the address. */
    ipv4onlylen = sizeof (ipv4only);
    nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_IPV4ONLY,
        &ipv4only, &ipv4onlylen);
    nn_assert (ipv4onlylen == sizeof (ipv4only));
    rc = nn_iface_resolve (addr, pos - addr - 1, ipv4only, &ss, &sslen);
    errnum_assert (rc == 0, -rc);

    /*  Combine the port and the address. */
    if (ss.ss_family == AF_INET) {
        ((struct sockaddr_in*) &ss)->sin_port = htons (port);
        sslen = sizeof (struct sockaddr_in);
    }
    else if (ss.ss_family == AF_INET6) {
        ((struct sockaddr_in6*) &ss)->sin6_port = htons (port);
        sslen = sizeof (struct sockaddr_in6);
    }
    else
        nn_assert (0);

    /*  Start listening for incoming connections. */
    rc = nn_usock_start (&self->usock, ss.ss_family, SOCK_STREAM, 0);
    /*  TODO: EMFILE error can happen here. We can wait a bit and re-try. */
    errnum_assert (rc == 0, -rc);
    rc = nn_usock_bind (&self->usock, (struct sockaddr*) &ss, (size_t) sslen);
    errnum_assert (rc == 0, -rc);
    rc = nn_usock_listen (&self->usock, NN_BTCP_BACKLOG);
    errnum_assert (rc == 0, -rc);
}
Example #9
0
int nn_bipc_create (void *hint, struct nn_epbase **epbase)
{
    struct nn_bipc *self;
    int reconnect_ivl;
    int reconnect_ivl_max;
    size_t sz;

    /*  Allocate the new endpoint object. */
    self = nn_alloc (sizeof (struct nn_bipc), "bipc");
    alloc_assert (self);

    /*  Initialise the structure. */
    nn_epbase_init (&self->epbase, &nn_bipc_epbase_vfptr, hint);
    nn_fsm_init_root (&self->fsm, nn_bipc_handler, nn_bipc_shutdown,
        nn_epbase_getctx (&self->epbase));
    self->state = NN_BIPC_STATE_IDLE;
    sz = sizeof (reconnect_ivl);
    nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_RECONNECT_IVL,
        &reconnect_ivl, &sz);
    nn_assert (sz == sizeof (reconnect_ivl));
    sz = sizeof (reconnect_ivl_max);
    nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_RECONNECT_IVL_MAX,
        &reconnect_ivl_max, &sz);
    nn_assert (sz == sizeof (reconnect_ivl_max));
    if (reconnect_ivl_max == 0)
        reconnect_ivl_max = reconnect_ivl;
    nn_backoff_init (&self->retry, NN_BIPC_SRC_RECONNECT_TIMER,
        reconnect_ivl, reconnect_ivl_max, &self->fsm);
    nn_usock_init (&self->usock, NN_BIPC_SRC_USOCK, &self->fsm);
    self->aipc = NULL;
    nn_list_init (&self->aipcs);

    /*  Start the state machine. */
    nn_fsm_start (&self->fsm);

    /*  Return the base class as an out parameter. */
    *epbase = &self->epbase;

    return 0;
}
Example #10
0
/*  Private functions. */
static int nn_cstream_compute_retry_ivl (struct nn_cstream *self)
{
    int reconnect_ivl;
    int reconnect_ivl_max;
    size_t sz;
    int result;
    unsigned int random;

    /*  Get relevant options' values. */
    sz = sizeof (reconnect_ivl);
    nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_RECONNECT_IVL,
        &reconnect_ivl, &sz);
    nn_assert (sz == sizeof (reconnect_ivl));
    sz = sizeof (reconnect_ivl_max);
    nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_RECONNECT_IVL_MAX,
        &reconnect_ivl_max, &sz);
    nn_assert (sz == sizeof (reconnect_ivl_max));

    /*  Negative number means that reconnect sequence is starting.
        The reconnect interval in this case is NN_RECONNECT_IVL. */
    if (self->retry_ivl < 0)
        self->retry_ivl = reconnect_ivl;

    /*  Current retry_ivl will be returned to the caller. */
    result = self->retry_ivl;

    /*  Re-compute new retry interval. */
    if (reconnect_ivl_max > 0 && reconnect_ivl_max > reconnect_ivl) {
        self->retry_ivl *= 2;
        if (self->retry_ivl > reconnect_ivl_max)
            self->retry_ivl = reconnect_ivl_max;
    }

    /*  Randomise the result to prevent re-connection storms when network
        and/or server goes down and then up again. This may rise
        the reconnection interval at most twice and at most by one second. */
    nn_random_generate (&random, sizeof (random));
    result += (random % result % 1000);
    return result;
}
Example #11
0
void nn_astream_init (struct nn_astream *self, struct nn_epbase *epbase,
    int s, struct nn_usock *usock, struct nn_bstream *bstream)
{
    int sndbuf;
    int rcvbuf;
    size_t sz;

    /*  Switch the state. */
    self->sink = &nn_astream_state_connected;
    self->bstream = bstream;

    /*  This stearm does not belong yet to the bstream. */
    nn_list_item_init (&self->item);

    /*  Get the current values of NN_SNDBUF and NN_RCVBUF options. */    
    sz = sizeof (sndbuf);
    nn_epbase_getopt (&self->bstream->epbase, NN_SOL_SOCKET, NN_SNDBUF,
        &sndbuf, &sz);
    nn_assert (sz == sizeof (sndbuf));
    sz = sizeof (rcvbuf);
    nn_epbase_getopt (&self->bstream->epbase, NN_SOL_SOCKET, NN_RCVBUF,
        &rcvbuf, &sz);
    nn_assert (sz == sizeof (rcvbuf));

    /*  Start the stream state machine. */
    nn_usock_init_child (&self->usock, usock, s, &self->sink, sndbuf, rcvbuf,
        usock->cp);
    
    /*  Note: must add myself to the astreams list *before* initializing my
        stream, which may fail and terminate me. */
    nn_list_insert (&bstream->astreams, &self->item,
        nn_list_end (&bstream->astreams));

    /*  Note: may fail and terminate me - do not reference self after
        this point! */
    nn_stream_init (&self->stream, epbase, &self->usock);
}
Example #12
0
File: cws.c Project: 4ker/nanomsg
static void nn_cws_start_resolving (struct nn_cws *self)
{
    int ipv4only;
    size_t ipv4onlylen;
    char *host;

    /*  Check whether IPv6 is to be used. */
    ipv4onlylen = sizeof (ipv4only);
    nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_IPV4ONLY,
        &ipv4only, &ipv4onlylen);
    nn_assert (ipv4onlylen == sizeof (ipv4only));

    host = nn_chunkref_data (&self->remote_host);
    nn_assert (strlen (host) > 0);

    nn_dns_start (&self->dns, host, self->remote_hostname_len, ipv4only,
        &self->dns_result);

    self->state = NN_CWS_STATE_RESOLVING;
}
Example #13
0
int nn_btcp_create (void *hint, struct nn_epbase **epbase)
{
    int rc;
    struct nn_btcp *self;
    const char *addr;
    const char *end;
    const char *pos;
    struct sockaddr_storage ss;
    size_t sslen;
    int ipv4only;
    size_t ipv4onlylen;

    /*  Allocate the new endpoint object. */
    self = nn_alloc (sizeof (struct nn_btcp), "btcp");
    alloc_assert (self);

    /*  Initalise the epbase. */
    nn_epbase_init (&self->epbase, &nn_btcp_epbase_vfptr, hint);
    addr = nn_epbase_getaddr (&self->epbase);

    /*  Parse the port. */
    end = addr + strlen (addr);
    pos = strrchr (addr, ':');
    if (nn_slow (!pos)) {
        nn_epbase_term (&self->epbase);
        return -EINVAL;
    }
    ++pos;
    rc = nn_port_resolve (pos, end - pos);
    if (nn_slow (rc < 0)) {
        nn_epbase_term (&self->epbase);
        return -EINVAL;
    }

    /*  Check whether IPv6 is to be used. */
    ipv4onlylen = sizeof (ipv4only);
    nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_IPV4ONLY,
        &ipv4only, &ipv4onlylen);
    nn_assert (ipv4onlylen == sizeof (ipv4only));

    /*  Parse the address. */
    rc = nn_iface_resolve (addr, pos - addr - 1, ipv4only, &ss, &sslen);
    if (nn_slow (rc < 0)) {
        nn_epbase_term (&self->epbase);
        return -ENODEV;
    }

    /*  Initialise the structure. */
    nn_fsm_init_root (&self->fsm, nn_btcp_handler, nn_btcp_shutdown,
        nn_epbase_getctx (&self->epbase));
    self->state = NN_BTCP_STATE_IDLE;
    nn_usock_init (&self->usock, NN_BTCP_SRC_USOCK, &self->fsm);
    self->atcp = NULL;
    nn_list_init (&self->atcps);

    /*  Start the state machine. */
    nn_fsm_start (&self->fsm);

    /*  Return the base class as an out parameter. */
    *epbase = &self->epbase;

    return 0;
}
Example #14
0
static void nn_atcp_handler (struct nn_fsm *self, int src, int type,
    NN_UNUSED void *srcptr)
{
    struct nn_atcp *atcp;
    int val;
    size_t sz;

    atcp = nn_cont (self, struct nn_atcp, fsm);

    switch (atcp->state) {

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

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

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

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

        case NN_ATCP_SRC_USOCK:
            switch (type) {
            case NN_USOCK_ACCEPTED:
                nn_epbase_clear_error (atcp->epbase);

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

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

                /*  Start the stcp state machine. */
                nn_usock_activate (&atcp->usock);
                nn_stcp_start (&atcp->stcp, &atcp->usock);
                atcp->state = NN_ATCP_STATE_ACTIVE;

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

                return;

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

        case NN_ATCP_SRC_LISTENER:
            switch (type) {

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

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

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

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

        case NN_ATCP_SRC_STCP:
            switch (type) {
            case NN_STCP_ERROR:
                nn_stcp_stop (&atcp->stcp);
                atcp->state = NN_ATCP_STATE_STOPPING_STCP;
                nn_epbase_stat_increment (atcp->epbase,
                    NN_STAT_BROKEN_CONNECTIONS, 1);
                return;
            default:
                nn_fsm_bad_action (atcp->state, src, type);
            }

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

/******************************************************************************/
/*  STOPPING_STCP state.                                                      */
/******************************************************************************/
    case NN_ATCP_STATE_STOPPING_STCP:
        switch (src) {

        case NN_ATCP_SRC_STCP:
            switch (type) {
            case NN_USOCK_SHUTDOWN:
                return;
            case NN_STCP_STOPPED:
                nn_usock_stop (&atcp->usock);
                atcp->state = NN_ATCP_STATE_STOPPING_USOCK;
                return;
            default:
                nn_fsm_bad_action (atcp->state, src, type);
            }

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

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

        case NN_ATCP_SRC_USOCK:
            switch (type) {
            case NN_USOCK_SHUTDOWN:
                return;
            case NN_USOCK_STOPPED:
                nn_fsm_raise (&atcp->fsm, &atcp->done, NN_ATCP_ERROR);
                atcp->state = NN_ATCP_STATE_DONE;
                return;
            default:
                nn_fsm_bad_action (atcp->state, src, type);
            }

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

/******************************************************************************/
/*  Invalid state.                                                            */
/******************************************************************************/
    default:
        nn_fsm_bad_state (atcp->state, src, type);
    }
}
Example #15
0
File: aipc.c Project: antmd/nanomsg
static void nn_aipc_handler (struct nn_fsm *self, int src, int type,
    void *srcptr)
{
    struct nn_aipc *aipc;
    int val;
    size_t sz;

    aipc = nn_cont (self, struct nn_aipc, fsm);

    switch (aipc->state) {

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

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

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

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

        case NN_AIPC_SRC_USOCK:
            switch (type) {
            case NN_USOCK_ACCEPTED:

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

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

                /*  Start the sipc state machine. */
                nn_usock_activate (&aipc->usock);
                nn_sipc_start (&aipc->sipc, &aipc->usock);
                aipc->state = NN_AIPC_STATE_ACTIVE;

                return;

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

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

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

        case NN_AIPC_SRC_SIPC:
            switch (type) {
            case NN_SIPC_ERROR:
                nn_sipc_stop (&aipc->sipc);
                aipc->state = NN_AIPC_STATE_STOPPING_SIPC;
                return;
            default:
                nn_fsm_bad_action (aipc->state, src, type);
            }

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

/******************************************************************************/
/*  STOPPING_SIPC state.                                                      */
/******************************************************************************/
    case NN_AIPC_STATE_STOPPING_SIPC:
        switch (src) {

        case NN_AIPC_SRC_SIPC:
            switch (type) {
            case NN_SIPC_STOPPED:
                nn_usock_stop (&aipc->usock);
                aipc->state = NN_AIPC_STATE_STOPPING_USOCK;
                return;
            default:
                nn_fsm_bad_action (aipc->state, src, type);
            }

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

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

        case NN_AIPC_SRC_USOCK:
            switch (type) {
            case NN_USOCK_STOPPED:
                nn_fsm_raise (&aipc->fsm, &aipc->done, NN_AIPC_ERROR);
                aipc->state = NN_AIPC_STATE_DONE;
                return;
            default:
                nn_fsm_bad_action (aipc->state, src, type);
            }

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

/******************************************************************************/
/*  Invalid state.                                                            */
/******************************************************************************/
    default:
        nn_fsm_bad_state (aipc->state, src, type);
    }
}
Example #16
0
static void nn_ctcp_start_connecting (struct nn_ctcp *self,
    struct sockaddr_storage *ss, size_t sslen)
{
    int rc;
    struct sockaddr_storage remote;
    size_t remotelen;
    struct sockaddr_storage local;
    size_t locallen;
    const char *addr;
    const char *end;
    const char *colon;
    const char *semicolon;
    uint16_t port;
    int ipv4only;
    size_t ipv4onlylen;
    int val;
    size_t sz;

    /*  Create IP address from the address string. */
    addr = nn_epbase_getaddr (&self->epbase);
    memset (&remote, 0, sizeof (remote));

    /*  Parse the port. */
    end = addr + strlen (addr);
    colon = strrchr (addr, ':');
    rc = nn_port_resolve (colon + 1, end - colon - 1);
    errnum_assert (rc > 0, -rc);
    port = rc;

    /*  Check whether IPv6 is to be used. */
    ipv4onlylen = sizeof (ipv4only);
    nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_IPV4ONLY,
        &ipv4only, &ipv4onlylen);
    nn_assert (ipv4onlylen == sizeof (ipv4only));

    /*  Parse the local address, if any. */
    semicolon = strchr (addr, ';');
    memset (&local, 0, sizeof (local));
    if (semicolon)
        rc = nn_iface_resolve (addr, semicolon - addr, ipv4only,
            &local, &locallen);
    else
        rc = nn_iface_resolve ("*", 1, ipv4only, &local, &locallen);
    if (nn_slow (rc < 0)) {
        nn_backoff_start (&self->retry);
        self->state = NN_CTCP_STATE_WAITING;
        return;
    }

    /*  Combine the remote address and the port. */
    remote = *ss;
    remotelen = sslen;
    if (remote.ss_family == AF_INET)
        ((struct sockaddr_in*) &remote)->sin_port = htons (port);
    else if (remote.ss_family == AF_INET6)
        ((struct sockaddr_in6*) &remote)->sin6_port = htons (port);
    else
        nn_assert (0);

    /*  Try to start the underlying socket. */
    rc = nn_usock_start (&self->usock, remote.ss_family, SOCK_STREAM, 0);
    if (nn_slow (rc < 0)) {
        nn_backoff_start (&self->retry);
        self->state = NN_CTCP_STATE_WAITING;
        return;
    }

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

    /*  Bind the socket to the local network interface. */
    rc = nn_usock_bind (&self->usock, (struct sockaddr*) &local, locallen);
    if (nn_slow (rc != 0)) {
        nn_backoff_start (&self->retry);
        self->state = NN_CTCP_STATE_WAITING;
        return;
    }

    /*  Start connecting. */
    nn_usock_connect (&self->usock, (struct sockaddr*) &remote, remotelen);
    self->state = NN_CTCP_STATE_CONNECTING;
    nn_epbase_stat_increment (&self->epbase,
        NN_STAT_INPROGRESS_CONNECTIONS, 1);
}
Example #17
0
static int nn_bws_listen (struct nn_bws *self)
{
    int rc;
    struct sockaddr_storage ss;
    size_t sslen;
    int ipv4only;
    size_t ipv4onlylen;
    const char *addr;
    const char *end;
    const char *pos;
    uint16_t port;

    /*  First, resolve the IP address. */
    addr = nn_epbase_getaddr (&self->epbase);
    memset (&ss, 0, sizeof (ss));

    /*  Parse the port. */
    end = addr + strlen (addr);
    pos = strrchr (addr, ':');
    nn_assert (pos);
    ++pos;
    rc = nn_port_resolve (pos, end - pos);
    if (rc < 0) {
        return rc;
    }
    port = (uint16_t) rc;

    /*  Parse the address. */
    ipv4onlylen = sizeof (ipv4only);
    nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_IPV4ONLY,
        &ipv4only, &ipv4onlylen);
    nn_assert (ipv4onlylen == sizeof (ipv4only));
    rc = nn_iface_resolve (addr, pos - addr - 1, ipv4only, &ss, &sslen);
    if (rc < 0) {
        return rc;
    }

    /*  Combine the port and the address. */
    if (ss.ss_family == AF_INET) {
        ((struct sockaddr_in*) &ss)->sin_port = htons (port);
        sslen = sizeof (struct sockaddr_in);
    }
    else if (ss.ss_family == AF_INET6) {
        ((struct sockaddr_in6*) &ss)->sin6_port = htons (port);
        sslen = sizeof (struct sockaddr_in6);
    }
    else
        nn_assert (0);

    /*  Start listening for incoming connections. */
    rc = nn_usock_start (&self->usock, ss.ss_family, SOCK_STREAM, 0);
    if (rc < 0) {
        return rc;
    }

    rc = nn_usock_bind (&self->usock, (struct sockaddr*) &ss, (size_t) sslen);
    if (rc < 0) {
        nn_usock_stop (&self->usock);
        return rc;
    }

    rc = nn_usock_listen (&self->usock, NN_BWS_BACKLOG);
    if (rc < 0) {
        nn_usock_stop (&self->usock);
        return rc;
    }
    nn_bws_start_accepting(self);

    return 0;
}
Example #18
0
int nn_ctcp_create (void *hint, struct nn_epbase **epbase)
{
    int rc;
    const char *addr;
    size_t addrlen;
    const char *semicolon;
    const char *hostname;
    const char *colon;
    const char *end;
    struct sockaddr_storage ss;
    size_t sslen;
    int ipv4only;
    size_t ipv4onlylen;
    struct nn_ctcp *self;
    int reconnect_ivl;
    int reconnect_ivl_max;
    size_t sz;

    /*  Allocate the new endpoint object. */
    self = nn_alloc (sizeof (struct nn_ctcp), "ctcp");
    alloc_assert (self);

    /*  Initalise the endpoint. */
    nn_epbase_init (&self->epbase, &nn_ctcp_epbase_vfptr, hint);

    /*  Check whether IPv6 is to be used. */
    ipv4onlylen = sizeof (ipv4only);
    nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_IPV4ONLY,
        &ipv4only, &ipv4onlylen);
    nn_assert (ipv4onlylen == sizeof (ipv4only));

    /*  Start parsing the address. */
    addr = nn_epbase_getaddr (&self->epbase);
    addrlen = strlen (addr);
    semicolon = strchr (addr, ';');
    hostname = semicolon ? semicolon + 1 : addr;
    colon = strrchr (addr, ':');
    end = addr + addrlen;

    /*  Parse the port. */
    if (nn_slow (!colon)) {
        nn_epbase_term (&self->epbase);
        return -EINVAL;
    }
    rc = nn_port_resolve (colon + 1, end - colon - 1);
    if (nn_slow (rc < 0)) {
        nn_epbase_term (&self->epbase);
        return -EINVAL;
    }

    /*  Check whether the host portion of the address is either a literal
        or a valid hostname. */
    if (nn_dns_check_hostname (hostname, colon - hostname) < 0 &&
          nn_literal_resolve (hostname, colon - hostname, ipv4only,
          &ss, &sslen) < 0) {
        nn_epbase_term (&self->epbase);
        return -EINVAL;
    }

    /*  If local address is specified, check whether it is valid. */
    if (semicolon) {
        rc = nn_iface_resolve (addr, semicolon - addr, ipv4only, &ss, &sslen);
        if (rc < 0) {
            nn_epbase_term (&self->epbase);
            return -ENODEV;
        }
    }

    /*  Initialise the structure. */
    nn_fsm_init_root (&self->fsm, nn_ctcp_handler, nn_ctcp_shutdown,
        nn_epbase_getctx (&self->epbase));
    self->state = NN_CTCP_STATE_IDLE;
    nn_usock_init (&self->usock, NN_CTCP_SRC_USOCK, &self->fsm);
    sz = sizeof (reconnect_ivl);
    nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_RECONNECT_IVL,
        &reconnect_ivl, &sz);
    nn_assert (sz == sizeof (reconnect_ivl));
    sz = sizeof (reconnect_ivl_max);
    nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_RECONNECT_IVL_MAX,
        &reconnect_ivl_max, &sz);
    nn_assert (sz == sizeof (reconnect_ivl_max));
    if (reconnect_ivl_max == 0)
        reconnect_ivl_max = reconnect_ivl;
    nn_backoff_init (&self->retry, NN_CTCP_SRC_RECONNECT_TIMER,
        reconnect_ivl, reconnect_ivl_max, &self->fsm);
    nn_stcp_init (&self->stcp, NN_CTCP_SRC_STCP, &self->epbase, &self->fsm);
    nn_dns_init (&self->dns, NN_CTCP_SRC_DNS, &self->fsm);

    /*  Start the state machine. */
    nn_fsm_start (&self->fsm);

    /*  Return the base class as an out parameter. */
    *epbase = &self->epbase;

    return 0;
}
Example #19
0
File: cws.c Project: 4ker/nanomsg
int nn_cws_create (void *hint, struct nn_epbase **epbase)
{
    int rc;
    const char *addr;
    size_t addrlen;
    const char *semicolon;
    const char *hostname;
    size_t hostlen;
    const char *colon;
    const char *slash;
    const char *resource;
    size_t resourcelen;
    struct sockaddr_storage ss;
    size_t sslen;
    int ipv4only;
    size_t ipv4onlylen;
    struct nn_cws *self;
    int reconnect_ivl;
    int reconnect_ivl_max;
    int msg_type;
    size_t sz;

    /*  Allocate the new endpoint object. */
    self = nn_alloc (sizeof (struct nn_cws), "cws");
    alloc_assert (self);

    /*  Initalise the endpoint. */
    nn_epbase_init (&self->epbase, &nn_cws_epbase_vfptr, hint);

    /*  Check whether IPv6 is to be used. */
    ipv4onlylen = sizeof (ipv4only);
    nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_IPV4ONLY,
        &ipv4only, &ipv4onlylen);
    nn_assert (ipv4onlylen == sizeof (ipv4only));

    /*  Start parsing the address. */
    addr = nn_epbase_getaddr (&self->epbase);
    addrlen = strlen (addr);
    semicolon = strchr (addr, ';');
    hostname = semicolon ? semicolon + 1 : addr;
    colon = strrchr (addr, ':');
    slash = colon ? strchr (colon, '/') : strchr (addr, '/');
    resource = slash ? slash : addr + addrlen;
    self->remote_hostname_len = colon ? colon - hostname : resource - hostname;

    /*  Host contains both hostname and port. */
    hostlen = resource - hostname;

    /*  Parse the port; assume port 80 if not explicitly declared. */
    if (nn_slow (colon != NULL)) {
        rc = nn_port_resolve (colon + 1, resource - colon - 1);
        if (nn_slow (rc < 0)) {
            nn_epbase_term (&self->epbase);
            return -EINVAL;
        }
        self->remote_port = rc;
    }
    else {
        self->remote_port = 80;
    }

    /*  Check whether the host portion of the address is either a literal
        or a valid hostname. */
    if (nn_dns_check_hostname (hostname, self->remote_hostname_len) < 0 &&
          nn_literal_resolve (hostname, self->remote_hostname_len, ipv4only,
          &ss, &sslen) < 0) {
        nn_epbase_term (&self->epbase);
        return -EINVAL;
    }

    /*  If local address is specified, check whether it is valid. */
    if (semicolon) {
        rc = nn_iface_resolve (addr, semicolon - addr, ipv4only, &ss, &sslen);
        if (rc < 0) {
            nn_epbase_term (&self->epbase);
            return -ENODEV;
        }
    }

    /*  At this point, the address is valid, so begin allocating resources. */
    nn_chunkref_init (&self->remote_host, hostlen + 1);
    memcpy (nn_chunkref_data (&self->remote_host), hostname, hostlen);
    ((uint8_t *) nn_chunkref_data (&self->remote_host)) [hostlen] = '\0';

    if (semicolon) {
        nn_chunkref_init (&self->nic, semicolon - addr);
        memcpy (nn_chunkref_data (&self->nic),
            addr, semicolon - addr);
    }
    else {
        nn_chunkref_init (&self->nic, 1);
        memcpy (nn_chunkref_data (&self->nic), "*", 1);
    }

    /*  The requested resource is used in opening handshake. */
    resourcelen = strlen (resource);
    if (resourcelen) {
        nn_chunkref_init (&self->resource, resourcelen + 1);
        strncpy (nn_chunkref_data (&self->resource),
            resource, resourcelen + 1);
    }
    else {
        /*  No resource specified, so allocate base path. */
        nn_chunkref_init (&self->resource, 2);
        strncpy (nn_chunkref_data (&self->resource), "/", 2);
    }

    /*  Initialise the structure. */
    nn_fsm_init_root (&self->fsm, nn_cws_handler, nn_cws_shutdown,
        nn_epbase_getctx (&self->epbase));
    self->state = NN_CWS_STATE_IDLE;
    nn_usock_init (&self->usock, NN_CWS_SRC_USOCK, &self->fsm);

    sz = sizeof (msg_type);
    nn_epbase_getopt (&self->epbase, NN_WS, NN_WS_MSG_TYPE,
        &msg_type, &sz);
    nn_assert (sz == sizeof (msg_type));
    self->msg_type = (uint8_t) msg_type;

    sz = sizeof (reconnect_ivl);
    nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_RECONNECT_IVL,
        &reconnect_ivl, &sz);
    nn_assert (sz == sizeof (reconnect_ivl));
    sz = sizeof (reconnect_ivl_max);
    nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_RECONNECT_IVL_MAX,
        &reconnect_ivl_max, &sz);
    nn_assert (sz == sizeof (reconnect_ivl_max));
    if (reconnect_ivl_max == 0)
        reconnect_ivl_max = reconnect_ivl;
    nn_backoff_init (&self->retry, NN_CWS_SRC_RECONNECT_TIMER,
        reconnect_ivl, reconnect_ivl_max, &self->fsm);

    nn_sws_init (&self->sws, NN_CWS_SRC_SWS, &self->epbase, &self->fsm);
    nn_dns_init (&self->dns, NN_CWS_SRC_DNS, &self->fsm);

    /*  Start the state machine. */
    nn_fsm_start (&self->fsm);

    /*  Return the base class as an out parameter. */
    *epbase = &self->epbase;

    return 0;
}
Example #20
0
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);
    }
}
Example #21
0
File: cws.c Project: 4ker/nanomsg
static void nn_cws_start_connecting (struct nn_cws *self,
    struct sockaddr_storage *ss, size_t sslen)
{
    int rc;
    struct sockaddr_storage remote;
    size_t remotelen;
    struct sockaddr_storage local;
    size_t locallen;
    int ipv4only;
    size_t ipv4onlylen;
    int val;
    size_t sz;

    memset (&remote, 0, sizeof (remote));
    memset (&local, 0, sizeof (local));

    /*  Check whether IPv6 is to be used. */
    ipv4onlylen = sizeof (ipv4only);
    nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_IPV4ONLY,
        &ipv4only, &ipv4onlylen);
    nn_assert (ipv4onlylen == sizeof (ipv4only));

    rc = nn_iface_resolve (nn_chunkref_data (&self->nic),
    nn_chunkref_size (&self->nic), ipv4only, &local, &locallen);

    if (nn_slow (rc < 0)) {
        nn_backoff_start (&self->retry);
        self->state = NN_CWS_STATE_WAITING;
        return;
    }

    /*  Combine the remote address and the port. */
    remote = *ss;
    remotelen = sslen;
    if (remote.ss_family == AF_INET)
        ((struct sockaddr_in*) &remote)->sin_port = htons (self->remote_port);
    else if (remote.ss_family == AF_INET6)
        ((struct sockaddr_in6*) &remote)->sin6_port = htons (self->remote_port);
    else
        nn_assert (0);

    /*  Try to start the underlying socket. */
    rc = nn_usock_start (&self->usock, remote.ss_family, SOCK_STREAM, 0);
    if (nn_slow (rc < 0)) {
        nn_backoff_start (&self->retry);
        self->state = NN_CWS_STATE_WAITING;
        return;
    }

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

    /*  Bind the socket to the local network interface. */
    rc = nn_usock_bind (&self->usock, (struct sockaddr*) &local, locallen);
    if (nn_slow (rc != 0)) {
        nn_backoff_start (&self->retry);
        self->state = NN_CWS_STATE_WAITING;
        return;
    }

    /*  Start connecting. */
    nn_usock_connect (&self->usock, (struct sockaddr*) &remote, remotelen);
    self->state = NN_CWS_STATE_CONNECTING;
    nn_epbase_stat_increment (&self->epbase,
        NN_STAT_INPROGRESS_CONNECTIONS, 1);
}