aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Pickering <alex@cogarr.net>2020-07-13 16:16:46 -0400
committerAlexander Pickering <alex@cogarr.net>2020-07-13 16:16:46 -0400
commitcb3bd57fb3bac138a5426960e413ddd2176c4616 (patch)
tree446bc109f8d17b3d6946c190504445261155d5fc
downloadlua-nng-cb3bd57fb3bac138a5426960e413ddd2176c4616.tar.gz
lua-nng-cb3bd57fb3bac138a5426960e413ddd2176c4616.tar.bz2
lua-nng-cb3bd57fb3bac138a5426960e413ddd2176c4616.zip
Inital Commit
-rw-r--r--Makefile34
-rw-r--r--lua-nng-dev-1.rockspec45
-rw-r--r--spec/startup_spec.lua83
-rw-r--r--src/lua-nng.c228
4 files changed, 390 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..d82ee92
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,34 @@
+CC?=gcc
+CAFLAGS+=-I$(NNG_INCDIR) -I$(LUA_INCDIR) $(CFLAGS)
+LADFLAGS+=$(LIBFLAG) $(LDFLAGS) -L$(NNG_LIBDIR) -L$(LUA_LIBDIR)
+LD=gcc
+LIBS=-lnng -llua53
+
+ifeq ($(OS), Windows_NT)
+ LDFLAGS+=-mwindows
+ LIBS+=-lws2_32
+else
+endif
+
+
+src_files=$(shell find src/*.c)
+obj_files=$(src_files:src/%.c=build/%.o)
+target=bin/nng.$(LIB_EXTENSION)
+
+all: $(target)
+
+$(target) : $(obj_files)
+ $(LD) $(LADFLAGS) -o $@ $^ $(LIBS)
+
+$(obj_files): build/%.o : src/%.c
+ $(CC) $(CAFLAGS) -c -o $@ $<
+
+install: $(target)
+ $(CP) $(target) $(INST_LIBDIR)
+
+test:
+ busted --cpath=./bin/?$(SHARE_EXT)
+
+clean:
+ rm -rf build/*
+ rm -rf bin/*
diff --git a/lua-nng-dev-1.rockspec b/lua-nng-dev-1.rockspec
new file mode 100644
index 0000000..5cf013f
--- /dev/null
+++ b/lua-nng-dev-1.rockspec
@@ -0,0 +1,45 @@
+package = "lua-nng"
+rockspec_format="3.0"
+version = "dev-1"
+source = {
+ url = "*** please add URL for source tarball, zip or repository here ***"
+}
+description = {
+ summary = "A simple binding for Nanomessage Next Generation",
+ homepage = "https://cogarr.net/source/cgit.cgi/lua-nng/about",
+ license = "BSD/2 Clause",
+ maintainer = "Alexander Pickering <alex@cogarr.net>",
+ labels = {"network","nanomessage","nng"}
+}
+external_dependencies = {
+ NNG = {
+ library = "nng",
+ header = "nng/nng.h"
+ }
+}
+build = {
+ type = "make",
+ build_variables = {
+ CFLAGS="$(CFLAGS)",
+ LUA_INCDIR="$(LUA_INCDIR)",
+ NNG_INCDIR="$(NNG_INCDIR)",
+ NNG_LIBDIR="$(NNG_LIBDIR)",
+ LUA_LIBDIR="$(LUA_LIBDIR)",
+ FIND="$(FIND)",
+ LIB_EXTENSION="$(LIB_EXTENSION)",
+ LIBFLAG="$(LIBFLAG)",
+ },
+ install_variables = {
+ INST_PREFIX="$(PREFIX)",
+ INST_LIBDIR="$(LIBDIR)",
+ NNG_LIBDIR="$(NNG_LIBDIR)",
+ LUA_LIBDIR="$(LUA_LIBDIR)",
+ LIB_EXTENSION="$(LIB_EXTENSION)",
+ CP="$(CP)",
+ },
+ install = {
+ bin = {
+ "bin/nng.dll"
+ }
+ }
+}
diff --git a/spec/startup_spec.lua b/spec/startup_spec.lua
new file mode 100644
index 0000000..45fa996
--- /dev/null
+++ b/spec/startup_spec.lua
@@ -0,0 +1,83 @@
+--[[
+test startup of nanomsg api
+]]
+
+describe("nng",function()
+ local nng
+ it("should be included with require()",function()
+ nng = require("nng")
+ end)
+ it("should be able to create sockets",function()
+ local socket = assert(nng.pair1_open())
+ end)
+ it("should be able to extablish a connection over inter-process communication",function()
+ local s1 = assert(nng.pair1_open())
+ local s2 = assert(nng.pair1_open())
+ assert(s1:listen("ipc:///tmp/pair.ipc"))
+ assert(s2:dial("ipc://tmp/pair.ipc"))
+
+ assert(s2:send("hello"))
+ local rec = assert(s1:recv())
+ assert(rec == "hello","Failed to receive hello, received:" .. rec)
+ end)
+ it("should be able to use a bus socket to distribute information",function()
+ local b = {}
+ for i = 1,10 do
+ local s = assert(nng.bus0_open())
+ b[i] = s
+ end
+ for i = 1,10 do
+ local ipcaddr = string.format("ipc:///tmp/bus_%d.ipc",i)
+ assert(b[i]:listen(ipcaddr))
+ end
+ for i = 1,10 do
+ for j = 1,10 do
+ if i ~= j then
+ local addr = string.format("ipc:///tmp/bus_%d.ipc",j)
+ assert(b[i]:dial(addr))
+ end
+ end
+ end
+ assert(b[1]:send("Hello"))
+ for i = 2,10 do
+ local msg = assert(b[i]:recv())
+ assert(msg == "Hello")
+ end
+ end)
+ it("should be able to use a survey socket to gather information",function()
+ math.randomseed(os.time())
+ local s = assert(nng.surveyor0_open())
+ assert(s:listen("ipc:///tmp/survey.ipc"))
+ local b = {}
+ for i = 1,100 do
+ local r = assert(nng.respondent0_open())
+ assert(r:dial("ipc:///tmp/survey.ipc"))
+ b[i] = r
+ end
+ assert(s:send("Hello"))
+ for i = 1,100 do
+ local survey = assert(b[i]:recv())
+ assert(survey == "Hello")
+ assert(b[i]:send(string.format("%f",math.random())))
+ end
+ local responses = {}
+ while true do
+ local succ, msg = s:recv(nng.NNG_FLAG_NONBLOCK)
+ if succ then
+ table.insert(responses,tonumber(succ))
+ elseif msg == "Try again" then
+ os.execute("sleep 1")
+ elseif msg == "Incorrect state" then
+ break
+ end
+ end
+ local avg = 0
+ for _,v in pairs(responses) do
+ avg = avg + v
+ end
+ avg = avg / #responses
+ --avg should be about 0.5
+ assert(avg > 0.4)
+ assert(avg < 0.6)
+ end)
+end)
diff --git a/src/lua-nng.c b/src/lua-nng.c
new file mode 100644
index 0000000..71e57e8
--- /dev/null
+++ b/src/lua-nng.c
@@ -0,0 +1,228 @@
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+
+#define NNG_STATIC_LIB
+
+#include <nng/nng.h>
+
+#include <nng/transport/inproc/inproc.h>
+#include <nng/transport/ipc/ipc.h>
+#include <nng/transport/tcp/tcp.h>
+#include <nng/transport/tls/tls.h>
+#include <nng/transport/zerotier/zerotier.h>
+
+#include <nng/protocol/pair1/pair.h>
+#include <nng/protocol/bus0/bus.h>
+#include <nng/protocol/pubsub0/pub.h>
+#include <nng/protocol/pubsub0/sub.h>
+#include <nng/protocol/pipeline0/pull.h>
+#include <nng/protocol/pipeline0/push.h>
+#include <nng/protocol/reqrep0/req.h>
+#include <nng/protocol/reqrep0/rep.h>
+#include <nng/protocol/survey0/respond.h>
+#include <nng/protocol/survey0/survey.h>
+
+#define OPEN(name)\
+ int lnng_ ## name ## _open(lua_State *L){\
+ nng_socket *s = (nng_socket*)lua_newuserdata(L,sizeof(nng_socket));\
+ int err = nng_ ## name ## _open(s);\
+ if(err == 0){\
+ luaL_setmetatable(L,"nng.socket");\
+ return 1;\
+ }else{\
+ lua_pushboolean(L,0);\
+ lua_pushstring(L,nng_strerror(err));\
+ return 2;\
+ }\
+ }
+
+OPEN(bus0);
+OPEN(pair1);
+OPEN(pub0);
+OPEN(sub0);
+OPEN(pull0);
+OPEN(push0);
+OPEN(req0);
+OPEN(rep0);
+OPEN(surveyor0);
+OPEN(respondent0);
+
+nng_socket* tosocket(lua_State *L, int offset){
+ luaL_checkudata(L,offset,"nng.socket");
+ return (nng_socket*)lua_touserdata(L,offset);
+}
+
+//socket:listen(url[, flags]) :: listener
+int lnng_listen(lua_State *L){
+ int argc = lua_gettop(L);
+ int flags = 0;
+ nng_socket *sock = tosocket(L,1);
+ const char *url = luaL_checkstring(L,2);
+ if(argc >= 3){
+ flags = luaL_checkinteger(L,3);
+ }
+ lua_pop(L,argc);
+ nng_listener *lp = (nng_listener*)lua_newuserdata(L,sizeof(nng_listener));
+ int err = nng_listen(*sock, url, lp, flags);
+ if(err == 0){
+ luaL_setmetatable(L,"nng.listener");
+ return 1;
+ }else{
+ lua_pushboolean(L,0);
+ lua_pushstring(L,nng_strerror(err));
+ return 2;
+ }
+}
+
+//socket:dial(url[, flags]) :: dialer
+int lnng_dial(lua_State *L){
+ int argc = lua_gettop(L);
+ int flags = 0;
+ nng_socket *sock = tosocket(L,1);
+ const char *url = luaL_checkstring(L,2);
+ if(argc >= 3){
+ flags = luaL_checkinteger(L,3);
+ }
+ lua_pop(L,argc);
+ nng_dialer *dp = (nng_dialer*)lua_newuserdata(L,sizeof(nng_dialer));
+ int err = nng_dial(*sock, url, dp, flags);
+ if(err == 0){
+ luaL_setmetatable(L,"nng.dialer");
+ return 1;
+ }else{
+ lua_pushboolean(L,0);
+ lua_pushstring(L,nng_strerror(err));
+ return 2;
+ }
+}
+
+//socket:send("data"[, flags])
+int lnng_send(lua_State *L){
+ int argc = lua_gettop(L);
+ int flags = 0;
+ nng_socket *sock = tosocket(L,1);
+ size_t datasize;
+ const char *data = luaL_checklstring(L,2,&datasize);
+ if(argc >= 3){
+ flags = luaL_checkinteger(L,3);
+ }
+ lua_pop(L,argc);
+ int err = nng_send(*sock, (void*)data, datasize, flags);
+ if(err == 0){
+ lua_pushboolean(L,1);
+ return 1;
+ }else{
+ lua_pushboolean(L,0);
+ lua_pushstring(L,nng_strerror(err));
+ return 2;
+ }
+}
+
+//socket:recv([flags])
+int lnng_recv(lua_State *L){
+ int argc = lua_gettop(L);
+ int flags = NNG_FLAG_ALLOC; //don't support zero copy
+ nng_socket *sock = tosocket(L,1);
+ if(argc >= 2){
+ flags += luaL_checkinteger(L,2);
+ }
+ char *data = NULL;
+ size_t datasize;
+ int err = nng_recv(*sock, &data, &datasize, flags);
+ if(err == 0){
+ lua_pushlstring(L,data,datasize);
+ nng_free(data,datasize);
+ return 1;
+ }else{
+ lua_pushboolean(L,0);
+ lua_pushstring(L,nng_strerror(err));
+ return 2;
+ }
+}
+
+//socket:close()
+int lnng_socket_close(lua_State *L){
+ nng_socket *sock = tosocket(L,1);
+ int err = nng_close(*sock);
+ lua_pop(L,1);
+ return 0;
+}
+
+//close(ud_dialer)
+int lnng_dialer_close(lua_State *L){
+ nng_dialer *dp = (nng_dialer*)lua_touserdata(L,1);
+ nng_dialer_close(*dp);
+ lua_pop(L,1);
+ return 0;
+}
+
+//close(ud_listener)
+int lnng_listener_close(lua_State *L){
+ nng_listener *lp = (nng_listener*)lua_touserdata(L,1);
+ int err = nng_listener_close(*lp);
+ lua_pop(L,1);
+ return 0;
+}
+
+static const struct luaL_Reg nng_dialer_m[] = {
+
+ {NULL, NULL}
+};
+
+static const struct luaL_Reg nng_listener_m[] = {
+
+ {NULL, NULL}
+};
+
+static const struct luaL_Reg nng_socket_m[] = {
+ {"dial", lnng_dial},
+ {"listen", lnng_listen},
+ {"send", lnng_send},
+ {"recv", lnng_recv},
+ {NULL, NULL}
+};
+
+static const struct luaL_Reg nng_f[] = {
+ {"bus0_open", lnng_bus0_open},
+ {"pair1_open", lnng_pair1_open},
+ {"pub0_open", lnng_pub0_open},
+ {"sub0_open", lnng_sub0_open},
+ {"pull0_open", lnng_pull0_open},
+ {"push0_open", lnng_push0_open},
+ {"req0_open", lnng_req0_open},
+ {"rep0_open", lnng_rep0_open},
+ {"surveyor0_open",lnng_surveyor0_open},
+ {"respondent0_open",lnng_respondent0_open},
+ {NULL, NULL}
+};
+
+
+#define flag(name) lua_pushnumber(L,name); lua_setfield(L,-2,#name);
+int luaopen_nng(lua_State *L){
+ luaL_newmetatable(L,"nng.socket");
+ luaL_newlib(L,nng_socket_m);
+ lua_setfield(L,-2,"__index");
+ lua_pushcfunction(L,lnng_socket_close);
+ lua_setfield(L,-2,"__gc");
+ lua_pop(L,1);
+
+ luaL_newmetatable(L,"nng.dialer");
+ luaL_newlib(L,nng_dialer_m);
+ lua_setfield(L,-2,"__index");
+ lua_pushcfunction(L,lnng_dialer_close);
+ lua_setfield(L,-2,"__gc");
+ lua_pop(L,1);
+
+ luaL_newmetatable(L,"nng.listener");
+ luaL_newlib(L,nng_listener_m);
+ lua_setfield(L,-2,"__index");
+ lua_pushcfunction(L,lnng_listener_close);
+ lua_setfield(L,-2,"__gc");
+ lua_pop(L,1);
+
+ luaL_newlib(L,nng_f);
+ flag(NNG_FLAG_NONBLOCK);
+ flag(NNG_FLAG_ALLOC);
+ return 1;
+}