Ejemplo n.º 1
0
static int
zyre_node_recv_peer (zyre_node_t *self)
{
    //  Router socket tells us the identity of this peer
    zre_msg_t *msg = zre_msg_recv (self->inbox);
    if (msg == NULL)
        return 0;               //  Interrupted

    //  First frame is sender identity, holding binary UUID
    zuuid_t *uuid = zuuid_new ();
    zuuid_set (uuid, zframe_data (zre_msg_address (msg)));

    //  On HELLO we may create the peer if it's unknown
    //  On other commands the peer must already exist
    zyre_peer_t *peer = (zyre_peer_t *) zhash_lookup (self->peers, zuuid_str (uuid));
    if (zre_msg_id (msg) == ZRE_MSG_HELLO) {
        peer = zyre_node_require_peer (self, uuid, zre_msg_ipaddress (msg), zre_msg_mailbox (msg));
        assert (peer);
        zyre_peer_set_ready (peer, true);
    }
    //  Ignore command if peer isn't ready
    if (peer == NULL || !zyre_peer_ready (peer)) {
        zre_msg_destroy (&msg);
        zuuid_destroy (&uuid);
        return 0;
    }
    if (!zyre_peer_check_message (peer, msg)) {
        zclock_log ("W: [%s] lost messages from %s", zuuid_str (self->uuid), zuuid_str (uuid));
        assert (false);
    }

    //  Now process each command
    if (zre_msg_id (msg) == ZRE_MSG_HELLO) {
        //  Tell the caller about the peer
        zstr_sendm (self->pipe, "ENTER");
        zstr_sendm (self->pipe, zuuid_str (uuid));
        zframe_t *headers = zhash_pack (zre_msg_headers (msg));
        zframe_send (&headers, self->pipe, 0);
        
        //  Join peer to listed groups
        char *name = zre_msg_groups_first (msg);
        while (name) {
            zyre_node_join_peer_group (self, peer, name);
            name = zre_msg_groups_next (msg);
        }
        //  Hello command holds latest status of peer
        zyre_peer_set_status (peer, zre_msg_status (msg));
        
        //  Store peer headers for future reference
        zyre_peer_set_headers (peer, zre_msg_headers (msg));

        //  If peer is a ZRE/LOG collector, connect to it
        char *collector = zre_msg_headers_string (msg, "X-ZRELOG", NULL);
        if (collector)
            zyre_log_connect (self->log, collector);
    }
    else
    if (zre_msg_id (msg) == ZRE_MSG_WHISPER) {
        //  Pass up to caller API as WHISPER event
        zstr_sendm (self->pipe, "WHISPER");
        zstr_sendm (self->pipe, zuuid_str (uuid));
        zmsg_t *content = zmsg_dup (zre_msg_content (msg));
        zmsg_send (&content, self->pipe);
    }
    else
    if (zre_msg_id (msg) == ZRE_MSG_SHOUT) {
        //  Pass up to caller as SHOUT event
        zstr_sendm (self->pipe, "SHOUT");
        zstr_sendm (self->pipe, zuuid_str (uuid));
        zstr_sendm (self->pipe, zre_msg_group (msg));
        zmsg_t *content = zmsg_dup (zre_msg_content (msg));
        zmsg_send (&content, self->pipe);
    }
    else
    if (zre_msg_id (msg) == ZRE_MSG_PING) {
        zre_msg_t *msg = zre_msg_new (ZRE_MSG_PING_OK);
        zyre_peer_send (peer, &msg);
    }
    else
    if (zre_msg_id (msg) == ZRE_MSG_JOIN) {
        zyre_node_join_peer_group (self, peer, zre_msg_group (msg));
        assert (zre_msg_status (msg) == zyre_peer_status (peer));
    }
    else
    if (zre_msg_id (msg) == ZRE_MSG_LEAVE) {
        zyre_node_leave_peer_group (self, peer, zre_msg_group (msg));
        assert (zre_msg_status (msg) == zyre_peer_status (peer));
    }
    zuuid_destroy (&uuid);
    zre_msg_destroy (&msg);
    
    //  Activity from peer resets peer timers
    zyre_peer_refresh (peer);
    return 0;
}
Ejemplo n.º 2
0
static void
zyre_node_recv_peer (zyre_node_t *self)
{
    //  Router socket tells us the identity of this peer
    zre_msg_t *msg = zre_msg_recv (self->inbox);
    if (!msg)
        return;                 //  Interrupted

    //  First frame is sender identity
    byte *peerid_data = zframe_data (zre_msg_routing_id (msg));
    size_t peerid_size = zframe_size (zre_msg_routing_id (msg));

    //  Identity must be [1] followed by 16-byte UUID
    if (peerid_size != ZUUID_LEN + 1) {
        zre_msg_destroy (&msg);
        return;
    }
    zuuid_t *uuid = zuuid_new ();
    zuuid_set (uuid, peerid_data + 1);

    //  On HELLO we may create the peer if it's unknown
    //  On other commands the peer must already exist
    zyre_peer_t *peer = (zyre_peer_t *) zhash_lookup (self->peers, zuuid_str (uuid));
    if (zre_msg_id (msg) == ZRE_MSG_HELLO) {
        if (peer) {
            //  Remove fake peers
            if (zyre_peer_ready (peer)) {
                zyre_node_remove_peer (self, peer);
                assert (!(zyre_peer_t *) zhash_lookup (self->peers, zuuid_str (uuid)));
            }
            else
            if (streq (zyre_peer_endpoint (peer), self->endpoint)) {
                //  We ignore HELLO, if peer has same endpoint as current node
                zre_msg_destroy (&msg);
                zuuid_destroy (&uuid);
                return;
            }
        }
        peer = zyre_node_require_peer (self, uuid, zre_msg_endpoint (msg));
        assert (peer);
        zyre_peer_set_ready (peer, true);
    }
    //  Ignore command if peer isn't ready
    if (peer == NULL || !zyre_peer_ready (peer)) {
        zre_msg_destroy (&msg);
        zuuid_destroy (&uuid);
        return;
    }
    if (zyre_peer_messages_lost (peer, msg)) {
        zsys_warning ("(%s) messages lost from %s", self->name, zyre_peer_name (peer));
        zyre_node_remove_peer (self, peer);
        zre_msg_destroy (&msg);
        zuuid_destroy (&uuid);
        return;
    }
    //  Now process each command
    if (zre_msg_id (msg) == ZRE_MSG_HELLO) {
        //  Store properties from HELLO command into peer
        zyre_peer_set_name (peer, zre_msg_name (msg));
        zyre_peer_set_headers (peer, zre_msg_headers (msg));

        //  Tell the caller about the peer
        zstr_sendm (self->outbox, "ENTER");
        zstr_sendm (self->outbox, zyre_peer_identity (peer));
        zstr_sendm (self->outbox, zyre_peer_name (peer));
        zframe_t *headers = zhash_pack (zyre_peer_headers (peer));
        zframe_send (&headers, self->outbox, ZFRAME_MORE);
        zstr_send (self->outbox, zre_msg_endpoint (msg));

        if (self->verbose)
            zsys_info ("(%s) ENTER name=%s endpoint=%s",
                self->name, zyre_peer_name (peer), zyre_peer_endpoint (peer));

        //  Join peer to listed groups
        const char *name = zre_msg_groups_first (msg);
        while (name) {
            zyre_node_join_peer_group (self, peer, name);
            name = zre_msg_groups_next (msg);
        }
        //  Now take peer's status from HELLO, after joining groups
        zyre_peer_set_status (peer, zre_msg_status (msg));
    }
    else
    if (zre_msg_id (msg) == ZRE_MSG_WHISPER) {
        //  Pass up to caller API as WHISPER event
        zstr_sendm (self->outbox, "WHISPER");
        zstr_sendm (self->outbox, zuuid_str (uuid));
        zstr_sendm (self->outbox, zyre_peer_name (peer));
        zmsg_t *content = zmsg_dup (zre_msg_content (msg));
        zmsg_send (&content, self->outbox);
    }
    else
    if (zre_msg_id (msg) == ZRE_MSG_SHOUT) {
        //  Pass up to caller as SHOUT event
        zstr_sendm (self->outbox, "SHOUT");
        zstr_sendm (self->outbox, zuuid_str (uuid));
        zstr_sendm (self->outbox, zyre_peer_name (peer));
        zstr_sendm (self->outbox, zre_msg_group (msg));
        zmsg_t *content = zmsg_dup (zre_msg_content (msg));
        zmsg_send (&content, self->outbox);
    }
    else
    if (zre_msg_id (msg) == ZRE_MSG_PING) {
        zre_msg_t *msg = zre_msg_new (ZRE_MSG_PING_OK);
        zyre_peer_send (peer, &msg);
    }
    else
    if (zre_msg_id (msg) == ZRE_MSG_JOIN) {
        zyre_node_join_peer_group (self, peer, zre_msg_group (msg));
        assert (zre_msg_status (msg) == zyre_peer_status (peer));
    }
    else
    if (zre_msg_id (msg) == ZRE_MSG_LEAVE) {
        zyre_node_leave_peer_group (self, peer, zre_msg_group (msg));
        assert (zre_msg_status (msg) == zyre_peer_status (peer));
    }
    zuuid_destroy (&uuid);
    zre_msg_destroy (&msg);

    //  Activity from peer resets peer timers
    zyre_peer_refresh (peer, self->evasive_timeout, self->expired_timeout);
}
Ejemplo n.º 3
0
static int
agent_recv_from_peer (agent_t *self)
{
    //  Router socket tells us the identity of this peer
    zre_msg_t *msg = zre_msg_recv (self->inbox);
    if (msg == NULL)
        return 0;               //  Interrupted

    char *identity = zframe_strdup (zre_msg_address (msg));
        
    //  On HELLO we may create the peer if it's unknown
    //  On other commands the peer must already exist
    zre_peer_t *peer = (zre_peer_t *) zhash_lookup (self->peers, identity);
    if (zre_msg_id (msg) == ZRE_MSG_HELLO) {
        peer = s_require_peer (
            self, identity, zre_msg_ipaddress (msg), zre_msg_mailbox (msg));
        assert (peer);
        zre_peer_ready_set (peer, true);
    }
    //  Ignore command if peer isn't ready
    if (peer == NULL || !zre_peer_ready (peer)) {
				free(identity);
        zre_msg_destroy (&msg);
        return 0;
    }
    if (!zre_peer_check_message (peer, msg)) {
        zclock_log ("W: [%s] lost messages from %s", self->identity, identity);
        assert (false);
    }

    //  Now process each command
    if (zre_msg_id (msg) == ZRE_MSG_HELLO) {
        //  Join peer to listed groups
        char *name = zre_msg_groups_first (msg);
        while (name) {
            s_join_peer_group (self, peer, name);
            name = zre_msg_groups_next (msg);
        }
        //  Hello command holds latest status of peer
        zre_peer_status_set (peer, zre_msg_status (msg));
        
        //  Store peer headers for future reference
        zre_peer_headers_set (peer, zre_msg_headers (msg));

        //  If peer is a ZRE/LOG collector, connect to it
        char *collector = zre_msg_headers_string (msg, "X-ZRELOG", NULL);
        if (collector)
            zre_log_connect (self->log, collector);
        
        //  If peer is a FileMQ publisher, connect to it
        char *publisher = zre_msg_headers_string (msg, "X-FILEMQ", NULL);
        if (publisher)
            fmq_client_connect (self->fmq_client, publisher);
    }
    else
    if (zre_msg_id (msg) == ZRE_MSG_WHISPER) {
        //  Pass up to caller API as WHISPER event
        zframe_t *cookie = zre_msg_content (msg);
        zstr_sendm (self->pipe, "WHISPER");
        zstr_sendm (self->pipe, identity);
        zframe_send (&cookie, self->pipe, ZFRAME_REUSE); // let msg free the frame
    }
    else
    if (zre_msg_id (msg) == ZRE_MSG_SHOUT) {
        //  Pass up to caller as SHOUT event
        zframe_t *cookie = zre_msg_content (msg);
        zstr_sendm (self->pipe, "SHOUT");
        zstr_sendm (self->pipe, identity);
        zstr_sendm (self->pipe, zre_msg_group (msg));
        zframe_send (&cookie, self->pipe, ZFRAME_REUSE); // let msg free the frame
    }
    else
    if (zre_msg_id (msg) == ZRE_MSG_PING) {
        zre_msg_t *msg = zre_msg_new (ZRE_MSG_PING_OK);
        zre_peer_send (peer, &msg);
    }
    else
    if (zre_msg_id (msg) == ZRE_MSG_JOIN) {
        s_join_peer_group (self, peer, zre_msg_group (msg));
        assert (zre_msg_status (msg) == zre_peer_status (peer));
    }
    else
    if (zre_msg_id (msg) == ZRE_MSG_LEAVE) {
        s_leave_peer_group (self, peer, zre_msg_group (msg));
        assert (zre_msg_status (msg) == zre_peer_status (peer));
    }
    free (identity);
    zre_msg_destroy (&msg);
    
    //  Activity from peer resets peer timers
    zre_peer_refresh (peer);
    return 0;
}
Ejemplo n.º 4
0
int
zre_msg_test (bool verbose)
{
    printf (" * zre_msg: ");

    //  @selftest
    //  Simple create/destroy test
    zre_msg_t *self = zre_msg_new (0);
    assert (self);
    zre_msg_destroy (&self);

    //  Create pair of sockets we can send through
    zctx_t *ctx = zctx_new ();
    assert (ctx);

    void *output = zsocket_new (ctx, ZMQ_DEALER);
    assert (output);
    zsocket_bind (output, "inproc://selftest");

    void *input = zsocket_new (ctx, ZMQ_ROUTER);
    assert (input);
    zsocket_connect (input, "inproc://selftest");
    
    //  Encode/send/decode and verify each message type
    int instance;
    zre_msg_t *copy;
    self = zre_msg_new (ZRE_MSG_HELLO);
    
    //  Check that _dup works on empty message
    copy = zre_msg_dup (self);
    assert (copy);
    zre_msg_destroy (&copy);

    zre_msg_set_sequence (self, 123);
    zre_msg_set_ipaddress (self, "Life is short but Now lasts for ever");
    zre_msg_set_mailbox (self, 123);
    zre_msg_groups_append (self, "Name: %s", "Brutus");
    zre_msg_groups_append (self, "Age: %d", 43);
    zre_msg_set_status (self, 123);
    zre_msg_headers_insert (self, "Name", "Brutus");
    zre_msg_headers_insert (self, "Age", "%d", 43);
    //  Send twice from same object
    zre_msg_send_again (self, output);
    zre_msg_send (&self, output);

    for (instance = 0; instance < 2; instance++) {
        self = zre_msg_recv (input);
        assert (self);
        assert (zre_msg_routing_id (self));
        
        assert (zre_msg_sequence (self) == 123);
        assert (streq (zre_msg_ipaddress (self), "Life is short but Now lasts for ever"));
        assert (zre_msg_mailbox (self) == 123);
        assert (zre_msg_groups_size (self) == 2);
        assert (streq (zre_msg_groups_first (self), "Name: Brutus"));
        assert (streq (zre_msg_groups_next (self), "Age: 43"));
        assert (zre_msg_status (self) == 123);
        assert (zre_msg_headers_size (self) == 2);
        assert (streq (zre_msg_headers_string (self, "Name", "?"), "Brutus"));
        assert (zre_msg_headers_number (self, "Age", 0) == 43);
        zre_msg_destroy (&self);
    }
    self = zre_msg_new (ZRE_MSG_WHISPER);
    
    //  Check that _dup works on empty message
    copy = zre_msg_dup (self);
    assert (copy);
    zre_msg_destroy (&copy);

    zre_msg_set_sequence (self, 123);
    zmsg_t *whisper_content = zmsg_new ();
    zre_msg_set_content (self, &whisper_content);
    zmsg_addstr (zre_msg_content (self), "Hello, World");
    //  Send twice from same object
    zre_msg_send_again (self, output);
    zre_msg_send (&self, output);

    for (instance = 0; instance < 2; instance++) {
        self = zre_msg_recv (input);
        assert (self);
        assert (zre_msg_routing_id (self));
        
        assert (zre_msg_sequence (self) == 123);
        assert (zmsg_size (zre_msg_content (self)) == 1);
        zre_msg_destroy (&self);
    }
    self = zre_msg_new (ZRE_MSG_SHOUT);
    
    //  Check that _dup works on empty message
    copy = zre_msg_dup (self);
    assert (copy);
    zre_msg_destroy (&copy);

    zre_msg_set_sequence (self, 123);
    zre_msg_set_group (self, "Life is short but Now lasts for ever");
    zmsg_t *shout_content = zmsg_new ();
    zre_msg_set_content (self, &shout_content);
    zmsg_addstr (zre_msg_content (self), "Hello, World");
    //  Send twice from same object
    zre_msg_send_again (self, output);
    zre_msg_send (&self, output);

    for (instance = 0; instance < 2; instance++) {
        self = zre_msg_recv (input);
        assert (self);
        assert (zre_msg_routing_id (self));
        
        assert (zre_msg_sequence (self) == 123);
        assert (streq (zre_msg_group (self), "Life is short but Now lasts for ever"));
        assert (zmsg_size (zre_msg_content (self)) == 1);
        zre_msg_destroy (&self);
    }
    self = zre_msg_new (ZRE_MSG_JOIN);
    
    //  Check that _dup works on empty message
    copy = zre_msg_dup (self);
    assert (copy);
    zre_msg_destroy (&copy);

    zre_msg_set_sequence (self, 123);
    zre_msg_set_group (self, "Life is short but Now lasts for ever");
    zre_msg_set_status (self, 123);
    //  Send twice from same object
    zre_msg_send_again (self, output);
    zre_msg_send (&self, output);

    for (instance = 0; instance < 2; instance++) {
        self = zre_msg_recv (input);
        assert (self);
        assert (zre_msg_routing_id (self));
        
        assert (zre_msg_sequence (self) == 123);
        assert (streq (zre_msg_group (self), "Life is short but Now lasts for ever"));
        assert (zre_msg_status (self) == 123);
        zre_msg_destroy (&self);
    }
    self = zre_msg_new (ZRE_MSG_LEAVE);
    
    //  Check that _dup works on empty message
    copy = zre_msg_dup (self);
    assert (copy);
    zre_msg_destroy (&copy);

    zre_msg_set_sequence (self, 123);
    zre_msg_set_group (self, "Life is short but Now lasts for ever");
    zre_msg_set_status (self, 123);
    //  Send twice from same object
    zre_msg_send_again (self, output);
    zre_msg_send (&self, output);

    for (instance = 0; instance < 2; instance++) {
        self = zre_msg_recv (input);
        assert (self);
        assert (zre_msg_routing_id (self));
        
        assert (zre_msg_sequence (self) == 123);
        assert (streq (zre_msg_group (self), "Life is short but Now lasts for ever"));
        assert (zre_msg_status (self) == 123);
        zre_msg_destroy (&self);
    }
    self = zre_msg_new (ZRE_MSG_PING);
    
    //  Check that _dup works on empty message
    copy = zre_msg_dup (self);
    assert (copy);
    zre_msg_destroy (&copy);

    zre_msg_set_sequence (self, 123);
    //  Send twice from same object
    zre_msg_send_again (self, output);
    zre_msg_send (&self, output);

    for (instance = 0; instance < 2; instance++) {
        self = zre_msg_recv (input);
        assert (self);
        assert (zre_msg_routing_id (self));
        
        assert (zre_msg_sequence (self) == 123);
        zre_msg_destroy (&self);
    }
    self = zre_msg_new (ZRE_MSG_PING_OK);
    
    //  Check that _dup works on empty message
    copy = zre_msg_dup (self);
    assert (copy);
    zre_msg_destroy (&copy);

    zre_msg_set_sequence (self, 123);
    //  Send twice from same object
    zre_msg_send_again (self, output);
    zre_msg_send (&self, output);

    for (instance = 0; instance < 2; instance++) {
        self = zre_msg_recv (input);
        assert (self);
        assert (zre_msg_routing_id (self));
        
        assert (zre_msg_sequence (self) == 123);
        zre_msg_destroy (&self);
    }

    zctx_destroy (&ctx);
    //  @end

    printf ("OK\n");
    return 0;
}
Ejemplo n.º 5
0
int
zre_msg_test (bool verbose)
{
    printf (" * zre_msg: ");

    //  @selftest
    //  Simple create/destroy test
    zre_msg_t *self = zre_msg_new (0);
    assert (self);
    zre_msg_destroy (&self);

    //  Create pair of sockets we can send through
    zctx_t *ctx = zctx_new ();
    assert (ctx);

    void *output = zsocket_new (ctx, ZMQ_DEALER);
    assert (output);
    zsocket_bind (output, "inproc://selftest");
    void *input = zsocket_new (ctx, ZMQ_ROUTER);
    assert (input);
    zsocket_connect (input, "inproc://selftest");
    
    //  Encode/send/decode and verify each message type

    self = zre_msg_new (ZRE_MSG_HELLO);
    zre_msg_set_sequence (self, 123);
    zre_msg_set_ipaddress (self, "Life is short but Now lasts for ever");
    zre_msg_set_mailbox (self, 123);
    zre_msg_groups_append (self, "Name: %s", "Brutus");
    zre_msg_groups_append (self, "Age: %d", 43);
    zre_msg_set_status (self, 123);
    zre_msg_headers_insert (self, "Name", "Brutus");
    zre_msg_headers_insert (self, "Age", "%d", 43);
    zre_msg_send (&self, output);
    
    self = zre_msg_recv (input);
    assert (self);
    assert (zre_msg_sequence (self) == 123);
    assert (streq (zre_msg_ipaddress (self), "Life is short but Now lasts for ever"));
    assert (zre_msg_mailbox (self) == 123);
    assert (zre_msg_groups_size (self) == 2);
    assert (streq (zre_msg_groups_first (self), "Name: Brutus"));
    assert (streq (zre_msg_groups_next (self), "Age: 43"));
    assert (zre_msg_status (self) == 123);
    assert (zre_msg_headers_size (self) == 2);
    assert (streq (zre_msg_headers_string (self, "Name", "?"), "Brutus"));
    assert (zre_msg_headers_number (self, "Age", 0) == 43);
    zre_msg_destroy (&self);

    self = zre_msg_new (ZRE_MSG_WHISPER);
    zre_msg_set_sequence (self, 123);
    zre_msg_set_content (self, zframe_new ("Captcha Diem", 12));
    zre_msg_send (&self, output);
    
    self = zre_msg_recv (input);
    assert (self);
    assert (zre_msg_sequence (self) == 123);
    assert (zframe_streq (zre_msg_content (self), "Captcha Diem"));
    zre_msg_destroy (&self);

    self = zre_msg_new (ZRE_MSG_SHOUT);
    zre_msg_set_sequence (self, 123);
    zre_msg_set_group (self, "Life is short but Now lasts for ever");
    zre_msg_set_content (self, zframe_new ("Captcha Diem", 12));
    zre_msg_send (&self, output);
    
    self = zre_msg_recv (input);
    assert (self);
    assert (zre_msg_sequence (self) == 123);
    assert (streq (zre_msg_group (self), "Life is short but Now lasts for ever"));
    assert (zframe_streq (zre_msg_content (self), "Captcha Diem"));
    zre_msg_destroy (&self);

    self = zre_msg_new (ZRE_MSG_JOIN);
    zre_msg_set_sequence (self, 123);
    zre_msg_set_group (self, "Life is short but Now lasts for ever");
    zre_msg_set_status (self, 123);
    zre_msg_send (&self, output);
    
    self = zre_msg_recv (input);
    assert (self);
    assert (zre_msg_sequence (self) == 123);
    assert (streq (zre_msg_group (self), "Life is short but Now lasts for ever"));
    assert (zre_msg_status (self) == 123);
    zre_msg_destroy (&self);

    self = zre_msg_new (ZRE_MSG_LEAVE);
    zre_msg_set_sequence (self, 123);
    zre_msg_set_group (self, "Life is short but Now lasts for ever");
    zre_msg_set_status (self, 123);
    zre_msg_send (&self, output);
    
    self = zre_msg_recv (input);
    assert (self);
    assert (zre_msg_sequence (self) == 123);
    assert (streq (zre_msg_group (self), "Life is short but Now lasts for ever"));
    assert (zre_msg_status (self) == 123);
    zre_msg_destroy (&self);

    self = zre_msg_new (ZRE_MSG_PING);
    zre_msg_set_sequence (self, 123);
    zre_msg_send (&self, output);
    
    self = zre_msg_recv (input);
    assert (self);
    assert (zre_msg_sequence (self) == 123);
    zre_msg_destroy (&self);

    self = zre_msg_new (ZRE_MSG_PING_OK);
    zre_msg_set_sequence (self, 123);
    zre_msg_send (&self, output);
    
    self = zre_msg_recv (input);
    assert (self);
    assert (zre_msg_sequence (self) == 123);
    zre_msg_destroy (&self);

    zctx_destroy (&ctx);
    //  @end

    printf ("OK\n");
    return 0;
}