Coder Social home page Coder Social logo

zeromq / zyre Goto Github PK

View Code? Open in Web Editor NEW
849.0 61.0 179.0 5.35 MB

Zyre - an open-source framework for proximity-based peer-to-peer applications

License: Mozilla Public License 2.0

CMake 3.23% Shell 7.40% Python 22.50% Ruby 3.18% QMake 0.69% C++ 20.39% QML 0.01% Makefile 0.44% C 26.99% Batchfile 4.08% Java 2.17% JavaScript 0.42% HTML 0.04% M4 2.55% Lua 0.99% Dockerfile 0.08% Pascal 4.04% NASL 0.80%

zyre's Introduction

GitHub release OBS draft OBS stable license

Zyre - Local Area Clustering for Peer-to-Peer Applications

Linux & MacOSX Windows
Build Status Build status

Contents

Overview

Scope and Goals

Ownership and License

Using Zyre

Building on Linux and macOS

Building on Windows

Building on Windows

Linking with an Application

Use from Other Languages

API Summary

Hints to Contributors

This Document

Overview

Scope and Goals

Zyre provides reliable group messaging over local area networks. It has these key characteristics:

  • Zyre needs no administration or configuration.
  • Peers may join and leave the network at any time.
  • Peers talk to each other without any central brokers or servers.
  • Peers can talk directly to each other.
  • Peers can join groups, and then talk to groups.
  • Zyre is reliable, and loses no messages even when the network is heavily loaded.
  • Zyre is fast and has low latency, requiring no consensus protocols.
  • Zyre is designed for WiFi networks, yet also works well on Ethernet networks.
  • Time for a new peer to join a network is about one second.

Typical use cases for Zyre are:

  • Local service discovery.
  • Clustering of a set of services on the same Ethernet network.
  • Controlling a network of smart devices (Internet of Things).
  • Multi-user mobile applications (like smart classrooms).

Technical details:

  • Uses RFC 36 (http://rfc.zeromq.org/spec:36/ZRE) protocol for discovery and heartbeating.
  • Uses reliable Dealer-Router pattern for interconnection, assuring that messages are not lost unless a peer application terminates.
  • Optimized for WiFi, using UDP broadcasts for discovery and heartbeating…
  • Offers alternative discovery mechanism (gossip) for Ethernet networks.

Ownership and License

The contributors are listed in AUTHORS. This project uses the MPL v2 license, see LICENSE.

Zyre uses the C4.1 (Collective Code Construction Contract) process for contributions.

Zyre uses the CLASS (C Language Style for Scalabilty) guide for code style.

To report an issue, use the Zyre issue tracker at github.com.

Using Zyre

Building on Linux and macOS

To start with, you need at least these packages:

  • git -- git is how we share code with other people.
  • build-essential, libtool, pkg-config - the C compiler and related tools.
  • autotools-dev, autoconf, automake - the GNU autoconf makefile generators.
  • cmake - the CMake makefile generators (an alternative to autoconf).

Plus some others:

  • uuid-dev, libpcre3-dev - utility libraries.
  • valgrind - a useful tool for checking your code.
  • pkg-config - an optional useful tool to make building with dependencies easier.

Which we install like this (using the Debian-style apt-get package manager):

    sudo apt-get update
    sudo apt-get install -y \
    git build-essential libtool \
    pkg-config autotools-dev autoconf automake cmake \
    uuid-dev libpcre3-dev valgrind

    # only execute this next line if interested in updating the man pages as
    # well (adds to build time):
    sudo apt-get install -y asciidoc

Here's how to build Zyre from GitHub (building from packages is very similar, you don't clone a repo but unpack a tarball), including the libsodium (for security) and libzmq (ZeroMQ core) libraries:

    git clone --depth 1 -b stable https://github.com/jedisct1/libsodium.git
    cd libsodium
    ./autogen.sh && ./configure && make check
    sudo make install
    cd ..

    git clone https://github.com/zeromq/libzmq.git
    cd libzmq
    ./autogen.sh
    # do not specify "--with-libsodium" if you prefer to use internal tweetnacl
    # security implementation (recommended for development)
    ./configure --with-libsodium
    make check
    sudo make install
    sudo ldconfig
    cd ..

    git clone https://github.com/zeromq/czmq.git
    cd czmq
    ./autogen.sh && ./configure && make check
    sudo make install
    sudo ldconfig
    cd ..

    git clone https://github.com/zeromq/zyre.git
    cd zyre
    ./autogen.sh && ./configure && make check
    sudo make install
    sudo ldconfig
    cd ..

Test by running the zyre_selftest command:

zyre/src/.libs/zyre_selftest

Test by running the zpinger command, from two or more PCs.

zyre/src/.libs/zpinger

Building on Windows

To start with, you need MS Visual Studio (C/C++). The free community edition works well.

Then, install git, and make sure it works from a DevStudio command prompt:

git

Now let's build Zyre from GitHub:

    git clone --depth 1 -b stable https://github.com/jedisct1/libsodium.git
    git clone https://github.com/zeromq/libzmq.git
    git clone https://github.com/zeromq/czmq.git
    git clone https://github.com/zeromq/zyre.git
    cd zyre\builds\msvc
    configure.bat
    cd build
    buildall.bat
    cd ..\..\..\..

Test by running the zyre_selftest command:

    dir/s/b zyre_selftest.exe
    zyre\builds\msvc\vs2013\DebugDEXE\zyre_selftest.exe
    zyre\builds\msvc\vs2013\ReleaseDEXE\zyre_selftest.exe

    :: select your choice and run it
    zyre\builds\msvc\vs2013\DebugDEXE\zyre_selftest.exe

Test by running zpinger from two or more PCs:

    dir/s/b zpinger.exe
    zyre\builds\msvc\vs2013\DebugDEXE\zpinger.exe
    zyre\builds\msvc\vs2013\ReleaseDEXE\zpinger.exe
    zyre\builds\msvc\vs2013\x64\DebugDEXE\zpinger.exe

    :: select your choice and run it
    zyre\builds\msvc\vs2013\ReleaseDEXE\zpinger.exe

Building on Windows

To start with, you need MS Visual Studio (C/C++). The free community edition works well.

Then, install git, and make sure it works from a DevStudio command prompt:

git

Using CMake

zyre requires czmq and libzmq, so we need to build libzmq first. For libzmq, you can optionally use libsodium as the curve encryption library. So we will start from building libsodium in the following (and you can bypass the building of libsodium if you are ok with libzmq's default curve encryption library):

git clone --depth 1 -b stable https://github.com/jedisct1/libsodium.git
cd libsodium\builds\msvc\build
buildall.bat
cd ..\..\..\..

Once done, you can find the library files under libsodium\bin\<Win32|x64>\<Debug|Release>\<Platform Toolset>\<dynamic|ltcg|static>.

Here, the <Platform Toolset> is the platform toolset you are using: v100 for VS2010, v140 for VS2015, v141 for VS2017, etc.

git clone https://github.com/zeromq/libzmq.git
cd libzmq
mkdir build
cd build
cmake .. -DBUILD_STATIC=OFF -DBUILD_SHARED=ON -DZMQ_BUILD_TESTS=ON -DWITH_LIBSODIUM=ON -DCMAKE_INCLUDE_PATH=..\libsodium\src\libsodium\include -DCMAKE_LIBRARY_PATH=..\libsodium\bin\Win32\Release\<Platform Toolset>\dynamic -DCMAKE_INSTALL_PREFIX=C:\projects\libs
cmake --build . --config Release --target install
cd ..\..\

-DWITH_LIBSODIUM=ON is necessary if you want to build libzmq with libsodium. CMAKE_INCLUDE_PATH option tells libzmq where to search for libsodium's header files. And the CMAKE_LIBRARY_PATH option tells where to search for libsodium library files. If you don't need libsodium support, you can omit these three options.

-DCMAKE_INSTALL_PREFIX=C:\libzmq means we want to install libzmq into the C:\libzmq. You may need to run your shell with administrator privilege in order to write to the system disk.

Next, let's build czmq:

git clone https://github.com/zeromq/czmq.git
cd czmq
mkdir build
cd build
cmake .. -DCZMQ_BUILD_SHARED=ON -DCZMQ_BUILD_STATIC=OFF -DCMAKE_PREFIX_PATH=C:\projects\libs -DCMAKE_INSTALL_PREFIX=C:\projects\libs
cmake --build . --config Release --target install

Remember that we installed libzmq to C:\projects\libs through specifying -DCMAKE_INSTALL_PREFIX in the previous step. We here use -DCMAKE_PREFIX_PATH=C:\projects\libs to tell czmq where to search for libzmq.

That is not the whole story. We didn't mention the building of libcurl, lz4, libuuid and other czmq optional libraries above. In fact, to build all of these optional libraries successfully is really tricky. Please refer issue #1972 for more details.

Now, it is time to build zyre:

git clone https://github.com/zeromq/zyre.git
cd zyre
mkdir build
cd build
cmake .. -DZYRE_BUILD_SHARED=ON -DZYRE_BUILD_STATIC=OFF -DCMAKE_PREFIX_PATH=C:\projects\libs
cmake --build . --config Release
ctest -C Release

Linking with an Application

Include zyre.h in your application and link with libzyre. Here is a typical gcc link command:

gcc myapp.c -lzyre -lczmq -lzmq -o myapp

Use from Other Languages

This is a list of auto-generated bindings:

API Summary

This is the API provided by Zyre 2.x, in alphabetical order.

zyre - API wrapping one Zyre node

Zyre does local area discovery and clustering. A Zyre node broadcasts UDP beacons, and connects to peers that it finds. This class wraps a Zyre node with a message-based API.

All incoming events are zmsg_t messages delivered via the zyre_recv call. The first frame defines the type of the message, and following frames provide further values:

ENTER fromnode name headers ipaddress:port
    a new peer has entered the network
EVASIVE fromnode name
    a peer is being evasive (i.e. quiet) and will be pinged manually
SILENT fromnode name
    a peer has been quiet and has not answered ping after 1 second
EXIT fromnode name
    a peer has left the network
JOIN fromnode name groupname
    a peer has joined a specific group
LEAVE fromnode name groupname
    a peer has joined a specific group
WHISPER fromnode name message
    a peer has sent this node a message
SHOUT fromnode name groupname message
    a peer has sent one of our groups a message

In SHOUT and WHISPER the message is zero or more frames, and can hold any ZeroMQ message. In ENTER, the headers frame contains a packed dictionary, see zhash_pack/unpack.

To join or leave a group, use the zyre_join and zyre_leave methods. To set a header value, use the zyre_set_header method. To send a message to a single peer, use zyre_whisper. To send a message to a group, use zyre_shout.

Todo: allow multipart contents

This is the class interface:

    //  This is a stable class, and may not change except for emergencies. It
    //  is provided in stable builds.
    //  This class has draft methods, which may change over time. They are not
    //  in stable releases, by default. Use --enable-drafts to enable.
    //  Constructor, creates a new Zyre node. Note that until you start the
    //  node it is silent and invisible to other nodes on the network.
    //  The node name is provided to other nodes during discovery. If you
    //  specify NULL, Zyre generates a randomized node name from the UUID.
    ZYRE_EXPORT zyre_t *
        zyre_new (const char *name);
    
    //  Destructor, destroys a Zyre node. When you destroy a node, any
    //  messages it is sending or receiving will be discarded.
    ZYRE_EXPORT void
        zyre_destroy (zyre_t **self_p);
    
    //  Return our node UUID string, after successful initialization
    ZYRE_EXPORT const char *
        zyre_uuid (zyre_t *self);
    
    //  Return our node name, after successful initialization. First 6
    //  characters of UUID by default.
    ZYRE_EXPORT const char *
        zyre_name (zyre_t *self);
    
    //  Set the public name of this node overriding the default. The name is
    //  provide during discovery and come in each ENTER message.
    ZYRE_EXPORT void
        zyre_set_name (zyre_t *self, const char *name);
    
    //  Set node header; these are provided to other nodes during discovery
    //  and come in each ENTER message.
    ZYRE_EXPORT void
        zyre_set_header (zyre_t *self, const char *name, const char *format, ...) CHECK_PRINTF (3);
    
    //  Set verbose mode; this tells the node to log all traffic as well as
    //  all major events.
    ZYRE_EXPORT void
        zyre_set_verbose (zyre_t *self);
    
    //  Set UDP beacon discovery port; defaults to 5670, this call overrides
    //  that so you can create independent clusters on the same network, for
    //  e.g. development vs. production. Has no effect after zyre_start().
    ZYRE_EXPORT void
        zyre_set_port (zyre_t *self, int port_nbr);
    
    //  Set the peer evasiveness timeout, in milliseconds. Default is 5000.
    //  This can be tuned in order to deal with expected network conditions
    //  and the response time expected by the application. This is tied to
    //  the beacon interval and rate of messages received.
    ZYRE_EXPORT void
        zyre_set_evasive_timeout (zyre_t *self, int interval);
    
    //  Set the peer silence timeout, in milliseconds. Default is 5000.
    //  This can be tuned in order to deal with expected network conditions
    //  and the response time expected by the application. This is tied to
    //  the beacon interval and rate of messages received.
    //  Silence is triggered one second after the timeout if peer has not
    //  answered ping and has not sent any message.
    //  NB: this is currently redundant with the evasiveness timeout. Both
    //  affect the same timeout value.
    ZYRE_EXPORT void
        zyre_set_silent_timeout (zyre_t *self, int interval);
    
    //  Set the peer expiration timeout, in milliseconds. Default is 30000.
    //  This can be tuned in order to deal with expected network conditions
    //  and the response time expected by the application. This is tied to
    //  the beacon interval and rate of messages received.
    ZYRE_EXPORT void
        zyre_set_expired_timeout (zyre_t *self, int interval);
    
    //  Set UDP beacon discovery interval, in milliseconds. Default is instant
    //  beacon exploration followed by pinging every 1,000 msecs.
    ZYRE_EXPORT void
        zyre_set_interval (zyre_t *self, size_t interval);
    
    //  Set network interface for UDP beacons. If you do not set this, CZMQ will
    //  choose an interface for you. On boxes with several interfaces you should
    //  specify which one you want to use, or strange things can happen.
    ZYRE_EXPORT void
        zyre_set_interface (zyre_t *self, const char *value);
    
    //  By default, Zyre binds to an ephemeral TCP port and broadcasts the local
    //  host name using UDP beaconing. When you call this method, Zyre will use
    //  gossip discovery instead of UDP beaconing. You MUST set-up the gossip
    //  service separately using zyre_gossip_bind() and _connect(). Note that the
    //  endpoint MUST be valid for both bind and connect operations. You can use
    //  inproc://, ipc://, or tcp:// transports (for tcp://, use an IP address
    //  that is meaningful to remote as well as local nodes). Returns 0 if
    //  the bind was successful, else -1.
    ZYRE_EXPORT int
        zyre_set_endpoint (zyre_t *self, const char *format, ...) CHECK_PRINTF (2);
    
    //  Set-up gossip discovery of other nodes. At least one node in the cluster
    //  must bind to a well-known gossip endpoint, so other nodes can connect to
    //  it. Note that gossip endpoints are completely distinct from Zyre node
    //  endpoints, and should not overlap (they can use the same transport).
    ZYRE_EXPORT void
        zyre_gossip_bind (zyre_t *self, const char *format, ...) CHECK_PRINTF (2);
    
    //  Set-up gossip discovery of other nodes. A node may connect to multiple
    //  other nodes, for redundancy paths. For details of the gossip network
    //  design, see the CZMQ zgossip class.
    ZYRE_EXPORT void
        zyre_gossip_connect (zyre_t *self, const char *format, ...) CHECK_PRINTF (2);
    
    //  Start node, after setting header values. When you start a node it
    //  begins discovery and connection. Returns 0 if OK, -1 if it wasn't
    //  possible to start the node.
    ZYRE_EXPORT int
        zyre_start (zyre_t *self);
    
    //  Stop node; this signals to other peers that this node will go away.
    //  This is polite; however you can also just destroy the node without
    //  stopping it.
    ZYRE_EXPORT void
        zyre_stop (zyre_t *self);
    
    //  Join a named group; after joining a group you can send messages to
    //  the group and all Zyre nodes in that group will receive them.
    ZYRE_EXPORT int
        zyre_join (zyre_t *self, const char *group);
    
    //  Leave a group
    ZYRE_EXPORT int
        zyre_leave (zyre_t *self, const char *group);
    
    //  Receive next message from network; the message may be a control
    //  message (ENTER, EXIT, JOIN, LEAVE) or data (WHISPER, SHOUT).
    //  Returns zmsg_t object, or NULL if interrupted
    //  Caller owns return value and must destroy it when done.
    ZYRE_EXPORT zmsg_t *
        zyre_recv (zyre_t *self);
    
    //  Send message to single peer, specified as a UUID string
    //  Destroys message after sending
    ZYRE_EXPORT int
        zyre_whisper (zyre_t *self, const char *peer, zmsg_t **msg_p);
    
    //  Send message to a named group
    //  Destroys message after sending
    ZYRE_EXPORT int
        zyre_shout (zyre_t *self, const char *group, zmsg_t **msg_p);
    
    //  Send formatted string to a single peer specified as UUID string
    ZYRE_EXPORT int
        zyre_whispers (zyre_t *self, const char *peer, const char *format, ...) CHECK_PRINTF (3);
    
    //  Send formatted string to a named group
    ZYRE_EXPORT int
        zyre_shouts (zyre_t *self, const char *group, const char *format, ...) CHECK_PRINTF (3);
    
    //  Return zlist of current peer ids.
    //  Caller owns return value and must destroy it when done.
    ZYRE_EXPORT zlist_t *
        zyre_peers (zyre_t *self);
    
    //  Return zlist of current peers of this group.
    //  Caller owns return value and must destroy it when done.
    ZYRE_EXPORT zlist_t *
        zyre_peers_by_group (zyre_t *self, const char *name);
    
    //  Return zlist of currently joined groups.
    //  Caller owns return value and must destroy it when done.
    ZYRE_EXPORT zlist_t *
        zyre_own_groups (zyre_t *self);
    
    //  Return zlist of groups known through connected peers.
    //  Caller owns return value and must destroy it when done.
    ZYRE_EXPORT zlist_t *
        zyre_peer_groups (zyre_t *self);
    
    //  Return the endpoint of a connected peer.
    //  Returns empty string if peer does not exist.
    //  Caller owns return value and must destroy it when done.
    ZYRE_EXPORT char *
        zyre_peer_address (zyre_t *self, const char *peer);
    
    //  Return the value of a header of a conected peer.
    //  Returns null if peer or key doesn't exits.
    //  Caller owns return value and must destroy it when done.
    ZYRE_EXPORT char *
        zyre_peer_header_value (zyre_t *self, const char *peer, const char *name);
    
    //  Return socket for talking to the Zyre node, for polling
    ZYRE_EXPORT zsock_t *
        zyre_socket (zyre_t *self);
    
    //  Print zyre node information to stdout
    ZYRE_EXPORT void
        zyre_print (zyre_t *self);
    
    //  Return the Zyre version for run-time API detection; returns
    //  major * 10000 + minor * 100 + patch, as a single integer.
    ZYRE_EXPORT uint64_t
        zyre_version (void);
    
    //  Self test of this class.
    ZYRE_EXPORT void
        zyre_test (bool verbose);
    
    #ifdef ZYRE_BUILD_DRAFT_API
    //  *** Draft method, for development use, may change without warning ***
    //  Set the TCP port bound by the ROUTER peer-to-peer socket (beacon mode).
    //  Defaults to * (the port is randomly assigned by the system).
    //  This call overrides this, to bypass some firewall issues when ports are
    //  random. Has no effect after zyre_start().
    ZYRE_EXPORT void
        zyre_set_beacon_peer_port (zyre_t *self, int port_nbr);
    
    //  *** Draft method, for development use, may change without warning ***
    //  This options enables a peer to actively contest for leadership in the
    //  given group. If this option is not set the peer will still participate in
    //  elections but never gets elected. This ensures that a consent for a leader
    //  is reached within a group even though not every peer is contesting for
    //  leadership.
    ZYRE_EXPORT void
        zyre_set_contest_in_group (zyre_t *self, const char *group);
    
    //  *** Draft method, for development use, may change without warning ***
    //  Set an alternative endpoint value when using GOSSIP ONLY. This is useful
    //  if you're advertising an endpoint behind a NAT.
    ZYRE_EXPORT void
        zyre_set_advertised_endpoint (zyre_t *self, const char *value);
    
    //  *** Draft method, for development use, may change without warning ***
    //  Apply a azcert to a Zyre node.
    ZYRE_EXPORT void
        zyre_set_zcert (zyre_t *self, zcert_t *zcert);
    
    //  *** Draft method, for development use, may change without warning ***
    //  Specify the ZAP domain (for use with CURVE).
    ZYRE_EXPORT void
        zyre_set_zap_domain (zyre_t *self, const char *domain);
    
    //  *** Draft method, for development use, may change without warning ***
    //  Set-up gossip discovery with CURVE enabled.
    ZYRE_EXPORT void
        zyre_gossip_connect_curve (zyre_t *self, const char *public_key, const char *format, ...) CHECK_PRINTF (3);
    
    //  *** Draft method, for development use, may change without warning ***
    //  Unpublish a GOSSIP node from local list, useful in removing nodes from list when they EXIT
    ZYRE_EXPORT void
        zyre_gossip_unpublish (zyre_t *self, const char *node);
    
    //  *** Draft method, for development use, may change without warning ***
    //  Explicitly connect to a peer
    ZYRE_EXPORT int
        zyre_require_peer (zyre_t *self, const char *uuid, const char *endpoint, const char *public_key);
    
    #endif // ZYRE_BUILD_DRAFT_API

Please add '@interface' section in './../src/zyre.c'.

This is the class self test code:

    //  We'll use inproc gossip discovery so that this works without networking
    
    uint64_t version = zyre_version ();
    assert ((version / 10000) % 100 == ZYRE_VERSION_MAJOR);
    assert ((version / 100) % 100 == ZYRE_VERSION_MINOR);
    assert (version % 100 == ZYRE_VERSION_PATCH);
    
    //  Create two nodes
    zyre_t *node1 = zyre_new ("node1");
    assert (node1);
    assert (streq (zyre_name (node1), "node1"));
    zyre_set_header (node1, "X-HELLO", "World");
    if (verbose)
        zyre_set_verbose (node1);
    
    //  Set inproc endpoint for this node
    int rc = zyre_set_endpoint (node1, "inproc://zyre-node1");
    assert (rc == 0);
    //  Set up gossip network for this node
    zyre_gossip_bind (node1, "inproc://gossip-hub");
    rc = zyre_start (node1);
    assert (rc == 0);
    
    zyre_t *node2 = zyre_new ("node2");
    assert (node2);
    assert (streq (zyre_name (node2), "node2"));
    if (verbose)
        zyre_set_verbose (node2);
    
    //  Set inproc endpoint for this node
    //  First, try to use existing name, it'll fail
    rc = zyre_set_endpoint (node2, "inproc://zyre-node1");
    assert (rc == -1);
    //  Now use available name and confirm that it succeeds
    rc = zyre_set_endpoint (node2, "inproc://zyre-node2");
    assert (rc == 0);
    
    //  Set up gossip network for this node
    zyre_gossip_connect (node2, "inproc://gossip-hub");
    rc = zyre_start (node2);
    assert (rc == 0);
    assert (strneq (zyre_uuid (node1), zyre_uuid (node2)));
    
    zyre_join (node1, "GLOBAL");
    zyre_join (node2, "GLOBAL");
    
    //  Give time for them to interconnect
    zclock_sleep (250);
    if (verbose)
        zyre_dump (node1);
    
    zlist_t *peers = zyre_peers (node1);
    assert (peers);
    assert (zlist_size (peers) == 1);
    zlist_destroy (&peers);
    
    zyre_join (node1, "node1 group of one");
    zyre_join (node2, "node2 group of one");
    
    // Give them time to join their groups
    zclock_sleep (250);
    
    zlist_t *own_groups = zyre_own_groups (node1);
    assert (own_groups);
    assert (zlist_size (own_groups) == 2);
    zlist_destroy (&own_groups);
    
    zlist_t *peer_groups = zyre_peer_groups (node1);
    assert (peer_groups);
    assert (zlist_size (peer_groups) == 2);
    zlist_destroy (&peer_groups);
    
    char *value = zyre_peer_header_value (node2, zyre_uuid (node1), "X-HELLO");
    assert (streq (value, "World"));
    zstr_free (&value);
    
    //  One node shouts to GLOBAL
    zyre_shouts (node1, "GLOBAL", "Hello, World");
    
    //  Second node should receive ENTER, JOIN, and SHOUT
    zmsg_t *msg = zyre_recv (node2);
    assert (msg);
    char *command = zmsg_popstr (msg);
    assert (streq (command, "ENTER"));
    zstr_free (&command);
    assert (zmsg_size (msg) == 4);
    char *peerid = zmsg_popstr (msg);
    char *name = zmsg_popstr (msg);
    assert (streq (name, "node1"));
    zstr_free (&name);
    zframe_t *headers_packed = zmsg_pop (msg);
    
    char *address = zmsg_popstr (msg);
    char *endpoint = zyre_peer_address (node2, peerid);
    assert (streq (address, endpoint));
    zstr_free (&peerid);
    zstr_free (&endpoint);
    zstr_free (&address);
    
    assert (headers_packed);
    zhash_t *headers = zhash_unpack (headers_packed);
    assert (headers);
    zframe_destroy (&headers_packed);
    assert (streq ((char *) zhash_lookup (headers, "X-HELLO"), "World"));
    zhash_destroy (&headers);
    zmsg_destroy (&msg);
    
    msg = zyre_recv (node2);
    assert (msg);
    command = zmsg_popstr (msg);
    assert (streq (command, "JOIN"));
    zstr_free (&command);
    assert (zmsg_size (msg) == 3);
    zmsg_destroy (&msg);
    
    msg = zyre_recv (node2);
    assert (msg);
    command = zmsg_popstr (msg);
    assert (streq (command, "JOIN"));
    zstr_free (&command);
    assert (zmsg_size (msg) == 3);
    zmsg_destroy (&msg);
    
    msg = zyre_recv (node2);
    assert (msg);
    command = zmsg_popstr (msg);
    assert (streq (command, "SHOUT"));
    zstr_free (&command);
    zmsg_destroy (&msg);
    
    zyre_stop (node2);
    
    msg = zyre_recv (node2);
    assert (msg);
    command = zmsg_popstr (msg);
    assert (streq (command, "STOP"));
    zstr_free (&command);
    zmsg_destroy (&msg);
    
    zyre_stop (node1);
    
    zyre_destroy (&node1);
    zyre_destroy (&node2);
    
    printf ("OK\n");
    
    #ifdef ZYRE_BUILD_DRAFT_API
    //  DRAFT-API: Security
    if (zsys_has_curve()){
    
        printf (" * zyre-curve: ");
        if (verbose)
            printf ("\n");
    
        if (verbose)
            zsys_debug("----------------TESTING CURVE --------------");
    
        zactor_t *speaker = zactor_new (zbeacon, NULL);
        assert (speaker);
        if (verbose)
            zstr_sendx (speaker, "VERBOSE", NULL);
    
        // ensuring we have a broadcast address
        zsock_send (speaker, "si", "CONFIGURE", 9999);
        char *hostname = zstr_recv (speaker);
        if (!*hostname) {
            printf ("OK (skipping test, no UDP broadcasting)\n");
            zactor_destroy (&speaker);
            freen (hostname);
            return;
        }
        freen (hostname);
        zactor_destroy (&speaker);
    
    
        // zap setup
        zactor_t *auth = zactor_new(zauth, NULL);
        assert (auth);
    
        if (verbose) {
            zstr_sendx(auth, "VERBOSE", NULL);
            zsock_wait(auth);
        }
    
        zstr_sendx (auth, "CURVE", CURVE_ALLOW_ANY, NULL);
        zsock_wait (auth);
    
        zyre_t *node3 = zyre_new ("node3");
        zyre_t *node4 = zyre_new ("node4");
    
        assert (node3);
        assert (node4);
    
        if (verbose) {
            zyre_set_verbose (node3);
            zyre_set_verbose (node4);
        }
    
        zyre_set_zap_domain(node3, "TEST");
        zyre_set_zap_domain(node4, "TEST");
    
        zsock_set_rcvtimeo(node3->inbox, 10000);
        zsock_set_rcvtimeo(node4->inbox, 10000);
    
        zcert_t *node3_cert = zcert_new ();
        zcert_t *node4_cert = zcert_new ();
    
        assert (node3_cert);
        assert (node4_cert);
    
        zyre_set_zcert (node3, node3_cert);
        zyre_set_zcert (node4, node4_cert);
    
        zyre_set_header (node3, "X-PUBLICKEY", "%s", zcert_public_txt (node3_cert));
        zyre_set_header (node4, "X-PUBLICKEY", "%s", zcert_public_txt (node4_cert));
    
        // test beacon
        if (verbose)
            zsys_debug ("----------------TESTING BEACON----------------");
    
        rc = zyre_start (node3);
        assert (rc == 0);
    
        rc = zyre_start (node4);
        assert (rc == 0);
    
        zyre_join (node3, "GLOBAL");
        zyre_join (node4, "GLOBAL");
    
        zclock_sleep (1500);
    
        if (verbose) {
            zyre_dump (node3);
            zyre_dump (node4);
        }
    
        zyre_shouts (node3, "GLOBAL", "Hello, World");
    
        //  Second node should receive ENTER, JOIN, and SHOUT
        msg = zyre_recv (node4);
        assert (msg);
        command = zmsg_popstr (msg);
        assert (streq (command, "ENTER"));
        zstr_free (&command);
    
        char *peerid = zmsg_popstr (msg);
        assert (peerid);
        name = zmsg_popstr (msg);
        assert (streq (name, "node3"));
        zmsg_destroy (&msg);
    
        msg = zyre_recv (node4);
        assert (msg);
        command = zmsg_popstr (msg);
        assert (streq (command, "JOIN"));
        zstr_free (&command);
        zmsg_destroy (&msg);
    
        msg = zyre_recv (node4);
        assert (msg);
        command = zmsg_popstr (msg);
        assert (streq (command, "SHOUT"));
        zstr_free (&command);
        zmsg_destroy (&msg);
    
        zyre_leave (node3, "GLOBAL");
        zyre_leave (node4, "GLOBAL");
    
        zstr_free (&name);
        zstr_free (&peerid);
        zstr_free (&command);
    
        zyre_stop (node3);
        zyre_stop (node4);
    
        // give things a chance to settle...
        zclock_sleep (250);
    
        zyre_destroy(&node3);
        zyre_destroy(&node4);
    
        zcert_destroy(&node3_cert);
        zcert_destroy(&node4_cert);
    
        // test gossip
        if (verbose)
            zsys_debug ("----------------TESTING GOSSIP----------------");
    
        zyre_t *node5 = zyre_new ("node5");
        zyre_t *node6 = zyre_new ("node6");
    
        assert (node5);
        assert (node6);
    
        if (verbose) {
            zyre_set_verbose (node5);
            zyre_set_verbose (node6);
        }
    
        // if it takes more than 10s, something probably went terribly wrong
        zsock_set_rcvtimeo(node5->inbox, 10000);
        zsock_set_rcvtimeo(node6->inbox, 10000);
    
        zcert_t *node5_cert = zcert_new ();
        zcert_t *node6_cert = zcert_new ();
    
        assert (node5_cert);
        assert (node6_cert);
    
        zyre_set_zcert(node5, node5_cert);
        zyre_set_zcert(node6, node6_cert);
    
        zyre_set_header(node5, "X-PUBLICKEY", "%s", zcert_public_txt(node5_cert));
        zyre_set_header(node6, "X-PUBLICKEY", "%s", zcert_public_txt(node6_cert));
    
        // TODO- set_advertised_endpoint tests
    //        zyre_set_endpoint(node5, "tcp://127.0.0.1:9001");
    //        zyre_set_advertised_endpoint(node5, "tcp://localhost:9001");
    
        const char *gossip_cert = zcert_public_txt (node5_cert);
    
        // TODO- need to add zyre_gossip_port functions to get port from gossip bind(?)
        zyre_gossip_bind(node5, "tcp://127.0.0.1:9001");
        zyre_gossip_connect_curve(node6, gossip_cert, "tcp://127.0.0.1:9001");
    
        rc = zyre_start (node5);
        assert (rc == 0);
    
        rc = zyre_start (node6);
        assert (rc == 0);
    
        zyre_join (node5, "GLOBAL");
        zyre_join (node6, "GLOBAL");
    
        // give things a chance to settle...
        zclock_sleep (1500);
    
        if (verbose) {
            zyre_dump (node5);
            zyre_dump (node6);
        }
    
        zyre_shouts (node5, "GLOBAL", "Hello, World");
    
        //  Second node should receive ENTER, JOIN, and SHOUT
        msg = zyre_recv (node6);
        assert (msg);
        command = zmsg_popstr (msg);
        assert (streq (command, "ENTER"));
        zstr_free (&command);
    
        peerid = zmsg_popstr (msg);
        assert (peerid);
        name = zmsg_popstr (msg);
        zmsg_destroy (&msg);
    
        assert (streq (name, "node5"));
        zstr_free (&name);
    
        zyre_leave (node5, "GLOBAL");
        zyre_leave (node6, "GLOBAL");
    
        zyre_stop (node5);
        zyre_stop (node6);
    
        // give things a chance to settle...
        zclock_sleep (250);
    
        zstr_free (&peerid);
    
        zcert_destroy (&node5_cert);
        zcert_destroy (&node6_cert);
    
        zyre_destroy (&node5);
        zyre_destroy (&node6);
        zactor_destroy (&auth);
    
        printf ("OK\n");
    
    }
    #endif
    }

zyre_event - no title found

This class provides a higher-level API to the zyre_recv call, by doing work that you will want to do in many cases, such as unpacking the peer headers for each ENTER event received.

Please add '@discuss' section in './../src/zyre_event.c'.

This is the class interface:

    //  This is a stable class, and may not change except for emergencies. It
    //  is provided in stable builds.
    //  Constructor: receive an event from the zyre node, wraps zyre_recv.
    //  The event may be a control message (ENTER, EXIT, JOIN, LEAVE) or
    //  data (WHISPER, SHOUT).
    ZYRE_EXPORT zyre_event_t *
        zyre_event_new (zyre_t *node);
    
    //  Destructor; destroys an event instance
    ZYRE_EXPORT void
        zyre_event_destroy (zyre_event_t **self_p);
    
    //  Returns event type, as printable uppercase string. Choices are:
    //  "ENTER", "EXIT", "JOIN", "LEAVE", "EVASIVE", "WHISPER" and "SHOUT"
    //  and for the local node: "STOP"
    ZYRE_EXPORT const char *
        zyre_event_type (zyre_event_t *self);
    
    //  Return the sending peer's uuid as a string
    ZYRE_EXPORT const char *
        zyre_event_peer_uuid (zyre_event_t *self);
    
    //  Return the sending peer's public name as a string
    ZYRE_EXPORT const char *
        zyre_event_peer_name (zyre_event_t *self);
    
    //  Return the sending peer's ipaddress as a string
    ZYRE_EXPORT const char *
        zyre_event_peer_addr (zyre_event_t *self);
    
    //  Returns the event headers, or NULL if there are none
    ZYRE_EXPORT zhash_t *
        zyre_event_headers (zyre_event_t *self);
    
    //  Returns value of a header from the message headers
    //  obtained by ENTER. Return NULL if no value was found.
    ZYRE_EXPORT const char *
        zyre_event_header (zyre_event_t *self, const char *name);
    
    //  Returns the group name that a SHOUT event was sent to
    ZYRE_EXPORT const char *
        zyre_event_group (zyre_event_t *self);
    
    //  Returns the incoming message payload; the caller can modify the
    //  message but does not own it and should not destroy it.
    ZYRE_EXPORT zmsg_t *
        zyre_event_msg (zyre_event_t *self);
    
    //  Returns the incoming message payload, and pass ownership to the
    //  caller. The caller must destroy the message when finished with it.
    //  After called on the given event, further calls will return NULL.
    //  Caller owns return value and must destroy it when done.
    ZYRE_EXPORT zmsg_t *
        zyre_event_get_msg (zyre_event_t *self);
    
    //  Print event to zsys log
    ZYRE_EXPORT void
        zyre_event_print (zyre_event_t *self);
    
    //  Self test of this class.
    ZYRE_EXPORT void
        zyre_event_test (bool verbose);
    

Please add '@interface' section in './../src/zyre_event.c'.

This is the class self test code:

    //  Create two nodes
    zyre_t *node1 = zyre_new ("node1");
    assert (node1);
    zyre_set_header (node1, "X-HELLO", "World");
    int rc = zyre_set_endpoint (node1, "inproc://zyre-node1");
    assert (rc == 0);
    // use gossiping instead of beaconing, suits Travis better
    zyre_gossip_bind (node1, "inproc://gossip-hub");
    if (verbose)
        zyre_set_verbose (node1);
    if (zyre_start (node1)) {
        zyre_destroy (&node1);
        printf ("OK (skipping test, no UDP discovery)\n");
        return;
    }
    zyre_join (node1, "GLOBAL");
    
    zyre_t *node2 = zyre_new ("node2");
    assert (node2);
    if (verbose)
        zyre_set_verbose (node2);
    rc = zyre_set_endpoint (node2, "inproc://zyre-node2");
    assert (rc == 0);
    // use gossiping instead of beaconing, suits Travis better
    zyre_gossip_connect (node2, "inproc://gossip-hub");
    rc = zyre_start (node2);
    assert (rc == 0);
    zyre_join (node2, "GLOBAL");
    
    //  Give time for them to interconnect
    zclock_sleep (250);
    
    //  One node shouts to GLOBAL
    zmsg_t *msg = zmsg_new ();
    zmsg_addstr (msg, "Hello, World");
    zyre_shout (node1, "GLOBAL", &msg);
    zclock_sleep (100);
    
    //  Parse ENTER
    zyre_event_t *event = zyre_event_new (node2);
    assert (streq (zyre_event_type (event), "ENTER"));
    const char *sender = zyre_event_peer_uuid (event);
    assert (sender);
    const char *name = zyre_event_peer_name (event);
    assert (name);
    assert (streq (name, "node1"));
    const char *address = zyre_event_peer_addr (event);
    assert (address);
    const char *header = zyre_event_header (event, "X-HELLO");
    assert (header);
    zyre_event_destroy (&event);
    
    //  Parse JOIN
    //  We tolerate other events, which we can get if there are instances
    //  of Zyre running somewhere on the network.
    event = zyre_event_new (node2);
    if (streq (zyre_event_type (event), "JOIN")) {
        //  Parse SHOUT
        zyre_event_destroy (&event);
        event = zyre_event_new (node2);
        if (streq (zyre_event_type (event), "SHOUT")) {
            assert (streq (zyre_event_group (event), "GLOBAL"));
            zmsg_t *msg = zyre_event_get_msg (event);
            char *string = zmsg_popstr (msg);
            zmsg_destroy (&msg);
            assert (streq (string, "Hello, World"));
            free (string);
        }
        zyre_event_destroy (&event);
    }
    zyre_destroy (&node1);
    zyre_destroy (&node2);

Hints to Contributors

Zyre is a nice, neat library, and you may not immediately appreciate why. Read the CLASS style guide please, and write your code to make it indistinguishable from the rest of the code in the library. That is the only real criteria for good style: it's invisible.

Don't include system headers in source files. The right place for these is CZMQ.

Do read your code after you write it and ask, "Can I make this simpler?" We do use a nice minimalist and yet readable style. Learn it, adopt it, use it.

Before opening a pull request read our contribution guidelines. Thanks!

This Document

This documentation was generated from zyre/README.txt using Gitdown

zyre's People

Contributors

awynne avatar benjdero avatar bluca avatar c-rack avatar cekoski avatar dev1an avatar dysl3xik avatar eclazi avatar gabm avatar gotcha avatar hintjens avatar hoh avatar jemc avatar jimklimov avatar justinazoff avatar keent avatar maccradar avatar mditzel avatar miniway avatar opedroso avatar pijyoi avatar sappo avatar sjmackenzie avatar sphaero avatar stephan57160 avatar trevorbernard avatar twhittock avatar vperron avatar wesyoung avatar zoobab avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

zyre's Issues

Detect lost WiFi interface / shifted peer

Problem: if the WiFi interface goes down and comes back up, we don't recover properly

Solution: detect this on the host peer by unbinding the router socket and destroying all peers. Detect this on other peers by comparing a peer's previous IP address and port with the current one, in all UDP beacons and OHAI messages, and reconnect the dealer socket if these change.

Clusters discovery and interconnect

Hi,Pieter.
If i have 100 clusters(some zyre nodes join together to create a cluster), how make them discovery and interconnect each other.

groups with a physical location

problem:

groups are only associated with a name. applications that take into account spatial conditions need a way to
1 find the peers in a particular location
2 send messages to peers in a particular location.

solution:

incorporate the Military Grid Reference System into zyre. such that an application can send a message to all peers in a particular quadrant. the application programmer decides how big the quadrant is. please look up MGRS on wikipedia.

Message payloads not implemented

Problem: WHISPER and SHOUT commands haven't been fully implemented; they don't carry a payload

Solution: implement message payloads for these commands

zyre testing 2/3 - send logs or metrics to ZPER

zyre testing consist of three parts.

  1. application distribution
  2. send logs or metrics to ZPER front
  3. dump ZPER contents to a MongoDB

send logs or metrics to ZPER front

  • Uses ZPER front (it's almost ready and works)
  • Zyre test programs (ex, zyre_ping) send logs or metrics to ZPER through PUSH or DEALER socket
    • An alternative is, the test programs leave logs to a local file and another file listener reads the file and sends to ZPER
  • ZPER store ZMQ frames as is to disk based on topics.

A race condition can occur

situation:

A zyre agent can notice new peer from both the BEACON or "HELLO". Then agent sends "ENTER" to its interface through the connected pipe.

An application send a greeting, ex "HI" when it get "ENTER".

    // zre_interface_agent handler

    if (pollitems [1].revents & ZMQ_POLLIN)
        agent_recv_from_peer (self);                     // -- 1)

    if (pollitems [2].revents & ZMQ_POLLIN)
        agent_recv_udp_beacon (self);                // -- 2)

At 1) "ENTER" is sent to the application and the application send "HI" through the pipe. But it is not handled yet. It will be handled at the next cycle.

At 2) "ENTER" is sent to the application again and the application send "HI" and blocks as the pipe is already full (hwm is 1)

possible solutions:

  • don't handle inbox and udp events at one cycle.
  • increase the pipe hwm

Reconnection of X-ZRELOG collector will cause multiple connection from other nodes

With one zyre node running one can interrupt zlogger and every time it starts one can see insreased number of messages

14-04-14 08:18:37  I: [E16F] [E31B] - Peer enters tcp://147.213.192.236:49154

As one can see bellow

(=096e1) mvala@vala zyre $ zlogger
^C(=096e1) mvala@vala zyre $ zlogger 
14-04-14 08:18:37  I: [E16F] [E31B] - Peer enters tcp://147.213.192.236:49154
^C(=096e1) mvala@vala zyre $ zlogger 
14-04-14 08:18:38  I: [E16F] [E31B] - Peer enters tcp://147.213.192.236:49154
14-04-14 08:18:38  I: [E16F] [E31B] - Peer enters tcp://147.213.192.236:49154
^C(=096e1) mvala@vala zyre $ zlogger 
14-04-14 08:18:39  I: [E16F] [E31B] - Peer enters tcp://147.213.192.236:49154
14-04-14 08:18:39  I: [E16F] [E31B] - Peer enters tcp://147.213.192.236:49154
14-04-14 08:18:39  I: [E16F] [E31B] - Peer enters tcp://147.213.192.236:49154
^C(=096e1) mvala@vala zyre $ zlogger 
14-04-14 08:18:40  I: [E16F] [E31B] - Peer enters tcp://147.213.192.236:49154
14-04-14 08:18:40  I: [E16F] [E31B] - Peer enters tcp://147.213.192.236:49154
14-04-14 08:18:40  I: [E16F] [E31B] - Peer enters tcp://147.213.192.236:49154
14-04-14 08:18:40  I: [E16F] [E31B] - Peer enters tcp://147.213.192.236:49154

This is caused, because every time new logger says ZRE_MSG_HELLO, we connect to it. So probably we should connect there only once. In case we have more loggers running in parallel we should have keep list of loggers and we should have function to disconnect from them.

I can implement such think, but before i wanted to discuss it.

Ciao

Martin

zre_tester causes 100% cpu usage

In interface_task(), the logic implemented is that if the interface reports that a peer JOINs or LEAVEs, then 1/3 of the time we will join or leave the same group.

This would appear to cause a storm of recursive JOINs and LEAVEs amongst all the simulated interfaces.

Could someone confirm if this was the intended behavior?
The zguide pseudo-code in "The Zyre Tester" does not list this logic.

Compile Error C2275: 'zmq_pollitem_t' : illegal use of this type as an expression

Hi! I'm trying to compile the zrechat example using :

  • Windows 7 64-Bit
  • VS2012
  • zmq 3.2.4
  • czmq 1.4.1
  • filemq (1.0a1?)

The above error points to line 38:
zmq_pollitem_t items [] = {

I get 21 errors in all. The first 11 seem to all stem from the above issue. I get another error at this line:

char *command = zmsg_popstr (msg);

The error:

error C2143: syntax error : missing ';' before 'type'

.
I get similar errors for the declarations of char *message, zctx_t *ctx and void *chat_pipe.

Any ideas? It could have something to do with my project setup, I've not worked with c much, my experience is mostly higher-level with c++ and openFrameworks.

Memory freed before use in zre_log_msg.c

In zre_log_msg.c lines 259-260 of zre_log_msg_recv read:
free (self->data);
GET_STRING (self->data);
when they should be:
GET_STRING (self->data);
free (self->data);

Need a way to configure home directory of inbox/outbox folder

In Android, it is not allowed to create .inbox and .outbox directory.

We should pass home directory or proper sdcard media path to create directory and files as an option.

Solution :

The zre_interface accepts a hash table or a list of key=value string as parameters.

Then it pass the parameters to background agent when it forks the agent

zyre testing3/3 - dump ZPER contents to CSV

zyre testing consist of three parts.

  1. application distribution
  2. send logs or metrics to ZPER front
  3. dump ZPER contents to CSV

dump ZPER contents to CSV

  • A listener read ZPER disk files and dumps to CSV for various analysis

zre_msg.xml and zre_msg.c mismatch

<header>
    <field name = "sequence" type = "number" size = "2" />
</header>

<message name = "HELLO" id = "10">
    <field name = "from" type = "string" />
    <field name = "port" type = "number" size = "2" />
    <field name = "groups" type = "strings" />
    <field name = "status" type = "number" size = "1" />
    <field name = "headers" type = "dictionary" />
Greet a peer so it connect back to us.
</message>

But all generated number fields are byte.

struct _zre_msg_t {
    ...
    byte sequence;

    byte port;

    byte status;
    ...
};

Recent tarballs?

Building a homebrew package of this, but it looks like there are no recent tarballs in the github releases pane. Are they hosted elsewhere?

complex build

I just built Zyre and have to say I found it quite an unpleasant experience getting all the dependencies sorted out.

It'd be nice if it was distributed with the Zeromq dependencies (libzmq, libczmq, libfmq) bundled in and configure flags for compiling the required bits in one step.

Tracking message delivery

problem : zre_terster works fine now, but there's no way to verify messages are delivered to a peer or a group without loss.

solution: a small script parse console output messages and verify the delivery

Bored maintainer

Problem: This maintainer is bored
Solution: I want to click the green button more please.

zyre example hangs

Hi All,

i am running latest zmq,czmq,zyre and i wanted to try example. I found out that it hangs. Am i doing something wrong?

Here is source and part where it hangs "// ***** HANGS here ***"

zctx_t *ctx = zctx_new();
// Create two nodes
zyre_t *node1 = zyre_new(ctx);
zyre_t *node2 = zyre_new(ctx);
zyre_set_header(node1, "X-FILEMQ", "tcp://128.0.0.1:6777");
zyre_set_header(node1, "X-HELLO", "World");
zyre_start(node1);
zyre_start(node2);
zyre_join(node1, "GLOBAL");
zyre_join(node2, "GLOBAL");

// Give time for them to interconnect
zclock_sleep(250);

// One node shouts to GLOBAL
zmsg_t *msg = zmsg_new();
zmsg_addstr(msg, "Hello, World");
zyre_shout(node1, "GLOBAL", &msg);

// Parse ENTER
// ***** HANGS here ***
zyre_event_t *zyre_event = zyre_event_recv(node2);

What am i doing wrong?

Ciao

Martin

zre_msg is sending 32 characters id instead of 16 bytes

I'm not sure if this is by design or an error. Once a uuid is revealed through a zbeacon it's immediately converted to a string by zuuid_str and passed to s_require_peer in zyre_node.c:216. The 32 character string is used as an identification in the dealer socket and so 32 bytes are on the wire as well instead of 16.

I just ran into this while trying to match the python implementation of zyre to the czmq version. I'm receiving a 32 character string from a c zyre client.

"interface" as variable name breaks on MinGW32

Under MinGW, czmq.h includes windows.h which includes rpc.h which eventually includes basetyps.h which does a "#define interface struct"

Quick fix is to undef it in zre.h
Or should the code use a different variable name?

zyre testing 1/3 - application distribution

zyre testing consist of three parts.

Each part doesn't have be so general at first and should be done at least 2 days.

  1. application distribution
  2. send logs or metrics to ZPER front
  3. dump ZPER contents to a MongoDB

Application distribution

  • Uses fabric
    • Test boxes support SSH connection
  • Get the latest codes from Git
  • Compile and install to a install directory
  • Stop and Start various test programs (ex, zyre_ping) with various parameters
    • number of process / thread
    • message types
    • message rates
    • etc

Split Java and C code into separate repositories

Wondering whether it's a good idea to keep the Java and C code in the same repository, since it's leading to two very different implementation states for the same revision; It'll make it all the more difficult to have future tagged versions out.

Need basic performance test tool

Problem: we lack a way to measure basic performances

Solution: write zre_perf (or some dedicated zre_xxx_perf programs) that automates some of the basic performance tests

Items we should measure are

  • how fast other zyre interfaces notice a new comer.
  • how many WHISPER messages can be sent/received in a sec
  • how many SHOUT messages can be sent/received in a sec

And we should also check how adding more zyre interfaces effect performance decline.

-fPIC breaks MSYS/MinGW32

Line 172 in configure.in sets -fPIC
CPPFLAGS="-D_REENTRANT -D_THREAD_SAFE -fPIC $CPPFLAGS"

This generates a warning: -fPIC ignored for target
which breaks the compilation process.

Is it safe to remove it for other platforms?
I understand that normally the PIC flag is added automatically if needed.

Issues with example chat

First seems to be some change in czmq

chat.c: In function ‘main’:
chat.c:85:9: error: too many arguments to function ‘zstr_send’
         zstr_send (chat_pipe, "%s:%s", argv [1], message);
         ^

However when I just remove the message construction and just pass message. I'm getting some weird errors.
I have 2 chat client nodes. If one sends "hello" the other receives this:

--------------------------------------
[005] SHOUT
[032] 45567214894743DDBCA9B52EB8688AEB
[004] CHAT
[004] CHAT
[006] hello

Notice the double "[004] CHAT"
If the receiving node then sends "hello back" in return:

hello back
CHAT

notice the CHAT message. I don't think it belongs there

The receiving node als receives the double CHAT:

--------------------------------------
[005] SHOUT
[032] DE8978FA2409419F838757DD0A592AD6
[004] CHAT
[004] CHAT
[011] hello back

I haven't dug around the code yet but perhaps someone instantly recognizes this?

Need basic testing tool

Problem: we lack a way to stress the protocols and check they work

Solution: write zre_tester that automates some of the basic tests

  • create/destroy an interface randomly, e.g. every minute or two
  • join some groups, leave some groups
  • chat to groups and to other nodes
  • uses sequence number in messages to detect loss

Our goal is to provoke failures (asserts, message loss, blockage due to HWM)

Integrate distributed logging into zyre

Dialog between me and pieter. Guidance for me to solve this issue ;)

I have been gotten disconnected earlier did you by chance answer my question/suggestion about logging?
I wondered if you wanted to start a log collector from the API
I mean, zyre already does distributed logging, you just need to plug in a collector somewhere
it's literally about 20 lines of code - see zlogger.c
okay, great
the reason it's not built in is that what you do with log data is pretty arbitrary
I mean, the collector isn't built in
the actual discovery of log collectors and sending of data is already built in
when developing application on top of zyre it would be nice to have some logging framework already in place
what we could do, for instance
is enable a node as a log collector so log messages come over the zyre socket?
LOG + data?
as an event?
yes, that sound absolutely reasonable. I'll look into that then
basically, take zlogger, merge into zyre_node.c... I can do it quickly but you may enjoy it
I really would :D
I'd suggest an api call, zyre_collect_logs () and then a third socket, SUB, in the node

Race Condition in Zyre

There is an interesting race condition in zyre. Imagine that we have one or more zyre nodes periodically issuing beacons. An entirely new node X is started via zyre_new(zctxt_t*), at which point it can respond to a beacon from another node by issuing a HELLO message. However, we want that HELLO message to carry some application-specific headers (key/value pairs) which we define for X using the zyre_set(...) method. At this point the race condition arises since X may have issued its HELLOs before we have a chance to set the headers of X. There are now several distinct possible behaviors in which one or more of the HELLO messages issued by X may contain none, some, or all of the headers created by successive calls to zyre_set(...).

One possible fix is to have a two-phased node start. In the first phase the node listens only on the API pipe for API commands (such as the "SET" command generated by zyre_set(...)). It does not enter the second phase until it receives an explicit "GO" command on the API pipe at which point it begins to transmit its own beacon, responds to the beacons of others, and handles inter-node message traffic.

This would resolve the race condition that leads to incomplete header sets in the HELLO messages of newly created nodes. However, it does not deal with the case of modifying or augmenting the headers later in the lifespan of X as other nodes arrive later on scene. In this case the a similar race condition arises where later HELLO messages from X may also contain an incomplete or inconsistent set of headers. Here we require a transaction-like API command containing a change set of headers that are applied in their entirety.

I discovered this race condition while constructing and testing a Racket Scheme API for zyre and roughly replicating the selftest zyre_test that appears in zyre.c. In my version of the test I created the two test nodes, node1 and node2, BEFORE I set the headers of node1. This version exhibits the classic symptoms of a race condition in which the HELLO message sent by node1 to node2 sometimes contains all of the expected headers and sometimes contains none of them.

peer mailbox blocks sometimes

problem: zre_msg_send blocks sometimes. The mailbox which uses DEALER socket blocks sometimes. This cause an interface handle any messages.

solution: Need to verify exact reason of blocking first.

Memory freed before use in zre_log_msg.c

In zre_log_msg.c lines 259-260 of zre_log_msg_recv read:
free (self->data);
GET_STRING (self->data);
when they should be:
GET_STRING (self->data);
free (self->data);

Use all available interfaces upon broadcast

Currently the interface used for discovery is defined as "the last available WLAN interface";
It would maybe be an improvement to send beacons on all the available interfaces, WLAN or not.

We could broadcast on multiple interfaces, and modify the beacon on each interface to use the correct
IP address to connect back on.

Do we need -Wno-unused?

I see that we have -Wno-unused on. Do we need it? Isn't it better without it?

CPPFLAGS="-pedantic -Werror -Wall -Wno-unused ${CPPFLAGS}"

Filemq client between multiple nodes

I'm building a photo share demo using zyre with FileMQ.

A FileMQ client on the Zyre Agent, connects to multiple FileMQ servers when it gets HELLO.

Between two zyre nodes would be fine. But when the third node appeared, old socket is destroyed. So the first two nodes cannot share files.

And the credit is kept at FileMQ client instance not per connection to servers. So third FileMQ server will not get the NOM from any of server. So the third server cannot send any chunk.

I guess the FileMQ client should be created on every peer.

does zre_interface need to know what groups are in the network ?

when a peer create (join) a new group, zre_interface backend get the JOIN and manage peer's groups. But it doesn't escalate to front-end.

If the available group name is known (or hidden by application user) in a system, the front-end doesn't need to get the event.

Or if application user can join an existing group, front-end might need to get the new group event.

Project structure....

I would like to refactor the project:

  • break into Zyre and Jyre (I've registered jyre.org)
  • review the public API and change the name of zre_node to something clearer (I'm thinking zynode_t)
  • move some classes (zre_uuid) into CZMQ
  • fix up the selftest and documentation, examples & tutorial

So unless there's disagreement, I'll fork the Java stack off to a new project.

cmake support

Cmake builds are not available.
Cmake support using the same approach as czmq (with makefile generation) will follow shortly in a pull request.

unknown type name ‘Bool’

Problem: filemq does not compile on Ubuntu out of the box.

fmq_selftest.c:30:5: error: unknown type name ‘Bool’
fmq_selftest.c:33:19: error: ‘TRUE’ undeclared (first use in this function)

Solution: use bool type from C99

need a way to fetch the list of peers and groups

problem:

Even if zre_interface gets the events of peer's enter, exit and group's join, reave, it could be a burden for zre_interface front-end to manage the list of peers and groups .

And zre_interface back-end (agent) already keeps these list.

soulution:
add new commands to fetch information which the agent has.

ztester fails

Hi,

I have been experimenting with zyre a bit recently. Running the ztester however, throws the following assertion (after a minute or 2). zlogger aborted as well (actually a few seconds earlier than ztester, judging from the time stamps). I get this assertion every time I run ztester so far.

14-01-21 17:01:10 W: [008767BDD7FD4B79BF23DE3A775AB54A] lost messages from 1BE3F2A3661A46DC8CBF96051943463E
lt-ztester: zyre_node.c:421: zyre_node_recv_peer: Assertion `0' failed.
Aborted
14-01-21 17:01:03 W: [5190D2CF0BB8478BB12BF247D0B36E8F] lost messages from 006B8B4567D54F828B4BFBFD6F18A63E
lt-zlogger: zyre_node.c:421: zyre_node_recv_peer: Assertion `0' failed.
Aborted

Apparently a message got lost. Any hints where and how to start digging for the cause of the error would be greatly appreciated.

Best regards,
Maarten

assert at stream_engine.cpp:267 with zsocket_destroy of zre_peer_disconnect

The latest code cause an assert at stream_engine.cpp:267

#3  0x0016aa14 in zmq::zmq_abort (errmsg_=0x190333 "encoder") at err.cpp:76
#4  0x001801a5 in zmq::stream_engine_t::out_event (this=0xaaa17740)
    at stream_engine.cpp:267
#5  0x0017f041 in zmq::stream_engine_t::activate_out (this=0xaaa17740)
    at stream_engine.cpp:310
#6  0x00179302 in zmq::session_base_t::read_activated (this=0xb66be988, 
    pipe_=0xb66beb98) at session_base.cpp:278
#7  0x001741b8 in process_activate_read (this=0xb66beb98) at pipe.cpp:204
#8  zmq::pipe_t::process_activate_read (this=0xb66beb98) at pipe.cpp:200
#9  0x001717b8 in zmq::object_t::process_command (this=0xb66beb98, cmd_=...)
    at object.cpp:64
#10 0x0016b7d0 in zmq::io_thread_t::in_event (this=0xaaa30bd0)
    at io_thread.cpp:75
#11 0x0016a5f1 in zmq::epoll_t::loop (this=0xaaa130f0) at epoll.cpp:161
#12 0x00185bac in thread_routine (arg_=0xaaa13134) at thread.cpp:83
#13 0x00357d4c in start_thread () from /lib/i386-linux-gnu/libpthread.so.0
#14 0x0028fd3e in clone () from /lib/i386-linux-gnu/libc.so.6

By rolling back one commit by one, a clue seemed zsocket_destroy. if I comment zsocket_destory at are_peer_disconnect, the assert doesn't occur.

This might be a issue of libzmq when handling the zsocket close.

Use alternate port for ZRE discovery?

I would like to run multiple independent zyre "clusters" on the same subnet. I have my development team and my QA team on the same subnet - It would be nice if the developers' nodes can be run independently of the QA nodes.

Is there an easy way to accomplish this, or do I need to parameterize zyre_new() to take a different discovery port for the zbeacon?

Thanks,
--Scott

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.