Beispiel #1
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);
}
Beispiel #2
0
void nn_streamhdr_start (struct nn_streamhdr *self, struct nn_usock *usock,
    struct nn_pipebase *pipebase)
{
    size_t sz;
    int protocol;

    /*  Take ownership of the underlying socket. */
    nn_assert (self->usock == NULL && self->usock_owner.fsm == NULL);
    self->usock_owner.src = NN_STREAMHDR_SRC_USOCK;
    self->usock_owner.fsm = &self->fsm;
    nn_usock_swap_owner (usock, &self->usock_owner);
    self->usock = usock;
    self->pipebase = pipebase;

    /*  Get the protocol identifier. */
    sz = sizeof (protocol);
    nn_pipebase_getopt (pipebase, NN_SOL_SOCKET, NN_PROTOCOL, &protocol, &sz);
    nn_assert (sz == sizeof (protocol));

    /*  Compose the protocol header. */
    memcpy (self->protohdr, "\0SP\0\0\0\0\0", 8);
    nn_puts (self->protohdr + 4, (uint16_t) protocol);

    /*  Launch the state machine. */
    nn_fsm_start (&self->fsm);
}
Beispiel #3
0
/*  Ceases further I/O on the underlying socket and prepares to send a
    close handshake on the next receive. */
static void nn_sws_fail_conn (struct nn_sws *self, int code, char *reason)
{
    size_t reason_len;
    size_t payload_len;
    uint8_t mask [4];
    uint8_t *payload_pos;

    nn_assert_state (self, NN_SWS_STATE_ACTIVE);

    /*  Destroy any remnant incoming message fragments. */
    nn_msg_array_term (&self->inmsg_array);

    /*  Reason string + code. */
    reason_len = strlen (reason);
    payload_len = reason_len + 2;

    /*  Ensure text is short enough to also include code and framing. */
    nn_assert (payload_len <= NN_SWS_MAX_SMALL_PAYLOAD);

    /*  RFC 6455 section 5.5.1. */
    self->fail_msg [0] = NN_SWS_FRAME_BITMASK_FIN | NN_WS_OPCODE_CLOSE;

    /*  Size of the payload, which is the status code plus the reason. */
    self->fail_msg [1] = payload_len;

    self->fail_msg_len = NN_SWS_FRAME_SIZE_INITIAL;

    /*  Generate 32-bit mask as per RFC 6455 5.3. */
    if (self->mode == NN_WS_CLIENT) {
        self->fail_msg [1] |= NN_SWS_FRAME_BITMASK_MASKED;
        nn_random_generate (mask, sizeof (mask));
        memcpy (&self->fail_msg [NN_SWS_FRAME_SIZE_INITIAL], mask, 4);
        self->fail_msg_len += 4;
    }

    payload_pos = &self->fail_msg [self->fail_msg_len];
    
    /*  Copy Status Code in network order (big-endian). */
    nn_puts (payload_pos, (uint16_t) code);
    self->fail_msg_len += 2;

    /*  Copy Close Reason immediately following the code. */
    memcpy (payload_pos + 2, reason, reason_len);

    /*  If this is a client, apply mask. */
    if (self->mode == NN_WS_CLIENT) {
        nn_sws_mask_payload (payload_pos, payload_len, mask, NULL);
    }

    self->fail_msg_len += payload_len;

    self->instate = NN_SWS_INSTATE_FAILING;

    /*  On the next recv, the connection will be failed. Why defer
        until the next recv? Semantically, until then, this incoming
        message has not been interpreted, so it's not until then that
        it could be failed. This type of pre-processing is necessary
        to early fail chunked transfers. */
    nn_pipebase_received (&self->pipebase);
}
Beispiel #4
0
int tcpmux_listen (int port, const char *service)
{
    int rc;
    int s;
    char ipcaddr [32];
    struct sockaddr_un unaddr;
    unsigned char buf [2];
    size_t sz;
    ssize_t ssz;

    /*  Make a connection to wsmux daemon. */
    s = socket (AF_UNIX, SOCK_STREAM, 0);
    if (s < 0)
        return -1;
    snprintf (ipcaddr, sizeof (ipcaddr), "/tmp/tcpmux-%d.ipc", port);
    nn_assert (strlen (ipcaddr) < sizeof (unaddr.sun_path));
    unaddr.sun_family = AF_UNIX;
    strcpy (unaddr.sun_path, ipcaddr);
    rc = connect (s, (struct sockaddr*) &unaddr, sizeof (unaddr));
    if (rc != 0)
        return -1;

    /* Send the connection header. */
    sz = strlen (service);
    nn_puts (buf, sz);
    ssz = send (s, buf, 2, 0);
    errno_assert (ssz >= 0);
    nn_assert (ssz == 2);
    ssz = send (s, service, sz, 0);
    errno_assert (ssz >= 0);
    nn_assert (ssz == sz);

    /*  Return the connection file descriptor to the user. */
    return s;
}
Beispiel #5
0
/*  Start sending a message. */
static int nn_sws_send (struct nn_pipebase *self, struct nn_msg *msg)
{
    struct nn_sws *sws;
    struct nn_iovec iov [3];
    int mask_pos;
    size_t sz;
    size_t hdrsz;
    uint8_t mask [4];

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

    nn_assert_state (sws, NN_SWS_STATE_ACTIVE);
    nn_assert (sws->outstate == NN_SWS_OUTSTATE_IDLE);

    /*  Move the message to the local storage. */
    nn_msg_term (&sws->outmsg);
    nn_msg_mv (&sws->outmsg, msg);

    /*  Compose the message header. See RFC 6455, section 5.2. */

    /*  Messages are always sent in a single fragment.
        They may be split up on the way to the peer though. */
    sws->outhdr [0] = NN_WS_OPCODE_BINARY | NN_SWS_FRAME_BITMASK_FIN;
    hdrsz = 1;
    
    /*  Frame the payload size. Don't set the mask bit yet. */
    sz = nn_chunkref_size (&sws->outmsg.sphdr) +
        nn_chunkref_size (&sws->outmsg.body);
    if (sz <= 0x7d) {
        sws->outhdr [1] = (uint8_t) sz;
        hdrsz += 1;
    }
    else if (sz <= 0xffff) {
        sws->outhdr [1] = 0x7e;
        nn_puts (&sws->outhdr [2], (uint16_t) sz);
        hdrsz += 3;
    }
    else {
        sws->outhdr [1] = 0x7f;
        nn_putll (&sws->outhdr [2], (uint64_t) sz);
        hdrsz += 9;
    }

    /*  Client-to-server communication has to be masked. See RFC 6455 5.3. */
    if (sws->mode == NN_WS_CLIENT) {

        /*  Generate 32-bit mask and store it in the frame. */
        /*  TODO: This is not a strong source of entropy. However, can we
            afford one wihout exhausting all the available entropy in the
            system at the high message rates? */
        nn_random_generate (mask, 4);
        sws->outhdr [1] |= NN_SWS_FRAME_BITMASK_MASKED;
        memcpy (&sws->outhdr [hdrsz], mask, 4);
        hdrsz += 4;

        /*  Mask payload, beginning with header and moving to body. */
        /*  TODO: This won't work if the message is shared among muliple
                   transports. We probably want to send the message in multiple
                   operations, masking only as much data at a time. */
        mask_pos = 0;
        nn_sws_mask_payload (nn_chunkref_data (&sws->outmsg.sphdr),
            nn_chunkref_size (&sws->outmsg.sphdr), mask, &mask_pos);
        nn_sws_mask_payload (nn_chunkref_data (&sws->outmsg.body),
            nn_chunkref_size (&sws->outmsg.body), mask, &mask_pos);
    }

    /*  Start async sending. */
    iov [0].iov_base = sws->outhdr;
    iov [0].iov_len = hdrsz;
    iov [1].iov_base = nn_chunkref_data (&sws->outmsg.sphdr);
    iov [1].iov_len = nn_chunkref_size (&sws->outmsg.sphdr);
    iov [2].iov_base = nn_chunkref_data (&sws->outmsg.body);
    iov [2].iov_len = nn_chunkref_size (&sws->outmsg.body);
    nn_usock_send (sws->usock, iov, 3);

    sws->outstate = NN_SWS_OUTSTATE_SENDING;

    /*  If a Close handshake was just sent, it's time to shut down. */
    if ((sws->outhdr [0] & NN_SWS_FRAME_BITMASK_OPCODE) ==
        NN_WS_OPCODE_CLOSE) {
        nn_pipebase_stop (&sws->pipebase);
        sws->state = NN_SWS_STATE_CLOSING_CONNECTION;
    }

    return 0;
}