1
0
Fork 0
mirror of https://git.rwth-aachen.de/acs/public/villas/node/ synced 2025-03-09 00:00:00 +01:00

Merge branch 'feature-nanomsg' into 'develop'

Add new nanomsg node-type

See merge request !20
This commit is contained in:
Steffen Vogel 2017-05-23 15:02:12 +02:00
commit ba3aec3d0e
16 changed files with 648 additions and 59 deletions

View file

@ -2,4 +2,5 @@
!build/release/packaging/rpm/*
!thirdparty/libxil/
!thirdparty/criterion/
!thirdparty/libwebsockets/
!thirdparty/libwebsockets/
!thirdparty/nanomsg/

3
.gitmodules vendored
View file

@ -25,3 +25,6 @@
[submodule "thirdparty/libopal"]
path = thirdparty/libopal
url = ../libopal.git
[submodule "thirdparty/nanomsg"]
path = thirdparty/nanomsg
url = https://github.com/nanomsg/nanomsg.git

View file

@ -56,7 +56,8 @@ RUN dnf -y install \
iproute \
python-pip \
valgrind \
gdb
gdb \
xmlto rubygem-asciidoctor
# 32bit versions of some standard libraries for RT-LAB code
RUN dnf -y install \
@ -80,6 +81,10 @@ RUN mkdir -p /tmp/criterion/build && cd /tmp/criterion/build && cmake -DCMAKE_IN
COPY thirdparty/libwebsockets /tmp/libwebsockets
RUN mkdir -p /tmp/libwebsockets/build && cd /tmp/libwebsockets/build && cmake -DLWS_IPV6=1 -DLWS_WITH_STATIC=0 -DLWS_WITHOUT_TESTAPPS=1 -DLWS_WITH_HTTP2=1 -DLIB_SUFFIX=64 .. && make install
# Build & Install nanomsg
COPY thirdparty/nanomsg /tmp/nanomsg
RUN mkdir -p /tmp/nanomsg/build && cd /tmp/nanomsg/build && cmake .. && make install
# Cleanup intermediate files from builds
RUN rm -rf /tmp/*

View file

@ -145,9 +145,23 @@ nodes = {
]
},
websocket_node = {
type = "websocket"
type = "websocket",
destinations = [ "http://example.com/node-name1", "https://example.com/another-node" ]
},
nanomsg_node = {
type = "nanomsg",
publish = [
"tcp://*:12000", # TCP socket
"ipc:///tmp/test.ipc", # Interprocess communication
"inproc://test" # Inprocess communication
],
subscribe = [
"tcp://127.0.0.1:12000",
"ipc:///tmp/test.ipc",
"inproc://test"
]
}
};

View file

@ -97,4 +97,7 @@ int list_count(struct list *l, cmp_cb_t cmp, void *ctx);
int list_contains(struct list *l, void *p);
/** Sort the list using the quicksort algorithm of libc */
void list_sort(struct list *l, cmp_cb_t cmp);
void list_sort(struct list *l, cmp_cb_t cmp);
/** Set single element in list */
int list_set(struct list *l, int index, void *value);

View file

@ -25,6 +25,10 @@
/* Forward declarations. */
struct msg;
struct sample;
/** The maximum length of a packet which contains stuct msg. */
#define MSG_MAX_PACKET_LEN 1500
/** Swaps the byte-order of the message.
*
@ -48,4 +52,17 @@ void msg_hton(struct msg *m);
* @retval 0 The message header is valid.
* @retval <0 The message header is invalid.
*/
int msg_verify(struct msg *m);
int msg_verify(struct msg *m);
/** Copy fields from \p msg into \p smp. */
int msg_to_sample(struct msg *msg, struct sample *smp);
/** Copy fields form \p smp into \p msg. */
int msg_from_sample(struct msg *msg, struct sample *smp);
/** Copy / read struct msg's from buffer \p buf to / fram samples \p smps. */
ssize_t msg_buffer_from_samples(struct sample *smps[], unsigned cnt, char *buf, size_t len);
/** Read struct sample's from buffer \p buf into samples \p smps. */
int msg_buffer_to_samples(struct sample *smps[], unsigned cnt, char *buf, size_t len);

View file

@ -0,0 +1,67 @@
/** Node type: nanomsg
*
* This file implements the file type for nodes.
*
* @file
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2017, Institute for Automation of Complex Power Systems, EONERC
* @license GNU General Public License (version 3)
*
* VILLASnode
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
/**
* @addtogroup nanomsg nanomsg node type
* @ingroup node
* @{
*/
#pragma once
#include "node.h"
#include "list.h"
struct nanomsg {
struct {
int socket;
struct list endpoints;
} publisher;
struct {
int socket;
struct list endpoints;
} subscriber;
};
/** @see node_type::print */
char * nanomsg_print(struct node *n);
/** @see node_type::parse */
int nanomsg_parse(struct node *n, config_setting_t *cfg);
/** @see node_type::open */
int nanomsg_start(struct node *n);
/** @see node_type::close */
int nanomsg_stop(struct node *n);
/** @see node_type::read */
int nanomsg_read(struct node *n, struct sample *smps[], unsigned cnt);
/** @see node_type::write */
int nanomsg_write(struct node *n, struct sample *smps[], unsigned cnt);
/** @} */

View file

@ -51,6 +51,14 @@ ifeq ($(shell $(PKGCONFIG) libnl-route-3.0; echo $$?),0)
endif
endif
# Enable nanomsg node type when libnanomsg is available
ifndef WITHOUT_NANOMSG
ifeq ($(shell $(PKGCONFIG) nanomsg; echo $$?),0)
LIB_SRCS += lib/nodes/nanomsg.c
LIB_PKGS += nanomsg
endif
endif
# Enable VILLASfpga support when libxil is available
ifndef WITHOUT_FPGA
ifeq ($(shell $(PKGCONFIG) libxil; echo $$?),0)

View file

@ -188,4 +188,14 @@ void list_sort(struct list *l, cmp_cb_t cmp)
qsort_r(l->array, l->length, sizeof(void *), cmp_sort, (void *) cmp);
pthread_mutex_unlock(&l->lock);
}
int list_set(struct list *l, int index, void *value)
{
if (index >= l->length)
return -1;
l->array[index] = value;
return 0;
}

View file

@ -21,9 +21,12 @@
*********************************************************************************/
#include <arpa/inet.h>
#include <string.h>
#include "msg.h"
#include "msg_format.h"
#include "sample.h"
#include "utils.h"
void msg_ntoh(struct msg *m)
{
@ -67,4 +70,83 @@ int msg_verify(struct msg *m)
return -3;
else
return 0;
}
int msg_to_sample(struct msg *msg, struct sample *smp)
{
int ret;
msg_ntoh(msg);
ret = msg_verify(msg);
if (ret)
return -1;
smp->length = MIN(msg->length, smp->capacity);
smp->sequence = msg->sequence;
smp->ts.origin = MSG_TS(msg);
smp->ts.received.tv_sec = -1;
smp->ts.received.tv_nsec = -1;
memcpy(smp->data, msg->data, SAMPLE_DATA_LEN(smp->length));
return 0;
}
int msg_from_sample(struct msg *msg, struct sample *smp)
{
*msg = MSG_INIT(smp->length, smp->sequence);
msg->ts.sec = smp->ts.origin.tv_sec;
msg->ts.nsec = smp->ts.origin.tv_nsec;
memcpy(msg->data, smp->data, MSG_DATA_LEN(smp->length));
msg_hton(msg);
return 0;
}
ssize_t msg_buffer_from_samples(struct sample *smps[], unsigned cnt, char *buf, size_t len)
{
int ret, i = 0;
char *ptr = buf;
struct msg *msg = (struct msg *) ptr;
struct sample *smp = smps[i];
while (ptr < buf + len && i < cnt) {
ret = msg_from_sample(msg, smp);
if (ret)
return ret;
ptr += MSG_LEN(smp->length);
msg = (struct msg *) ptr;
smp = smps[++i];
}
return ptr - buf;
}
int msg_buffer_to_samples(struct sample *smps[], unsigned cnt, char *buf, size_t len)
{
int ret, i = 0;
char *ptr = buf;
struct msg *msg = (struct msg *) ptr;
struct sample *smp = smps[i];
while (ptr < buf + len && i < cnt) {
ret = msg_to_sample(msg, smp);
if (ret)
return ret;
ptr += MSG_LEN(smp->length);
msg = (struct msg *) ptr;
smp = smps[++i];
}
return i;
}

251
lib/nodes/nanomsg.c Normal file
View file

@ -0,0 +1,251 @@
/** Node type: nanomsg
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2017, Institute for Automation of Complex Power Systems, EONERC
* @license GNU General Public License (version 3)
*
* VILLASnode
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#include <nanomsg/nn.h>
#include <nanomsg/pubsub.h>
#include <string.h>
#include "plugin.h"
#include "nodes/nanomsg.h"
#include "utils.h"
#include "msg.h"
int nanomsg_reverse(struct node *n)
{
struct nanomsg *m = n->_vd;
if (list_length(&m->publisher.endpoints) != 1 ||
list_length(&m->subscriber.endpoints) != 1)
return -1;
char *subscriber = list_first(&m->subscriber.endpoints);
char *publisher = list_first(&m->publisher.endpoints);
list_set(&m->subscriber.endpoints, 0, publisher);
list_set(&m->publisher.endpoints, 0, subscriber);
return 0;
}
static int nanomsg_parse_endpoints(struct list *l, config_setting_t *cfg)
{
const char *ep;
switch (config_setting_type(cfg)) {
case CONFIG_TYPE_LIST:
case CONFIG_TYPE_ARRAY:
for (int j = 0; j < config_setting_length(cfg); j++) {
const char *ep = config_setting_get_string_elem(cfg, j);
list_push(l, strdup(ep));
}
break;
case CONFIG_TYPE_STRING:
ep = config_setting_get_string(cfg);
list_push(l, strdup(ep));
break;
default:
return -1;
}
return 0;
}
int nanomsg_parse(struct node *n, config_setting_t *cfg)
{
int ret;
struct nanomsg *m = n->_vd;
config_setting_t *cfg_pub, *cfg_sub;
list_init(&m->publisher.endpoints);
list_init(&m->subscriber.endpoints);
cfg_pub = config_setting_lookup(cfg, "publish");
if (cfg_pub) {
ret = nanomsg_parse_endpoints(&m->publisher.endpoints, cfg_pub);
if (ret < 0)
cerror(cfg_pub, "Invalid type for 'publish' setting of node %s", node_name(n));
}
cfg_sub = config_setting_lookup(cfg, "subscribe");
if (cfg_sub) {
ret = nanomsg_parse_endpoints(&m->subscriber.endpoints, cfg_sub);
if (ret < 0)
cerror(cfg_pub, "Invalid type for 'subscribe' setting of node %s", node_name(n));
}
return 0;
}
char * nanomsg_print(struct node *n)
{
struct nanomsg *m = n->_vd;
char *buf = NULL;
strcatf(&buf, "subscribe=[ ");
for (size_t i = 0; i < list_length(&m->subscriber.endpoints); i++) {
char *ep = list_at(&m->subscriber.endpoints, i);
strcatf(&buf, "%s ", ep);
}
strcatf(&buf, "], publish=[ ");
for (size_t i = 0; i < list_length(&m->publisher.endpoints); i++) {
char *ep = list_at(&m->publisher.endpoints, i);
strcatf(&buf, "%s ", ep);
}
strcatf(&buf, " ]");
return buf;
}
int nanomsg_start(struct node *n)
{
int ret;
struct nanomsg *m = n->_vd;
ret = m->subscriber.socket = nn_socket(AF_SP, NN_SUB);
if (ret < 0)
return ret;
ret = m->publisher.socket = nn_socket(AF_SP, NN_PUB);
if (ret < 0)
return ret;
/* Subscribe to all topics */
ret = nn_setsockopt(ret = m->subscriber.socket, NN_SUB, NN_SUB_SUBSCRIBE, "", 0);
if (ret < 0)
return ret;
/* Bind publisher to socket */
for (size_t i = 0; i < list_length(&m->publisher.endpoints); i++) {
char *ep = list_at(&m->publisher.endpoints, i);
ret = nn_bind(m->publisher.socket, ep);
if (ret < 0) {
info("Failed to connect nanomsg socket: node=%s, endpoint=%s, error=%s", node_name(n), ep, nn_strerror(errno));
return ret;
}
}
/* Sonnect subscribers socket */
for (size_t i = 0; i < list_length(&m->subscriber.endpoints); i++) {
char *ep = list_at(&m->subscriber.endpoints, i);
ret = nn_connect(m->subscriber.socket, ep);
if (ret < 0) {
info("Failed to connect nanomsg socket: node=%s, endpoint=%s, error=%s", node_name(n), ep, nn_strerror(errno));
return ret;
}
}
return 0;
}
int nanomsg_stop(struct node *n)
{
int ret;
struct nanomsg *m = n->_vd;
ret = nn_shutdown(m->subscriber.socket, 0);
if (ret < 0)
return ret;
ret = nn_shutdown(m->publisher.socket, 0);
if (ret < 0)
return ret;
return 0;
}
int nanomsg_deinit()
{
nn_term();
return 0;
}
int nanomsg_read(struct node *n, struct sample *smps[], unsigned cnt)
{
int ret;
struct nanomsg *m = n->_vd;
char data[MSG_MAX_PACKET_LEN];
/* Receive payload */
ret = nn_recv(m->subscriber.socket, data, sizeof(data), 0);
if (ret < 0)
return ret;
return msg_buffer_to_samples(smps, cnt, data, ret);
}
int nanomsg_write(struct node *n, struct sample *smps[], unsigned cnt)
{
int ret;
struct nanomsg *m = n->_vd;
ssize_t sent;
char data[MSG_MAX_PACKET_LEN];
sent = msg_buffer_from_samples(smps, cnt, data, sizeof(data));
if (sent < 0)
return -1;
ret = nn_send(m->publisher.socket, data, sent, 0);
if (ret < 0)
return ret;
return cnt;
}
static struct plugin p = {
.name = "nanomsg",
.description = "scalability protocols library",
.type = PLUGIN_TYPE_NODE,
.node = {
.vectorize = 0,
.size = sizeof(struct nanomsg),
.reverse = nanomsg_reverse,
.parse = nanomsg_parse,
.print = nanomsg_print,
.start = nanomsg_start,
.stop = nanomsg_stop,
.deinit = nanomsg_deinit,
.read = nanomsg_read,
.write = nanomsg_write,
.instances = LIST_INIT()
}
};
REGISTER_PLUGIN(&p)

View file

@ -348,37 +348,16 @@ static int socket_read_villas(struct node *n, struct sample *smps[], unsigned cn
error("Remote node %s closed the connection", node_name(n));
else if (bytes < 0)
serror("Failed receive packet from node %s", node_name(n));
int received = 0;
char *ptr = data;
struct msg *msg = (struct msg *) ptr;
struct sample *smp = smps[received];
while (ptr < data + bytes - sizeof(struct msg) && received < cnt) {
msg_ntoh(msg);
ret = msg_verify(msg);
if (ret) {
warn("Received invalid packet for node %s", node_name(n));
return -1;
}
smp->length = msg->length;
smp->sequence = msg->sequence;
smp->ts.origin = MSG_TS(msg);
smp->ts.received.tv_sec = -1;
smp->ts.received.tv_nsec = -1;
memcpy(smp->data, msg->data, SAMPLE_DATA_LEN(msg->length));
ptr += MSG_LEN(msg->length);
msg = (struct msg *) ptr;
smp = smps[++received];
else if (bytes < MSG_LEN(1) || bytes % 4 != 0) {
warn("Received invalid packet for node %s", node_name(n));
return 0;
}
return received;
ret = msg_buffer_to_samples(smps, cnt, data, bytes);
if (ret < 0)
warn("Received invalid packet from node: %s", node_name(n));
return ret;
}
static int socket_write_none(struct node *n, struct sample *smps[], unsigned cnt)
@ -423,32 +402,15 @@ static int socket_write_villas(struct node *n, struct sample *smps[], unsigned c
{
struct socket *s = n->_vd;
ssize_t bytes = 0;
char data[MSG_MAX_PACKET_LEN];
ssize_t bytes = 0, sent;
for (int i = 0; i < cnt; i++)
bytes += MSG_LEN(smps[i]->length);
char data[bytes], *ptr = data;
struct msg *msg = (struct msg *) ptr;
for (int i = 0; i < cnt; i++) {
*msg = MSG_INIT(smps[i]->length, smps[i]->sequence);
msg->ts.sec = smps[i]->ts.origin.tv_sec;
msg->ts.nsec = smps[i]->ts.origin.tv_nsec;
memcpy(msg->data, smps[i]->data, MSG_DATA_LEN(smps[i]->length));
msg_hton(msg);
ptr += MSG_LEN(msg->length);
msg = (struct msg *) ptr;
}
sent = msg_buffer_from_samples(smps, cnt, data, sizeof(data));
if (sent < 0)
return -1;
/* Send message */
bytes = sendto(s->sd, data, bytes, 0, (struct sockaddr *) &s->remote, sizeof(s->remote));
bytes = sendto(s->sd, data, sent, 0, (struct sockaddr *) &s->remote, sizeof(s->remote));
if (bytes < 0)
serror("Failed send to node %s", node_name(n));

View file

@ -38,6 +38,14 @@ rpm-libxil: $(BUILDDIR)/thirdparty/libxil/ | $(RPMDIR)/SOURCES/
cp $(BUILDDIR)/thirdparty/libxil/libxil-*.tar.gz $(RPMDIR)/SOURCES/
rpmbuild -ba --define="_topdir $$(pwd)/$(RPMDIR)" $(SRCDIR)/thirdparty/libxil/libxil.spec
rpm-nanomsg: $(BUILDDIR)/thirdparty/nanomsg/ | $(RPMDIR)/SOURCES/
cmake -DCMAKE_INSTALL_PREFIX:PATH=$(PREFIX) \
-H$(SRCDIR)/thirdparty/nanomsg \
-B$(BUILDDIR)/thirdparty/nanomsg $(CMAKE_OPTS)
make -C$(BUILDDIR)/thirdparty/nanomsg package_source
cp $(BUILDDIR)/thirdparty/nanomsg/nanomsg-*.tar.gz $(RPMDIR)/SOURCES/
rpmbuild -ba --define="_topdir $$(pwd)/$(RPMDIR)" $(SRCDIR)/packaging/rpm/nanomsg.spec
rpm-libwebsockets: | $(RPMDIR)/RPMS/x86_64/ $(BUILDDIR)/thirdparty/libwebsockets/
cmake -DCMAKE_INSTALL_PREFIX:PATH=$(PREFIX) \
-H$(SRCDIR)/thirdparty/libwebsockets \

157
packaging/rpm/nanomsg.spec Normal file
View file

@ -0,0 +1,157 @@
# Don't create static libraries (unless we want to)
%bcond_with static
Name: nanomsg
Version: 1.0.0
Release: 40.master.20170523gitg5cc0074%{?dist}
Summary: A fast, scalable, and easy to use socket library
Group: System Environment/Libraries
License: MIT
URL: http://nanomsg.org/
Source0: nanomsg-%{version}-40-g5cc0074.tar.gz
BuildRequires: rubygem-asciidoctor xmlto cmake
BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
%description
nanomsg is a socket library that provides several common communication
patterns. It aims to make the networking layer fast, scalable, and easy
to use. Implemented in C, it works on a wide range of operating systems
with no further dependencies.
The communication patterns, also called "scalability protocols", are
basic blocks for building distributed systems. By combining them you can
create a vast array of distributed applications.
%if %{with static}
%package static
Summary: Libraries for static linking of applications which will use nanomsg
Group: Development/Libraries
Requires: %{name}-devel%{?_isa} = %{version}-%{release}
%description static
nanomsg is a socket library that provides several common communication
patterns. The nanomsg-static package includes static libraries needed to
link and develop applications using this library.
Most users will not need to install this package.
%endif
%package devel
Summary: Development files for the nanomsg socket library
Group: Development/Libraries
Requires: %{name}%{?_isa} = %{version}-%{release}
%description devel
This package contains files needed to develop applications using nanomsg,
a socket library that provides several common communication patterns.
%package utils
Summary: Command line interface for communicating with nanomsg
Group: Applications/Internet
%description utils
Includes nanocat, a simple utility for reading and writing to nanomsg
sockets and bindings, which can include local and remote connections.
%prep
%setup -q -n nanomsg-1.0.0-40-g5cc0074/
%build
# Enabling static library build disables the dynamic library.
# First configure and build the static library, then reconfigure and build
# the dynamic libs, tools and docs afterwards instead of patching CMake build files
%if %{with static}
%cmake -DNN_STATIC_LIB=ON -DNN_ENABLE_DOC=OFF -DNN_ENABLE_TEST=OFF -DNN_ENABLE_TOOLS=OFF .
make %{?_smp_mflags} V=1
%endif
%cmake -DNN_STATIC_LIB=OFF -DNN_ENABLE_DOC=ON -DNN_ENABLE_TEST=ON -DNN_ENABLE_TOOLS=ON .
make %{?_smp_mflags} V=1
%install
rm -fR %{buildroot}
make install DESTDIR="%{buildroot}"
%check
#make test LD_LIBRARY_PATH="%{buildroot}%{_libdir}" DESTDIR="%{buildroot}"
%post -p /sbin/ldconfig
%postun -p /sbin/ldconfig
%clean
rm -fR %{buildroot}
%files
%defattr(-,root,root)
%doc AUTHORS COPYING README.md
%{_libdir}/*.so.*
%if %{with static}
%files static
%defattr(-,root,root)
%{_libdir}/*.a*
%endif
%files devel
%defattr(-,root,root)
%{_docdir}/%{name}
%{_mandir}/man7/*
%{_mandir}/man3/*
%{_includedir}/*
%{_libdir}/*.so
%{_libdir}/pkgconfig/*.pc
%files utils
%defattr(-,root,root)
%{_mandir}/man1/*
%{_bindir}/*
%changelog
* Sat Apr 1 2017 Tarjei Knapstad <tarjei.knapstad@gmail.com> - 1.0.0-1
- Updated to 1.0.0 final release
- nanomsg moved to CMake, so this spec did too
- Changed source URL
- Moved contents of -doc package into -devel
- Removed conditional check, all tests should pass
- The nanocat symlink stuff is gone, nanocat is now a single binary with options
* Tue Oct 27 2015 Japheth Cleaver <cleaver@terabithia.org> 0.7-0.1.beta
- update to 0.7-beta release
* Fri Nov 14 2014 Japheth Cleaver <cleaver@terabithia.org> 0.5-0.1.beta
- update to 0.5-beta release
* Sun Jul 27 2014 Japheth Cleaver <cleaver@terabithia.org> 0.4-0.3.beta
- compile with correct Fedora flags
- move documentation back to base package
- spec file cleanups
* Thu Jul 17 2014 Japheth Cleaver <cleaver@terabithia.org> 0.4-0.2.beta
- drop the 'lib' prefix from package name
- remove explicit pkgconfig requires in nanomsg-devel
- move overview man pages to devel subpackage
- move html to doc subpackage
* Thu Jul 17 2014 Japheth Cleaver <cleaver@terabithia.org> 0.4-0.1.beta
- new "libnanomsg" package based on BZ#1012392, with current versioning
- devel and utils subpackages created, static lib a build conditional
- check section added as a build conditional
- ensure man pages for nanocat symlinks present
- disable RPATH in library
- License set to MIT

View file

@ -20,7 +20,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
###################################################################################
DEPS_CMAKE = libxil libwebsockets criterion jansson
DEPS_CMAKE = libxil libwebsockets criterion jansson nanomsg
DEPS_AUTOCONF = libnl libconfig libcurl
DEPS = $(DEPS_CMAKE) $(DEPS_AUTOCONF)

1
thirdparty/nanomsg vendored Submodule

@ -0,0 +1 @@
Subproject commit 5cc0074524684797dd5cd9067bbccbefe1513996