Exemplo n.º 1
0
void
zyre_peer_refresh (zyre_peer_t *self, uint64_t evasive_timeout, uint64_t expired_timeout)
{
    assert (self);
    self->evasive_at = zclock_mono () + evasive_timeout;
    self->expired_at = zclock_mono () + expired_timeout;
}
Exemplo n.º 2
0
static int
zyre_node_ping_peer (const char *key, void *item, void *argument)
{
    zyre_peer_t *peer = (zyre_peer_t *) item;
    zyre_node_t *self = (zyre_node_t *) argument;
    if (zclock_mono () >= zyre_peer_expired_at (peer)) {
        if (self->verbose)
            zsys_info ("(%s) peer expired name=%s endpoint=%s",
                self->name, zyre_peer_name (peer), zyre_peer_endpoint (peer));
        zyre_node_remove_peer (self, peer);
    }
    else
    if (zclock_mono () >= zyre_peer_evasive_at (peer)) {
        //  If peer is being evasive, force a TCP ping.
        //  TODO: do this only once for a peer in this state;
        //  it would be nicer to use a proper state machine
        //  for peer management.
        if (self->verbose)
            zsys_info ("(%s) peer seems dead/slow name=%s endpoint=%s",
                self->name, zyre_peer_name (peer), zyre_peer_endpoint (peer));
        zre_msg_t *msg = zre_msg_new (ZRE_MSG_PING);
        zyre_peer_send (peer, &msg);
        // Inform the calling application this peer is being evasive
    	zstr_sendm (self->outbox, "EVASIVE");
	zstr_sendm (self->outbox, zyre_peer_identity (peer));
    	zstr_send (self->outbox, zyre_peer_name (peer));
    }
    return 0;
}
Exemplo n.º 3
0
static long
s_tickless (zloop_t *self)
{
    //  Calculate tickless timer, up to 1 hour
    int64_t tickless = zclock_mono () + 1000 * 3600;
    
    //  Scan timers, which are not sorted
    //  TODO: sort timers properly on insertion
    s_timer_t *timer = (s_timer_t *) zlistx_first (self->timers);
    while (timer) {
        //  Find earliest timer
        if (tickless > timer->when)
            tickless = timer->when;
        timer = (s_timer_t *) zlistx_next (self->timers);
    }
    //  Tickets are sorted, so check first ticket
    s_ticket_t *ticket = (s_ticket_t *) zlistx_first (self->tickets);
    if (ticket && tickless > ticket->when)
        tickless = ticket->when;

    long timeout = (long) (tickless - zclock_mono ());
    if (timeout < 0)
        timeout = 0;
    if (self->verbose)
        zsys_debug ("zloop polling for %d msec", (int) timeout);
    
    return timeout * ZMQ_POLL_MSEC;
}
Exemplo n.º 4
0
//  --------------------------------------------------------------------------
//  Self test of this class
void
zclock_test (bool verbose)
{
    printf (" * zclock: ");

    //  @selftest
    int64_t start = zclock_time ();
    zclock_sleep (10);
    assert ((zclock_time () - start) >= 10);
    start = zclock_mono ();
    int64_t usecs = zclock_usecs ();
    zclock_sleep (10);
    assert ((zclock_mono () - start) >= 10);
    assert ((zclock_usecs () - usecs) >= 10000);
    char *timestr = zclock_timestr ();
    if (verbose)
        puts (timestr);
    freen (timestr);

#if defined (__WINDOWS__)
    zsys_shutdown();
#endif
    //  @end

    printf ("OK\n");
}
Exemplo n.º 5
0
void
zloop_ticket_reset (zloop_t *self, void *handle)
{
    s_ticket_t *ticket = (s_ticket_t *) handle;
    assert (ticket->tag == TICKET_TAG);
    ticket->when = zclock_mono () + ticket->delay;
    zlistx_move_end (self->tickets, ticket->list_handle);
}
Exemplo n.º 6
0
Arquivo: zloop.c Projeto: skaes/czmq
static s_ticket_t *
s_ticket_new (size_t delay, zloop_timer_fn handler, void *arg)
{
    s_ticket_t *self = (s_ticket_t *) zmalloc (sizeof (s_ticket_t));
    assert (self);
    self->tag = TICKET_TAG;
    self->delay = delay;
    self->when = zclock_mono () + delay;
    self->handler = handler;
    self->arg = arg;
    return self;
}
Exemplo n.º 7
0
void
zbeacon (zsock_t *pipe, void *args)
{
    self_t *self = s_self_new (pipe);
    assert (self);
    //  Signal successful initialization
    zsock_signal (pipe, 0);

    while (!self->terminated) {
        //  Poll on API pipe and on UDP socket
        zmq_pollitem_t pollitems [] = {
            { zsock_resolve (self->pipe), 0, ZMQ_POLLIN, 0 },
            { NULL, self->udpsock, ZMQ_POLLIN, 0 }
        };
        long timeout = -1;
        if (self->transmit) {
            timeout = (long) (self->ping_at - zclock_mono ());
            if (timeout < 0)
                timeout = 0;
        }
        int pollset_size = self->udpsock? 2: 1;
        if (zmq_poll (pollitems, pollset_size, timeout * ZMQ_POLL_MSEC) == -1)
            break;              //  Interrupted

        if (pollitems [0].revents & ZMQ_POLLIN)
            s_self_handle_pipe (self);
        if (pollitems [1].revents & ZMQ_POLLIN)
            s_self_handle_udp (self);

        if (self->transmit
        &&  zclock_mono () >= self->ping_at) {
            //  Send beacon to any listening peers
            if (zsys_udp_send (self->udpsock, self->transmit, &self->broadcast, sizeof (inaddr_t)))
                //  Try to recreate UDP socket on interface
                s_self_prepare_udp (self);
            self->ping_at = zclock_mono () + self->interval;
        }
    }
    s_self_destroy (&self);
}
Exemplo n.º 8
0
static int
s_self_handle_pipe (self_t *self)
{
    //  Get just the command off the pipe
    char *command = zstr_recv (self->pipe);
    if (!command)
        return -1;                  //  Interrupted

    if (self->verbose)
        zsys_info ("zbeacon: API command=%s", command);

    if (streq (command, "VERBOSE"))
        self->verbose = true;
    else
    if (streq (command, "CONFIGURE")) {
        int port;
        int rc = zsock_recv (self->pipe, "i", &port);
        assert (rc == 0);
        s_self_configure (self, port);
    }
    else
    if (streq (command, "PUBLISH")) {
        zframe_destroy (&self->transmit);
        zsock_recv (self->pipe, "fi", &self->transmit, &self->interval);
        assert (zframe_size (self->transmit) <= UDP_FRAME_MAX);
        if (self->interval == 0)
            self->interval = INTERVAL_DFLT;
        //  Start broadcasting immediately
        self->ping_at = zclock_mono ();
    }
    else
    if (streq (command, "SILENCE"))
        zframe_destroy (&self->transmit);
    else
    if (streq (command, "SUBSCRIBE")) {
        zframe_destroy (&self->filter);
        self->filter = zframe_recv (self->pipe);
        assert (zframe_size (self->filter) <= UDP_FRAME_MAX);
    }
    else
    if (streq (command, "UNSUBSCRIBE"))
        zframe_destroy (&self->filter);
    else
    if (streq (command, "$TERM"))
        self->terminated = true;
    else {
        zsys_error ("zbeacon: - invalid command: %s", command);
        assert (false);
    }
    zstr_free (&command);
    return 0;
}
Exemplo n.º 9
0
Arquivo: zloop.c Projeto: skaes/czmq
static s_timer_t *
s_timer_new (int timer_id, size_t delay, size_t times, zloop_timer_fn handler, void *arg)
{
    s_timer_t *self = (s_timer_t *) zmalloc (sizeof (s_timer_t));
    assert (self);
    self->timer_id = timer_id;
    self->delay = delay;
    self->times = times;
    self->when = zclock_mono () + delay;
    self->handler = handler;
    self->arg = arg;
    return self;
}
Exemplo n.º 10
0
static void
node_actor (zsock_t *pipe, void *args)
{
    zyre_t *node = zyre_new (NULL);
    if (!node)
        return;                 //  Could not create new node
    zyre_set_verbose (node);

    zyre_set_endpoint (node, "inproc://%s", (char *) args);
    free (args);

    //  Connect to test hub
    zyre_gossip_connect (node, "inproc://zyre-hub");
    zyre_start (node);
    zsock_signal (pipe, 0);     //  Signal "ready" to caller

    int counter = 0;
    char *to_peer = NULL;        //  Either of these set,
    char *to_group = NULL;       //    and we set a message
    char *cookie = NULL;

    zpoller_t *poller = zpoller_new (pipe, zyre_socket (node), NULL);
    int64_t trigger = zclock_mono () + 1000;
    while (true) {
        void *which = zpoller_wait (poller, randof (1000));
        if (!which)
            break;              //  Interrupted

        //  $TERM from parent means exit; anything else is breach of
        //  contract so we should assert
        if (which == pipe) {
            char *command = zstr_recv (pipe);
            assert (streq (command, "$TERM"));
            zstr_free (&command);
            break;              //  Finished
        }
        //  Process an event from node
        if (which == zyre_socket (node)) {
            zmsg_t *incoming = zyre_recv (node);
            if (!incoming)
                break;          //  Interrupted

            char *event = zmsg_popstr (incoming);
            char *peer = zmsg_popstr (incoming);
            char *name = zmsg_popstr (incoming);
            if (streq (event, "ENTER"))
                //  Always say hello to new peer
                to_peer = strdup (peer);
            else
            if (streq (event, "EXIT"))
                //  Always try talk to departed peer
                to_peer = strdup (peer);
            else
            if (streq (event, "WHISPER")) {
                //  Send back response 1/2 the time
                if (randof (2) == 0) {
                    to_peer = strdup (peer);
                    cookie = zmsg_popstr (incoming);
                }
            }
            else
            if (streq (event, "SHOUT")) {
                to_peer = strdup (peer);
                to_group = zmsg_popstr (incoming);
                cookie = zmsg_popstr (incoming);
                //  Send peer response 1/3rd the time
                if (randof (3) > 0) {
                    free (to_peer);
                    to_peer = NULL;
                }
                //  Send group response 1/3rd the time
                if (randof (3) > 0) {
                    free (to_group);
                    to_group = NULL;
                }
            }
            else
            if (streq (event, "JOIN")) {
                char *group = zmsg_popstr (incoming);
                printf ("I: %s joined %s\n", name, group);
                free (group);
            }
            else
            if (streq (event, "LEAVE")) {
                char *group = zmsg_popstr (incoming);
                printf ("I: %s left %s\n", name, group);
                free (group);
            }
            free (event);
            free (peer);
            free (name);
            zmsg_destroy (&incoming);

            //  Send outgoing messages if needed
            if (to_peer) {
                zyre_whispers (node, to_peer, "%d", counter++);
                free (to_peer);
                to_peer = NULL;
            }
            if (to_group) {
                zyre_shouts (node, to_group, "%d", counter++);
                free (to_group);
                to_group = NULL;
            }
            if (cookie) {
                free (cookie);
                cookie = NULL;
            }
        }
        if (zclock_mono () >= trigger) {
            trigger = zclock_mono () + 1000;
            char group [10];
            sprintf (group, "GROUP%03d", randof (MAX_GROUP));
            if (randof (4) == 0)
                zyre_join (node, group);
            else
            if (randof (3) == 0)
                zyre_leave (node, group);
        }
    }
    zpoller_destroy (&poller);
    zyre_destroy (&node);
}
Exemplo n.º 11
0
void
zbeacon_test (bool verbose)
{
    printf (" * zbeacon: ");
    if (verbose)
        printf ("\n");

    //  @selftest
    //  Test 1 - two beacons, one speaking, one listening
    //  Create speaker beacon to broadcast our service
    zactor_t *speaker = zactor_new (zbeacon, NULL);
    assert (speaker);
    if (verbose)
        zstr_sendx (speaker, "VERBOSE", NULL);

    zsock_send (speaker, "si", "CONFIGURE", 9999);
    char *hostname = zstr_recv (speaker);
    if (!*hostname) {
        printf ("OK (skipping test, no UDP broadcasting)\n");
        zactor_destroy (&speaker);
        free (hostname);
        return;
    }
    free (hostname);

    //  Create listener beacon on port 9999 to lookup service
    zactor_t *listener = zactor_new (zbeacon, NULL);
    assert (listener);
    if (verbose)
        zstr_sendx (listener, "VERBOSE", NULL);
    zsock_send (listener, "si", "CONFIGURE", 9999);
    hostname = zstr_recv (listener);
    assert (*hostname);
    free (hostname);

    //  We will broadcast the magic value 0xCAFE
    byte announcement [2] = { 0xCA, 0xFE };
    zsock_send (speaker, "sbi", "PUBLISH", announcement, 2, 100);
    //  We will listen to anything (empty subscription)
    zsock_send (listener, "sb", "SUBSCRIBE", "", 0);

    //  Wait for at most 1/2 second if there's no broadcasting
    zsock_set_rcvtimeo (listener, 500);
    char *ipaddress = zstr_recv (listener);
    if (ipaddress) {
        zframe_t *content = zframe_recv (listener);
        assert (zframe_size (content) == 2);
        assert (zframe_data (content) [0] == 0xCA);
        assert (zframe_data (content) [1] == 0xFE);
        zframe_destroy (&content);
        zstr_free (&ipaddress);
        zstr_sendx (speaker, "SILENCE", NULL);
    }
    zactor_destroy (&listener);
    zactor_destroy (&speaker);

    //  Test subscription filter using a 3-node setup
    zactor_t *node1 = zactor_new (zbeacon, NULL);
    assert (node1);
    zsock_send (node1, "si", "CONFIGURE", 5670);
    hostname = zstr_recv (node1);
    assert (*hostname);
    free (hostname);

    zactor_t *node2 = zactor_new (zbeacon, NULL);
    assert (node2);
    zsock_send (node2, "si", "CONFIGURE", 5670);
    hostname = zstr_recv (node2);
    assert (*hostname);
    free (hostname);

    zactor_t *node3 = zactor_new (zbeacon, NULL);
    assert (node3);
    zsock_send (node3, "si", "CONFIGURE", 5670);
    hostname = zstr_recv (node3);
    assert (*hostname);
    free (hostname);

    zsock_send (node1, "sbi", "PUBLISH", "NODE/1", 6, 250);
    zsock_send (node2, "sbi", "PUBLISH", "NODE/2", 6, 250);
    zsock_send (node3, "sbi", "PUBLISH", "RANDOM", 6, 250);
    zsock_send (node1, "sb", "SUBSCRIBE", "NODE", 4);

    //  Poll on three API sockets at once
    zpoller_t *poller = zpoller_new (node1, node2, node3, NULL);
    assert (poller);
    int64_t stop_at = zclock_mono () + 1000;
    while (zclock_mono () < stop_at) {
        long timeout = (long) (stop_at - zclock_mono ());
        if (timeout < 0)
            timeout = 0;
        void *which = zpoller_wait (poller, timeout * ZMQ_POLL_MSEC);
        if (which) {
            assert (which == node1);
            char *ipaddress, *received;
            zstr_recvx (node1, &ipaddress, &received, NULL);
            assert (streq (received, "NODE/2"));
            zstr_free (&ipaddress);
            zstr_free (&received);
        }
    }
    zpoller_destroy (&poller);

    //  Stop listening
    zstr_sendx (node1, "UNSUBSCRIBE", NULL);

    //  Stop all node broadcasts
    zstr_sendx (node1, "SILENCE", NULL);
    zstr_sendx (node2, "SILENCE", NULL);
    zstr_sendx (node3, "SILENCE", NULL);

    //  Destroy the test nodes
    zactor_destroy (&node1);
    zactor_destroy (&node2);
    zactor_destroy (&node3);
    //  @end
    printf ("OK\n");
}
Exemplo n.º 12
0
int
zloop_start (zloop_t *self)
{
    assert (self);
    int rc = 0;

    //  Main reactor loop
    while (!zsys_interrupted) {
        if (self->need_rebuild) {
            //  If s_rebuild_pollset() fails, break out of the loop and
            //  return its error
            rc = s_rebuild_pollset (self);
            if (rc)
                break;
        }
        rc = zmq_poll (self->pollset, (int) self->poll_size, s_tickless (self));
        if (rc == -1 || zsys_interrupted) {
            if (self->verbose)
                zsys_debug ("zloop: interrupted");
            rc = 0;
            break;              //  Context has been shut down
        }
        
        //  Handle any timers that have now expired
        int64_t time_now = zclock_mono ();
        s_timer_t *timer = (s_timer_t *) zlistx_first (self->timers);
        while (timer) {
            if (time_now >= timer->when) {
                if (self->verbose)
                    zsys_debug ("zloop: call timer handler id=%d", timer->timer_id);
                rc = timer->handler (self, timer->timer_id, timer->arg);
                if (rc == -1)
                    break;      //  Timer handler signaled break
                if (timer->times && --timer->times == 0)
                    zlistx_delete (self->timers, timer->list_handle);
                else
                    timer->when += timer->delay;
            }
            timer = (s_timer_t *) zlistx_next (self->timers);
        }
        
        //  Handle any tickets that have now expired
        s_ticket_t *ticket = (s_ticket_t *) zlistx_first (self->tickets);
        while (ticket && time_now >= ticket->when) {
            if (self->verbose)
                zsys_debug ("zloop: call ticket handler");
            rc = ticket->handler (self, 0, ticket->arg);
            if (rc == -1)
                break;      //  Timer handler signaled break
            zlistx_delete (self->tickets, ticket->list_handle);
            ticket = (s_ticket_t *) zlistx_next (self->tickets);
        }
        
        //  Handle any readers and pollers that are ready
        size_t item_nbr;
        for (item_nbr = 0; item_nbr < self->poll_size && rc >= 0; item_nbr++) {
            s_reader_t *reader = &self->readact [item_nbr];
            if (reader->handler) {
                if ((self->pollset [item_nbr].revents & ZMQ_POLLERR)
                && !reader->tolerant) {
                    if (self->verbose)
                        zsys_warning ("zloop: can't read %s socket: %s",
                                      zsock_type_str (reader->sock),
                                      zmq_strerror (zmq_errno ()));
                    //  Give handler one chance to handle error, then kill
                    //  reader because it'll disrupt the reactor otherwise.
                    if (reader->errors++) {
                        zloop_reader_end (self, reader->sock);
                        self->pollset [item_nbr].revents = 0;
                    }
                }
                else
                    reader->errors = 0;     //  A non-error happened

                if (self->pollset [item_nbr].revents) {
                    if (self->verbose)
                        zsys_debug ("zloop: call %s socket handler",
                                    zsock_type_str (reader->sock));
                    rc = reader->handler (self, reader->sock, reader->arg);
                    if (rc == -1 || self->need_rebuild)
                        break;
                }
            }
            else {
                s_poller_t *poller = &self->pollact [item_nbr];
                assert (self->pollset [item_nbr].socket == poller->item.socket);

                if ((self->pollset [item_nbr].revents & ZMQ_POLLERR)
                && !poller->tolerant) {
                    if (self->verbose)
                        zsys_warning ("zloop: can't poll %s socket (%p, %d): %s",
                                      poller->item.socket ?
                                      zsys_sockname (zsock_type (poller->item.socket)) : "FD",
                                      poller->item.socket, poller->item.fd,
                                      zmq_strerror (zmq_errno ()));
                    //  Give handler one chance to handle error, then kill
                    //  poller because it'll disrupt the reactor otherwise.
                    if (poller->errors++) {
                        zloop_poller_end (self, &poller->item);
                        self->pollset [item_nbr].revents = 0;
                    }
                }
                else
                    poller->errors = 0;     //  A non-error happened

                if (self->pollset [item_nbr].revents) {
                    if (self->verbose)
                        zsys_debug ("zloop: call %s socket handler (%p, %d)",
                                    poller->item.socket ?
                                    zsys_sockname (zsock_type (poller->item.socket)) : "FD",
                                    poller->item.socket, poller->item.fd);
                    rc = poller->handler (self, &self->pollset [item_nbr], poller->arg);
                    if (rc == -1 || self->need_rebuild)
                        break;
                }
            }
        }
        //  Now handle any timer zombies
        //  This is going to be slow if we have many timers; we might use
        //  a faster lookup on the timer list.
        while (zlistx_first (self->zombies)) {
            //  Get timer_id back from pointer
            int timer_id = (byte *) zlistx_detach (self->zombies, NULL) - (byte *) NULL;
            s_timer_remove (self, timer_id);
        }
        if (rc == -1)
            break;
    }
    self->terminated = true;
    return rc;
}
Exemplo n.º 13
0
void
zyre_node_actor (zsock_t *pipe, void *args)
{
    //  Create node instance to pass around
    zyre_node_t *self = zyre_node_new (pipe, args);
    if (!self)                  //  Interrupted
        return;

    //  Signal actor successfully initialized
    zsock_signal (self->pipe, 0);

    //  Loop until the agent is terminated one way or another
    int64_t reap_at = zclock_mono () + REAP_INTERVAL;
    while (!self->terminated) {

        // Start beacon as soon as we can
        if (self->beacon && self->port <= 0) {
            //  Our hostname is provided by zbeacon
            zsock_send(self->beacon, "si", "CONFIGURE", self->beacon_port);
            char *hostname = zstr_recv(self->beacon);

            // Is UDP broadcast interface available?
            if (!streq(hostname, "")) {
                if (zsys_ipv6())
                    self->port = zsock_bind(self->inbox, "tcp://%s%%%s:*", zsys_ipv6_address(), zsys_interface());
                else
                    self->port = zsock_bind(self->inbox, "tcp://%s:*", hostname);

                if (self->port > 0) {
                    assert(!self->endpoint);   //  If caller set this, we'd be using gossip
                    if (streq(zsys_interface(), "*")) {
                        char *hostname = zsys_hostname();
                        self->endpoint = zsys_sprintf("tcp://%s:%d", hostname, self->port);
                        zstr_free(&hostname);
                    }
                    else {
                        self->endpoint = strdup(zsock_endpoint(self->inbox));
                    }

                    //  Set broadcast/listen beacon
                    beacon_t beacon;
                    beacon.protocol[0] = 'Z';
                    beacon.protocol[1] = 'R';
                    beacon.protocol[2] = 'E';
                    beacon.version = BEACON_VERSION;
                    beacon.port = htons(self->port);
                    zuuid_export(self->uuid, beacon.uuid);
                    zsock_send(self->beacon, "sbi", "PUBLISH",
                        (byte *)&beacon, sizeof(beacon_t), self->interval);
                    zsock_send(self->beacon, "sb", "SUBSCRIBE", (byte *) "ZRE", 3);
                    zpoller_add(self->poller, self->beacon);

                    //  Start polling on inbox
                    zpoller_add(self->poller, self->inbox);
                }
            }
            zstr_free(&hostname);
        }

        int timeout = (int) (reap_at - zclock_mono ());
        if (timeout > REAP_INTERVAL)
            timeout = REAP_INTERVAL;
        else
        if (timeout < 0)
            timeout = 0;

        zsock_t *which = (zsock_t *) zpoller_wait (self->poller, timeout);
        if (which == self->pipe)
            zyre_node_recv_api (self);
        else
        if (which == self->inbox)
            zyre_node_recv_peer (self);
        else
        if (self->beacon
        && (void *) which == self->beacon)
            zyre_node_recv_beacon (self);
        else
        if (self->gossip
        && (zactor_t *) which == self->gossip)
            zyre_node_recv_gossip (self);
        else
        if (zpoller_terminated (self->poller))
            break;          //  Interrupted, check before expired
        else
        if (zpoller_expired (self->poller)) {
            if (zclock_mono () >= reap_at) {
                void *item;
                reap_at = zclock_mono () + REAP_INTERVAL;
                //  Ping all peers and reap any expired ones
                for (item = zhash_first (self->peers); item != NULL;
                        item = zhash_next (self->peers))
                    zyre_node_ping_peer (zhash_cursor (self->peers), item, self);
            }
        }
    }
    zyre_node_destroy (&self);
}
Exemplo n.º 14
0
int
main (int argn, char *argv [])
{
    //  Raise theoretical limit on how many ZeroMQ sockets we can create,
    //  though real limit will be set by the process file handle limit.
    zsys_set_max_sockets (65535);

    //  Test case 1: two servers, bunch of clients.
    printf ("Starting small test case: ");
    fflush (stdout);

    zactor_t *server1 = zactor_new (zgossip, "server1");
    assert (server1);
    zstr_sendx (server1, "SET", "server/animate", "0", NULL);
    zstr_sendx (server1, "BIND", "inproc://server1", NULL);

    zactor_t *server2 = zactor_new (zgossip, "server2");
    assert (server2);
    zstr_sendx (server2, "SET", "server/animate", "0", NULL);
    zstr_sendx (server2, "BIND", "inproc://server2", NULL);
    zstr_sendx (server2, "CONNECT", "inproc://server1", NULL);

    zactor_t *client1 = zactor_new (zgossip, "client1");
    assert (client1);
    zstr_sendx (client1, "BIND", "inproc://client1", NULL);
    zstr_sendx (client1, "PUBLISH", "client1-00", "0000", NULL);
    zstr_sendx (client1, "PUBLISH", "client1-11", "1111", NULL);
    zstr_sendx (client1, "PUBLISH", "client1-22", "2222", NULL);
    zstr_sendx (client1, "CONNECT", "inproc://server1", NULL);

    zactor_t *client2 = zactor_new (zgossip, "client2");
    assert (client2);
    zstr_sendx (client2, "BIND", "inproc://client2", NULL);
    zstr_sendx (client2, "CONNECT", "inproc://server1", NULL);
    zstr_sendx (client2, "PUBLISH", "client2-00", "0000", NULL);
    zstr_sendx (client2, "PUBLISH", "client2-11", "1111", NULL);
    zstr_sendx (client2, "PUBLISH", "client2-22", "2222", NULL);

    zactor_t *client3 = zactor_new (zgossip, "client3");
    assert (client3);
    zstr_sendx (client3, "CONNECT", "inproc://server2", NULL);

    zactor_t *client4 = zactor_new (zgossip, "client4");
    assert (client4);
    zstr_sendx (client4, "CONNECT", "inproc://server2", NULL);

    zclock_sleep (100);

    assert_status (server1, 6);
    assert_status (server2, 6);
    assert_status (client1, 6);
    assert_status (client2, 6);
    assert_status (client3, 6);
    assert_status (client4, 6);

    zactor_destroy (&server1);
    zactor_destroy (&server2);
    zactor_destroy (&client1);
    zactor_destroy (&client2);
    zactor_destroy (&client3);
    zactor_destroy (&client4);
    printf ("OK\n");

    //  Test case 2: swarm of peers
    printf ("Starting swarm test case: ");
    fflush (stdout);

    //  Default limit on file handles is 1024 (POSIX), and fixed setup
    //  costs 8 handles (3 standard I/O plus 5 for CZMQ/libzmq). So the
    //  most nodes we can test by default is (1024 - 8) / 4 = 254. To
    //  test more, run "ulimit -n xxx" beforehand and pass swarm size
    //  as argument to this program. With e.g. Ubuntu, ceiling is 4K
    //  file handles per process, so the largest swarm I've tested is
    //  1022 nodes.
    int swarm_size = 254;
    if (argn >= 2)
        swarm_size = atoi (argv [1]);
    printf ("swarm_size=%d ", swarm_size);

    //  The set size defines the total number of properties we spread
    //  across the swarm. By default this is the swarm_size * 5. You can
    //  specify a different set size as second command line argument.
    int set_size = swarm_size * 5;
    if (argn >= 3)
        set_size = atoi (argv [2]);
    printf ("set_size=%d ", set_size);

    //  Swarm is an array of actors
    zactor_t *nodes [swarm_size];
    //  We'll poll all actors for activity (actors act like sockets)
    zpoller_t *poller = zpoller_new (NULL);
    assert (poller);

    //  Create swarm
    uint node_nbr;
    for (node_nbr = 0; node_nbr < swarm_size; node_nbr++) {
        nodes [node_nbr] = zactor_new (zgossip, NULL);
        assert (nodes [node_nbr]);
        zpoller_add (poller, nodes [node_nbr]);
    }
    printf (".");
    fflush (stdout);

    //  Interconnect swarm; ever node connects to one arbitrary node to
    //  create a directed graph, then oldest node connects to youngest
    //  node to create a loop, to test we're robust against cycles.
    for (node_nbr = 0; node_nbr < swarm_size; node_nbr++) {
        zstr_sendm (nodes [node_nbr], "BIND");
        zstr_sendf (nodes [node_nbr], "inproc://swarm-%d", node_nbr);
        if (node_nbr > 0) {
            zstr_sendm (nodes [node_nbr], "CONNECT");
            zstr_sendf (nodes [node_nbr], "inproc://swarm-%d", randof (node_nbr));
        }
    }
    zstr_sendm (nodes [0], "CONNECT");
    zstr_sendf (nodes [0], "inproc://swarm-%d", node_nbr - 1);
    printf (".");
    fflush (stdout);

    //  Publish the data set randomly across the swarm
    int item_nbr;
    for (item_nbr = 0; item_nbr < set_size; item_nbr++) {
        node_nbr = randof (swarm_size);
        assert (node_nbr != swarm_size);
        assert (node_nbr < swarm_size);
        zstr_sendm (nodes [node_nbr], "PUBLISH");
        zstr_sendfm (nodes [node_nbr], "key-%d", item_nbr);
        zstr_send (nodes [node_nbr], "value");
    }
    printf (". ");
    fflush (stdout);

    //  Each actor will deliver us tuples; count these until we're done
    int total = set_size * swarm_size;
    int pending = total;
    int64_t ticker = zclock_mono () + 2000;
    while (pending) {
        zsock_t *which = (zsock_t *) zpoller_wait (poller, 100);
        if (!which) {
            puts (" - stuck test, aborting");
            break;
        }
        char *command;
        zstr_recvx (which, &command, NULL);
        assert (streq (command, "DELIVER"));
        pending--;
        freen (command);
        if (zclock_mono () > ticker) {
            printf ("(%d%%)", (int) ((100 * (total - pending)) / total));
            fflush (stdout);
            ticker = zclock_mono () + 2000;
        }
    }
    //  Destroy swarm
    for (node_nbr = 0; node_nbr < swarm_size; node_nbr++)
        zactor_destroy (&nodes [node_nbr]);

    printf ("(100%%) OK\n");

#if defined (__WINDOWS__)
    zsys_shutdown();
#endif

    return 0;
}