GrumpyOldTroll / libmcrx

Multicast receive library.
Other
5 stars 2 forks source link

Intro

libmcrx is a low-level library for receiving multicast UDP traffic.

Build Clang Static Analysis

Motivation

The code for receiving multicast traffic is different on different platforms, and has some quirks and complexities. This library is intended to ease adoption of multicast-based protocols by simplifying the programming task of receiving multicast packets at the client side. Its API uses C linkage in an attempt to maximize the portability for implementing simple wrappers in other languages.

The library also is intended to serve as an extension point to integrate with some standards and standard-tracked work in progress in the IETF, ideally including:

Building

Linux

Prerequisites

For normal linux builds of the library, this project uses autoconf and automake, following the libabc template.

APT-based (Debian, Ubuntu)

apt-get install \
  autoconf \
  libtool-bin \
  make \
  build-essential

MacOS with brew

Using brew:

brew install \
  autoconf \
  automake \
  make \
  libtool

TBD: more platforms

Build

./autogen.sh
./configure
make

As usual with autotools, ./configure --help provides a bunch of options, and more in-depth explanations give more useful details.

For example, with something like --prefix=${HOME}/local-install a make install will not need sudo, and will put the library and header files under ${HOME}/local-install.

Test

Note that to test this library, you'll need reachability to an active sender of multicast traffic. See the how-to for some approaches.

NB: the current tests use a hardcoded (S,G), and probably should be changed to use a config file instead. As-is you'll basically need to be using the multicast-ingest-platform or to be in a multicast-capable network that performs ingest using DRIAD for it to pass, assuming the sender it uses is running.

make check

Install

Autoconf by default should build a configure and Makefiles that will put the headers and libraries into the default location for user libraries for the system.

sudo make install

Using the library

This library is structured as a few types of objects in a hierarchy, wrapping as much socket-receiving complexity as we could arrange.

The relevant objects are:

Each of these objects is created with a "_new" function, and is destroyed with a "_unref" function. (An internal refcount may be increased with a "_ref" function, which will keep the object alive through one extra "_unref".)

Each object also can hold an arbitrary "user data" pointer, set and retrieved with a set_userdata and get_userdata function. That pointer is opaque to the library, and provided as a convenience for the calling system.

Basic usage looks like this:

#include <mcrx/libmcrx.h>

static int receive_cb(struct mcrx_packet* packet);

int receive_thread() {
  struct mcrx_ctx* ctx = NULL;
  mcrx_ctx_new(&ctx);

  struct mcrx_subscription_config conf = MCRX_SUBSCRIPTION_CONFIG_INIT;
  mcrx_subscription_config_pton(&conf, "23.212.185.4", "232.1.1.1");
  conf.port = 5001;

  struct mcrx_subscription *sub;
  mcrx_subscription_new(ctx, &conf, &sub);
  mcrx_subscription_set_receive_cb(sub, receive_cb);

  mcrx_subscription_join(sub);

  while (1) {
    mcrx_ctx_receive_packets(ctx);
  }
}

static int receive_cb(struct mcrx_packet* packet) {
  // do something with packet
  // operations like creating, joining, and leaving subscriptions are
  // safe here.
  mcrx_packet_unref(packet);
  return MCRX_RECEIVE_CONTINUE;
}

For a more detailed example including appropriate error handling, please see mcrx-check.

Thread Safety

There is no thread safety handling inside the library. It's the caller's responsibility to ensure that no calls to any functions using the same ctx or the objects generated from the same ctx (including packets and subscriptions) have function calls that overlap in time between different threads.

Alternative Event Handlers

For an example integrating with an external event handler instead of using the blocking mcrx_ctx_receive_packets call, see the libmcrx integration with python-asyncio-taps.

That project uses python's asyncio as the event handling library, and exports sockets to be added to the list of sockets to monitor for read readiness via mcrx_ctx_set_receive_socket_handlers, rather than using the blocking mcrx_ctx_receive_packets call.

In that scenario, the calling system is responsible for making a timely call to the do_receive function for all the sockets that have been given to the calling system with the add_socket_cb callback and that have not yet been removed with the remove_socket_cb callback.