Example #1
0
ssize_t
zpipes_client_read (zpipes_client_t *self, void *data, size_t size, int timeout)
{
    assert (self);

    zpipes_msg_send_read (self->dealer, size, timeout);
    zpipes_msg_t *reply = zpipes_msg_recv (self->dealer);
    if (!reply) {
        self->error = EINTR;
        return -1;              //  Interrupted
    }
    ssize_t rc = 0;
    if (zpipes_msg_id (reply) == ZPIPES_MSG_READ_OK) {
        zchunk_t *chunk = zpipes_msg_chunk (reply);
        ssize_t bytes = zchunk_size (chunk);
        assert (bytes <= size);
        memcpy (data, zchunk_data (chunk), bytes);
        rc = bytes;
    }
    else
    if (zpipes_msg_id (reply) == ZPIPES_MSG_READ_END)
        rc = 0;
    else
    if (zpipes_msg_id (reply) == ZPIPES_MSG_READ_TIMEOUT) {
        self->error = EAGAIN;
        rc = -1;
    }
    else
    if (zpipes_msg_id (reply) == ZPIPES_MSG_READ_FAILED) {
        //  TODO: better error code?
        //  This happens if we close a pipe while there's a pending read
        self->error = EINTR;
        rc = -1;
    }
    else
    if (zpipes_msg_id (reply) == ZPIPES_MSG_INVALID) {
        self->error = EBADF;
        rc = -1;
    }
    zpipes_msg_destroy (&reply);
    return rc;
}
Example #2
0
void
zpipes_server_test (bool verbose)
{
    printf (" * zpipes_server: \n");
    if (verbose)
        printf ("\n");

    //  @selftest
    //  Prepare test cases
    const char *endpoint = "ipc://@/zpipes/local";
    zactor_t *server = zactor_new (zpipes_server, NULL);
    if (verbose)
        zstr_send (server, "VERBOSE");
    zstr_sendx (server, "BIND", endpoint, NULL);

    zsock_t *writer = zsock_new_dealer (endpoint);
    assert (writer);
    zsock_t *writer2 = zsock_new_dealer (endpoint);
    assert (writer2);
    zsock_t *reader = zsock_new_dealer (endpoint);
    assert (reader);
    zsock_t *reader2 = zsock_new_dealer (endpoint);
    assert (reader2);
    
    zchunk_t *chunk = zchunk_new ("Hello, World", 12);
    int32_t timeout = 100;
    
    //  --------------------------------------------------------------------
    //  Basic tests

    //  Open writer on pipe
    zpipes_msg_send_output (writer, "test pipe");
    if (s_expect_reply (writer, ZPIPES_MSG_OUTPUT_OK))
        assert (false);

    //  Write will timeout if there's no reader
    zpipes_msg_send_write (writer, chunk, timeout);
    if (s_expect_reply (writer, ZPIPES_MSG_WRITE_TIMEOUT))
        assert (false);

    //  Now open reader on pipe
    zpipes_msg_send_input (reader, "test pipe");
    if (s_expect_reply (reader, ZPIPES_MSG_INPUT_OK))
        assert (false);

    //  Read will timeout if there's no data
    zpipes_msg_send_read (reader, 12, timeout);
    if (s_expect_reply (reader, ZPIPES_MSG_READ_TIMEOUT))
        assert (false);

    //  Write should now be successful
    zpipes_msg_send_write (writer, chunk, 0);
    if (s_expect_reply (writer, ZPIPES_MSG_WRITE_OK))
        assert (false);

    //  Read should now be successful
    zpipes_msg_send_read (reader, 12, 0);
    if (s_expect_reply (reader, ZPIPES_MSG_READ_OK))
        assert (false);

    //  Zero read request returns "end of pipe"
    zpipes_msg_send_read (reader, 0, 0);
    if (s_expect_reply (reader, ZPIPES_MSG_READ_END))
        assert (false);

    //  Close writer
    zpipes_msg_send_close (writer);
    if (s_expect_reply (writer, ZPIPES_MSG_CLOSE_OK))
        assert (false);

    //  Any read request returns "end of pipe"
    zpipes_msg_send_read (reader, 12, timeout);
    if (s_expect_reply (reader, ZPIPES_MSG_READ_END))
        assert (false);

    //  Close reader
    zpipes_msg_send_close (reader);
    if (s_expect_reply (reader, ZPIPES_MSG_CLOSE_OK))
        assert (false);

    //  --------------------------------------------------------------------
    //  Test pipelining (request queuing & filtering)

    //  Open reader on pipe
    zpipes_msg_send_input (reader, "test pipe");
    if (s_expect_reply (reader, ZPIPES_MSG_INPUT_OK))
        assert (false);

    //  Open writer on pipe
    zpipes_msg_send_output (writer, "test pipe");
    if (s_expect_reply (writer, ZPIPES_MSG_OUTPUT_OK))
        assert (false);

    //  Pipeline three read requests
    zpipes_msg_send_read (reader, 12, timeout);
    zpipes_msg_send_read (reader, 12, timeout);
    zpipes_msg_send_read (reader, 12, timeout);

    //  First read will return with a timeout
    if (s_expect_reply (reader, ZPIPES_MSG_READ_TIMEOUT))
        assert (false);

    //  Write chunk to pipe
    zpipes_msg_send_write (writer, chunk, 0);
    if (s_expect_reply (writer, ZPIPES_MSG_WRITE_OK))
        assert (false);

    //  Second read will succeed
    if (s_expect_reply (reader, ZPIPES_MSG_READ_OK))
        assert (false);

    //  Send PING, expect PING-OK back
    zpipes_msg_send_ping (reader);
    if (s_expect_reply (reader, ZPIPES_MSG_PING_OK))
        assert (false);

    //  Close writer
    zpipes_msg_send_close (writer);
    if (s_expect_reply (writer, ZPIPES_MSG_CLOSE_OK))
        assert (false);

    //  Third read will report end of pipe
    if (s_expect_reply (reader, ZPIPES_MSG_READ_END))
        assert (false);

    //  Close reader
    zpipes_msg_send_close (reader);
    if (s_expect_reply (reader, ZPIPES_MSG_CLOSE_OK))
        assert (false);

    //  Read now fails as pipe is closed
    zpipes_msg_send_read (reader, 12, timeout);
    if (s_expect_reply (reader, ZPIPES_MSG_INVALID))
        assert (false);

    //  Closing an already closed pipe is an error
    zpipes_msg_send_close (reader);
    if (s_expect_reply (reader, ZPIPES_MSG_INVALID))
        assert (false);

    //  --------------------------------------------------------------------
    //  Test read/close pipelining

    //  Open reader on pipe
    zpipes_msg_send_input (reader, "test pipe");
    if (s_expect_reply (reader, ZPIPES_MSG_INPUT_OK))
        assert (false);

    //  Open writer on pipe
    zpipes_msg_send_output (writer, "test pipe");
    if (s_expect_reply (writer, ZPIPES_MSG_OUTPUT_OK))
        assert (false);

    //  Pipeline two read requests
    zpipes_msg_send_read (reader, 12, timeout);
    zpipes_msg_send_read (reader, 12, timeout);

    //  Send PING, expect PING-OK back
    zpipes_msg_send_ping (reader);
    if (s_expect_reply (reader, ZPIPES_MSG_PING_OK))
        assert (false);

    //  Close reader
    zpipes_msg_send_close (reader);
    
    //  First read now fails
    if (s_expect_reply (reader, ZPIPES_MSG_READ_FAILED))
        assert (false);
    
    if (s_expect_reply (reader, ZPIPES_MSG_CLOSE_OK))
        assert (false);

    //  Second read is now invalid
    if (s_expect_reply (reader, ZPIPES_MSG_INVALID))
        assert (false);
    
    //  Close writer
    zpipes_msg_send_close (writer);
    if (s_expect_reply (writer, ZPIPES_MSG_CLOSE_OK))
        assert (false);

    //  --------------------------------------------------------------------
    //  Test reads and writes of different sizes

    //  Open reader on pipe
    zpipes_msg_send_input (reader, "test pipe");
    if (s_expect_reply (reader, ZPIPES_MSG_INPUT_OK))
        assert (false);

    //  Open writer on pipe
    zpipes_msg_send_output (writer, "test pipe");
    if (s_expect_reply (writer, ZPIPES_MSG_OUTPUT_OK))
        assert (false);

    //  Write chunk to pipe
    zpipes_msg_send_write (writer, chunk, 0);
    if (s_expect_reply (writer, ZPIPES_MSG_WRITE_OK))
        assert (false);

    //  Close writer
    zpipes_msg_send_close (writer);
    if (s_expect_reply (writer, ZPIPES_MSG_CLOSE_OK))
        assert (false);

    //  Read back in several steps
    zpipes_msg_send_read (reader, 1, 0);
    if (s_expect_reply (reader, ZPIPES_MSG_READ_OK))
        assert (false);
    zpipes_msg_send_read (reader, 2, 0);
    if (s_expect_reply (reader, ZPIPES_MSG_READ_OK))
        assert (false);
    zpipes_msg_send_read (reader, 3, 0);
    if (s_expect_reply (reader, ZPIPES_MSG_READ_OK))
        assert (false);
    zpipes_msg_send_read (reader, 3, 0);
    if (s_expect_reply (reader, ZPIPES_MSG_READ_OK))
        assert (false);
    
    //  We get a short read (3 bytes)
    zpipes_msg_send_read (reader, 100, 0);
    if (s_expect_reply (reader, ZPIPES_MSG_READ_OK))
        assert (false);
    
    //  Pipe is now empty
    zpipes_msg_send_read (reader, 100, 0);
    if (s_expect_reply (reader, ZPIPES_MSG_READ_END))
        assert (false);
    
    //  Close reader
    zpipes_msg_send_close (reader);
    if (s_expect_reply (reader, ZPIPES_MSG_CLOSE_OK))
        assert (false);

    //  --------------------------------------------------------------------
    //  Test connection expiry

    //  Set connection timeout to 200 msecs
    zstr_sendx (server, "SET", "server/timeout", "200", NULL);

    //  Open reader on pipe
    zpipes_msg_send_input (reader, "test pipe");
    if (s_expect_reply (reader, ZPIPES_MSG_INPUT_OK))
        assert (false);

    //  Read will expire, we don't expect any response for this command
    zpipes_msg_send_read (reader, 12, 0);

    //  Do nothing for long enough for the timeout to hit
    zclock_sleep (300);

    //  Try again, server should now treat the client as disconnected
    zpipes_msg_send_read (reader, 12, 0);
    if (s_expect_reply (reader, ZPIPES_MSG_INVALID))
        assert (false);

    //  Now check that disconnection erases pipe contents

    //  Open reader on pipe
    zpipes_msg_send_input (reader, "test pipe");
    if (s_expect_reply (reader, ZPIPES_MSG_INPUT_OK))
        assert (false);

    //  Open writer on pipe
    zpipes_msg_send_output (writer, "test pipe");
    if (s_expect_reply (writer, ZPIPES_MSG_OUTPUT_OK))
        assert (false);

    //  Write chunk to pipe
    zpipes_msg_send_write (writer, chunk, 0);
    if (s_expect_reply (writer, ZPIPES_MSG_WRITE_OK))
        assert (false);

    //  Do nothing for long enough for the timeout to hit
    //  Both writer and reader should be disconnected
    zclock_sleep (300);

    //  Open reader on pipe
    zpipes_msg_send_input (reader, "test pipe");
    if (s_expect_reply (reader, ZPIPES_MSG_INPUT_OK))
        assert (false);

    //  Open writer on pipe
    zpipes_msg_send_output (writer, "test pipe");
    if (s_expect_reply (writer, ZPIPES_MSG_OUTPUT_OK))
        assert (false);

    //  This read should timeout, as pipe is empty
    zpipes_msg_send_read (reader, 12, timeout);
    if (s_expect_reply (reader, ZPIPES_MSG_READ_TIMEOUT))
        assert (false);

    //  Close writer
    zpipes_msg_send_close (writer);
    if (s_expect_reply (writer, ZPIPES_MSG_CLOSE_OK))
        assert (false);

    //  Close reader
    zpipes_msg_send_close (reader);
    if (s_expect_reply (reader, ZPIPES_MSG_CLOSE_OK))
        assert (false);
    
    //  --------------------------------------------------------------------
    //  Test writer closing while reader still active

    //  Open writer on pipe
    zpipes_msg_send_output (writer, "test pipe");
    if (s_expect_reply (writer, ZPIPES_MSG_OUTPUT_OK))
        assert (false);

    //  Open reader on pipe
    zpipes_msg_send_input (reader, "test pipe");
    if (s_expect_reply (reader, ZPIPES_MSG_INPUT_OK))
        assert (false);

    //  Write one chunk to pipe
    zpipes_msg_send_write (writer, chunk, 0);
    if (s_expect_reply (writer, ZPIPES_MSG_WRITE_OK))
        assert (false);

    //  Close writer, before reader has read data
    zpipes_msg_send_close (writer);
    if (s_expect_reply (writer, ZPIPES_MSG_CLOSE_OK))
        assert (false);

    //  Open writer on same pipe name
    zpipes_msg_send_output (writer, "test pipe");
    if (s_expect_reply (writer, ZPIPES_MSG_OUTPUT_OK))
        assert (false);

    //  Read should still be successful
    zpipes_msg_send_read (reader, 12, 0);
    if (s_expect_reply (reader, ZPIPES_MSG_READ_OK))
        assert (false);

    //  Create second reader and open pipe for input
    zpipes_msg_send_input (reader2, "test pipe");
    if (s_expect_reply (reader2, ZPIPES_MSG_INPUT_OK))
        assert (false);

    //  Write one chunk to pipe, will go to second instance
    zpipes_msg_send_write (writer, chunk, 0);
    if (s_expect_reply (writer, ZPIPES_MSG_WRITE_OK))
        assert (false);

    //  Pipe is terminated and empty
    zpipes_msg_send_read (reader, 0, 0);
    if (s_expect_reply (reader, ZPIPES_MSG_READ_END))
        assert (false);

    //  Reader2 should be successful
    zpipes_msg_send_read (reader2, 12, 0);
    if (s_expect_reply (reader2, ZPIPES_MSG_READ_OK))
        assert (false);

    //  Close reader 
    zpipes_msg_send_close (reader);
    if (s_expect_reply (reader, ZPIPES_MSG_CLOSE_OK))
        assert (false);

    //  Close writer
    zpipes_msg_send_close (writer);
    if (s_expect_reply (writer, ZPIPES_MSG_CLOSE_OK))
        assert (false);
    
    //  Pipe is terminated and empty
    zpipes_msg_send_read (reader2, 0, 0);
    if (s_expect_reply (reader2, ZPIPES_MSG_READ_END))
        assert (false);

    //  Do that again to be sure it wasn't a coincidence :)
    zpipes_msg_send_read (reader2, 0, 0);
    if (s_expect_reply (reader2, ZPIPES_MSG_READ_END))
        assert (false);

    //  Close reader2
    zpipes_msg_send_close (reader2);
    if (s_expect_reply (reader2, ZPIPES_MSG_CLOSE_OK))
        assert (false);

    //  --------------------------------------------------------------------
    //  Test reader closing while writer still active

    //  Open writer on pipe
    zpipes_msg_send_output (writer, "test pipe");
    if (s_expect_reply (writer, ZPIPES_MSG_OUTPUT_OK))
        assert (false);

    //  Open reader on pipe
    zpipes_msg_send_input (reader, "test pipe");
    if (s_expect_reply (reader, ZPIPES_MSG_INPUT_OK))
        assert (false);

    //  Write one chunk to pipe
    zpipes_msg_send_write (writer, chunk, 0);
    if (s_expect_reply (writer, ZPIPES_MSG_WRITE_OK))
        assert (false);

    //  Read should be successful
    zpipes_msg_send_read (reader, 12, 0);
    if (s_expect_reply (reader, ZPIPES_MSG_READ_OK))
        assert (false);

    //  Close reader
    zpipes_msg_send_close (reader);
    if (s_expect_reply (reader, ZPIPES_MSG_CLOSE_OK))
        assert (false);

    //  Write should fail
    zpipes_msg_send_write (writer, chunk, 0);
    if (s_expect_reply (writer, ZPIPES_MSG_WRITE_FAILED))
        assert (false);

    //  Close writer
    zpipes_msg_send_close (writer);
    if (s_expect_reply (writer, ZPIPES_MSG_CLOSE_OK))
        assert (false);

    //  --------------------------------------------------------------------
    //  Two readers or writers on same pipe are not allowed

    //  Open writer on pipe
    zpipes_msg_send_output (writer, "test pipe");
    if (s_expect_reply (writer, ZPIPES_MSG_OUTPUT_OK))
        assert (false);

    //  Open second writer on pipe
    zpipes_msg_send_output (writer2, "test pipe");
    if (s_expect_reply (writer2, ZPIPES_MSG_OUTPUT_FAILED))
        assert (false);

    //  Open reader on pipe
    zpipes_msg_send_input (reader, "test pipe");
    if (s_expect_reply (reader, ZPIPES_MSG_INPUT_OK))
        assert (false);

    //  Open second reader on pipe
    zpipes_msg_send_input (reader2, "test pipe");
    if (s_expect_reply (reader2, ZPIPES_MSG_INPUT_FAILED))
        assert (false);

    //  Close reader
    zpipes_msg_send_close (reader);
    if (s_expect_reply (reader, ZPIPES_MSG_CLOSE_OK))
        assert (false);

    //  Close writer
    zpipes_msg_send_close (writer);
    if (s_expect_reply (writer, ZPIPES_MSG_CLOSE_OK))
        assert (false);
    
    //  --------------------------------------------------------------------
    //  Test short read when writer closes

    //  Open writer on pipe
    zpipes_msg_send_output (writer, "test pipe");
    if (s_expect_reply (writer, ZPIPES_MSG_OUTPUT_OK))
        assert (false);

    //  Open reader on pipe
    zpipes_msg_send_input (reader, "test pipe");
    if (s_expect_reply (reader, ZPIPES_MSG_INPUT_OK))
        assert (false);

    //  Write one chunk to pipe
    zpipes_msg_send_write (writer, chunk, 0);
    if (s_expect_reply (writer, ZPIPES_MSG_WRITE_OK))
        assert (false);

    //  Try to read large amount of data, will block
    zpipes_msg_send_read (reader, 1000, 0);
    
    //  Close writer
    zpipes_msg_send_close (writer);
    if (s_expect_reply (writer, ZPIPES_MSG_CLOSE_OK))
        assert (false);

    //  Reader should now return short read
    if (s_expect_reply (reader, ZPIPES_MSG_READ_OK))
        assert (false);

    //  Pipe is terminated and empty
    zpipes_msg_send_read (reader, 0, 0);
    if (s_expect_reply (reader, ZPIPES_MSG_READ_END))
        assert (false);

    //  Close reader
    zpipes_msg_send_close (reader);
    if (s_expect_reply (reader, ZPIPES_MSG_CLOSE_OK))
        assert (false);

    //  --------------------------------------------------------------------
    zchunk_destroy (&chunk);
    zactor_destroy (&server);
    zsock_destroy (&reader);
    zsock_destroy (&writer);
    zsock_destroy (&reader2);
    zsock_destroy (&writer2);
    //  @end

    printf ("OK\n");
}