zbeacon(3)
==========

NAME
----
zbeacon - LAN service announcement and discovery

SYNOPSIS
--------
----
//  Create a new beacon on a certain UDP port
CZMQ_EXPORT zbeacon_t *
    zbeacon_new (int port_nbr);
    
//  Destroy a beacon
CZMQ_EXPORT void
    zbeacon_destroy (zbeacon_t **self_p);

//  Return our own IP address as printable string
CZMQ_EXPORT char *
    zbeacon_hostname (zbeacon_t *self);

//  Set broadcast interval in milliseconds (default is 1000 msec)
CZMQ_EXPORT void
    zbeacon_set_interval (zbeacon_t *self, int interval);

//  Filter out any beacon that looks exactly like ours
CZMQ_EXPORT void
    zbeacon_noecho (zbeacon_t *self);

//  Start broadcasting beacon to peers at the specified interval
CZMQ_EXPORT void
    zbeacon_publish (zbeacon_t *self, byte *transmit, size_t size);
    
//  Stop broadcasting beacons
CZMQ_EXPORT void
    zbeacon_silence (zbeacon_t *self);

//  Start listening to other peers; zero-sized filter means get everything
CZMQ_EXPORT void
    zbeacon_subscribe (zbeacon_t *self, byte *filter, size_t size);

//  Stop listening to other peers
CZMQ_EXPORT void
    zbeacon_unsubscribe (zbeacon_t *self);

//  Get beacon ZeroMQ socket, for polling or receiving messages
CZMQ_EXPORT void *
    zbeacon_socket (zbeacon_t *self);

//  Self test of this class
CZMQ_EXPORT void
    zbeacon_test (bool verbose);
----

DESCRIPTION
-----------

The zbeacon class implements a peer-to-peer discovery service for local
networks. A beacon can broadcast and/or capture service announcements
using UDP messages on the local area network. This implementation uses
IPv4 UDP broadcasts. You can define the format of your outgoing beacons,
and set a filter that validates incoming beacons. Beacons are sent and
received asynchronously in the background. The zbeacon API provides a
incoming beacons on a ZeroMQ socket (the pipe) that you can configure,
poll on, and receive messages on. Incoming beacons are always delivered
as two frames: the ipaddress of the sender (a string), and the beacon
data itself (binary, as published).


EXAMPLE
-------
.From zbeacon_test method
----
    //  Basic test: create a service and announce it
    zctx_t *ctx = zctx_new ();

    //  Create a service socket and bind to an ephemeral port
    void *service = zsocket_new (ctx, ZMQ_PUB);
    int port_nbr = zsocket_bind (service, "tcp://*:*");
    
    //  Create beacon to broadcast our service
    byte announcement [2] = { (port_nbr >> 8) & 0xFF, port_nbr & 0xFF };
    zbeacon_t *service_beacon = zbeacon_new (9999);
    zbeacon_set_interval (service_beacon, 100);
    zbeacon_publish (service_beacon, announcement, 2);

    //  Create beacon to lookup service
    zbeacon_t *client_beacon = zbeacon_new (9999);
    zbeacon_subscribe (client_beacon, NULL, 0);

    //  Wait for at most 1/2 second if there's no broadcast networking
    zsocket_set_rcvtimeo (zbeacon_socket (client_beacon), 500);

    char *ipaddress = zstr_recv (zbeacon_socket (client_beacon));
    if (ipaddress) {
        zframe_t *content = zframe_recv (zbeacon_socket (client_beacon));
        int received_port = (zframe_data (content) [0] << 8)
                        +  zframe_data (content) [1];
        assert (received_port == port_nbr);
        zframe_destroy (&content);
        free (ipaddress);
    }
    zbeacon_destroy (&client_beacon);
    zbeacon_destroy (&service_beacon);
    zctx_destroy (&ctx);
    
    zbeacon_t *node1 = zbeacon_new (5670);
    zbeacon_t *node2 = zbeacon_new (5670);
    zbeacon_t *node3 = zbeacon_new (5670);

    assert (*zbeacon_hostname (node1));
    assert (*zbeacon_hostname (node2));
    assert (*zbeacon_hostname (node3));
    
    zbeacon_set_interval (node1, 250);
    zbeacon_set_interval (node2, 250);
    zbeacon_set_interval (node3, 250);
    zbeacon_noecho (node1);
    zbeacon_publish (node1, (byte *) "NODE/1", 6);
    zbeacon_publish (node2, (byte *) "NODE/2", 6);
    zbeacon_publish (node3, (byte *) "GARBAGE", 7);
    zbeacon_subscribe (node1, (byte *) "NODE", 4);

    //  Poll on three API sockets at once
    zpoller_t *poller = zpoller_new (
        zbeacon_socket (node1), 
        zbeacon_socket (node2), 
        zbeacon_socket (node3), NULL);
        
    int64_t stop_at = zclock_time () + 1000;
    while (zclock_time () < stop_at) {
        long timeout = (long) (stop_at - zclock_time ());
        if (timeout < 0)
            timeout = 0;
        void *which = zpoller_wait (poller, timeout * ZMQ_POLL_MSEC);
        if (which) {
            assert (which == zbeacon_socket (node1));
            char *ipaddress, *beacon;
            zstr_recvx (zbeacon_socket (node1), &ipaddress, &beacon, NULL);
            assert (streq (beacon, "NODE/2"));
            free (ipaddress);
            free (beacon);
        }
    }
    zpoller_destroy (&poller);
    
    //  Stop listening
    zbeacon_unsubscribe (node1);
    
    //  Stop all node broadcasts
    zbeacon_silence (node1);
    zbeacon_silence (node2);
    zbeacon_silence (node3);

    //  Destroy the test nodes
    zbeacon_destroy (&node1);
    zbeacon_destroy (&node2);
    zbeacon_destroy (&node3);
----

SEE ALSO
--------
linkczmq:czmq[7]
