Compare commits

..

No commits in common. 'master' and 'native_objects' have entirely different histories.

1
.gitignore vendored

@ -1,4 +1,3 @@
build
*.lo
*.so
*.swp

@ -1,68 +0,0 @@
language: c
env:
matrix:
- LUA=lua5.1 LIBLUA=liblua5.1-dev LUA_INCDIR=/usr/include/lua5.1 LUA_LIB=lua5.1
- LUA=lua5.2 LIBLUA=liblua5.2-dev LUA_INCDIR=/usr/include/lua5.2 LUA_LIB=lua5.2
- LUA=luajit LIBLUA=libluajit-5.1-dev LUA_INCDIR=/usr/include/luajit-2.0 LUA_LIB=luajit-5.1
branches:
only:
- master
compiler:
- gcc
before_install:
- if [ $LUA = "luajit" ]; then
sudo add-apt-repository ppa:mwild1/ppa -y && sudo apt-get update -y;
fi
install:
- sudo apt-get install libzmq3-dev -y
- sudo apt-get install $LUA -y
- sudo apt-get install $LIBLUA -y
- LUA_LIBDIR=`pkg-config $LUA --variable=libdir`
- INSTALL_LMOD=`pkg-config $LUA --variable=INSTALL_LMOD`
- INSTALL_CMOD=`pkg-config $LUA --variable=INSTALL_CMOD`
## make sure there is a 'lua' command.
- if [ ! -x /usr/bin/lua ]; then
sudo ln -s `which $LUA` /usr/bin/lua;
fi
## install lua-llthreads
- git clone git://github.com/Neopallium/lua-llthreads.git
- cd lua-llthreads ; mkdir build ; cd build
- cmake .. -DLUA_LIBRARIES=$LUA_LIBDIR -DLUA_INCLUDE_DIR=$LUA_INCDIR
-DINSTALL_LMOD=$INSTALL_LMOD -DINSTALL_CMOD=$INSTALL_CMOD
- make
- sudo make install
- cd ../..
script:
#### build using pre-generated bindings.
- mkdir build; cd build
- cmake .. -DLUA_LIBRARIES=$LUA_LIBDIR -DLUA_INCLUDE_DIR=$LUA_INCDIR
-DINSTALL_LMOD=$INSTALL_LMOD -DINSTALL_CMOD=$INSTALL_CMOD
- make
- sudo make install
# Run tests.
- $LUA ../tests/test_inproc.lua
- $LUA ../perf/thread_lat.lua 1 1000
- cd .. ; rm -rf build
#### Re-Generate bindings.
- git clone git://github.com/Neopallium/LuaNativeObjects.git;
- mkdir build; cd build
- cmake .. -DLUA_LIBRARIES=$LUA_LIBDIR -DLUA_INCLUDE_DIR=$LUA_INCDIR
-DLUA_NATIVE_OBJECTS_PATH=$TRAVIS_BUILD_DIR/LuaNativeObjects
-DUSE_PRE_GENERATED_BINDINGS=OFF -DGENERATE_LUADOCS=OFF
-DINSTALL_LMOD=$INSTALL_LMOD -DINSTALL_CMOD=$INSTALL_CMOD
- make
- sudo make install
# Run tests.
- $LUA ../tests/test_inproc.lua
- $LUA ../perf/thread_lat.lua 1 1000
notifications:
email:
on_failure: always
on_success: change

211
API.md

@ -2,248 +2,81 @@
ZMQ_CONSTANT_NAME in the C API turns into zmq.CONSTANT_NAME in Lua.
## version()
## version
Reports 0MQ library version.
See [zmq_version(3)](http://api.zeromq.org/zmq_version.html).
zmq.version()
## init(io_threads)
## init
Initialises ØMQ context.
See [zmq_init(3)](http://api.zeromq.org/zmq_init.html).
zmq.init(io_threads)
# ZMQ Context methods
## term()
## term
Terminates ØMQ context.
See [zmq_term(3)](http://api.zeromq.org/zmq_term.html).
ctx:term()
## socket(type)
## socket
Creates ØMQ socket.
See [zmq_socket(3)](http://api.zeromq.org/zmq_socket.html).
ctx:socket(type)
# ZMQ Socket methods
## close()
## close
Destroys ØMQ socket.
See [zmq_close(3)](http://api.zeromq.org/zmq_close.html).
sock:close()
s:close()
## setopt(option, optval)
## setopt
Sets a specified option on a ØMQ socket.
See [zmq_setsockopt(3)](http://api.zeromq.org/zmq_setsockopt.html).
sock:setopt(option, optval)
s:setopt(option, optval)
## getopt(option)
## getopt
Gets a specified option of a ØMQ socket.
See [zmq_getsockopt(3)](http://api.zeromq.org/zmq_getsockopt.html).
sock:getopt(option)
s:getopt(option)
## bind(addr)
## bind
Binds the socket to the specified address.
See [zmq_bind(3)](http://api.zeromq.org/zmq_bind.html).
sock:bind(addr)
s:bind(addr)
## connect(addr)
## connect
Connect the socket to the specified address.
See [zmq_connect(3)](http://api.zeromq.org/zmq_connect.html).
sock:connect(addr)
## send(msg [, flags])
Sends a message(Lua string).
See [zmq_send(3)](http://api.zeromq.org/zmq_send.html).
sock:send(msg)
sock:send(msg, flags)
## recv([flags])
Retrieves a message(a Lua string) from the socket.
See [zmq_recv(3)](http://api.zeromq.org/zmq_recv.html).
msg = sock:recv()
msg = sock:recv(flags)
# Zero-copy send_msg/recv_msg methods
These methods allow Zero-copy transfer of a message from one ZMQ socket to another.
s:connect(addr)
## send_msg(msg [, flags])
## send
Sends a message from a zmq_msg_t object.
Sends a message.
See [zmq_send(3)](http://api.zeromq.org/zmq_send.html).
sock:send_msg(msg)
sock:send_msg(msg, flags)
s:send(msg)
s:send(msg, flags)
## recv_msg(msg [, flags])
## recv
Retrieves a message from the socket into a zmq_msg_t object.
Retrieves a message from the socket.
See [zmq_recv(3)](http://api.zeromq.org/zmq_recv.html).
sock:recv_msg(msg)
sock:recv_msg(msg, flags)
# zmq_msg_t object constructors
## zmq_msg_t.init()
Create an empty zmq_msg_t object.
See [zmq_msg_init(3)](http://api.zeromq.org/zmq_msg_init.html).
local msg = zmq_msg_t.init()
## zmq_msg_t.init_size(size)
Create an empty zmq_msg_t object and allow space for a message of `size` bytes.
See [zmq_msg_init_size(3)](http://api.zeromq.org/zmq_msg_init_size.html).
local msg = zmq_msg_t.init_size(size)
msg:set_data(data) -- if (#data ~= size) then the message will be re-sized.
## zmq_msg_t.init_data(data)
Create an zmq_msg_t object initialized with the content of `data`.
local msg = zmq_msg_t.init_data(data)
-- that is the same as:
local msg = zmq_msg_t.init_size(#data)
msg:set_data(data)
# zmq_msg_t object methods
## move(src)
Move the contents of one message into another.
See [zmq_msg_move(3)](http://api.zeromq.org/zmq_msg_move.html).
msg1:move(msg2) -- move contents from msg2 -> msg1
## copy(src)
Copy the contents of one message into another.
See [zmq_msg_copy(3)](http://api.zeromq.org/zmq_msg_copy.html).
msg1:copy(msg2) -- copy contents from msg2 -> msg1
## set_size(size)
Re-initialize the message with a new size. The current contents will be lost.
See [zmq_msg_init_size(3)](http://api.zeromq.org/zmq_msg_init_size.html).
msg:set_size(size) -- re-initialize message if size is different from current size.
local buf = msg:data() -- get buffer to fill message with new contents.
## set_data(data)
Change the message contents.
See [zmq_msg_data(3)](http://api.zeromq.org/zmq_msg_data.html).
msg:set_data(data) -- replace/set the message contents to `data`
## data()
Get a lightuserdata pointer to the message contents.
See [zmq_msg_data(3)](http://api.zeromq.org/zmq_msg_data.html).
local data = msg:data() -- get the message contents
## size()
Get the size of the message contents.
See [zmq_msg_size(3)](http://api.zeromq.org/zmq_msg_size.html).
local size = msg:size()
## close()
Free the message contents and invalid the zmq_msg_t userdata object.
See [zmq_msg_close(3)](http://api.zeromq.org/zmq_msg_close.html).
msg:close() -- free message contents and invalid `msg`
# FD/ZMQ Socket poller object
The poller object wraps [zmq_poll()](http://api.zeromq.org/zmq_poll.html) to allow polling
of events from multiple ZMQ Sockets and/or normal sockets.
## zmq.poller([pre_alloc])
Construct a new poller object. The optional `pre_alloc` parameter is to pre-size the poller
for the number of sockets it will handle (the size can grow dynamically as-needed).
local poller = zmq.poller(64)
## add(socket|fd, events, callback)
Add a ZMQ Socket or fd to the poller. `callback` will be called when one of the events
in `events` is raised.
poller:add(sock, zmq.POLLIN, function(sock) print(sock, " is readable.") end)
poller:add(sock, zmq.POLLOUT, function(sock) print(sock, " is writable.") end)
poller:add(sock, zmq.POLLIN+zmq.POLLOUT, function(sock, revents)
print(sock, " has events:", revents)
end)
## modify(socket|fd, events, callback)
Change the `events` or `callback` for a socket/fd.
-- first wait for read event.
poller:add(sock, zmq.POLLIN, function(sock) print(sock, " is readable.") end)
-- now wait for write event.
poller:modify(sock, zmq.POLLOUT, function(sock) print(sock, " is writable.") end)
## remove(socket|fd)
Remove a socket/fd from the poller.
-- first wait for read event.
poller:add(sock, zmq.POLLIN, function(sock) print(sock, " is readable.") end)
-- remove socket from poller.
poller:remove(sock)
## poll(timeout)
Wait `timeout` milliseconds [1] for events on the registered sockets (timeout = -1, means
wait indefinitely). If any events happen, then those events are dispatched.
poller:poll(1000) -- wait 1 second for events.
[1] For zmq 2.x `timeout` is in microseconds. For versions 3.x or higher `timeout` will be in milliseconds.
poller:poll(1000 * zmq.POLL_MSEC) -- backwards/forwards compatible
## start()
Start an event loop waiting for and dispatching events.
poller:start()
## stop()
Stop the event loop.
poller:stop()
s:recv()
s:recv(flags)

@ -1,7 +1,7 @@
#
# Lua bindings for 0MQ
#
cmake_minimum_required(VERSION 3.18)
cmake_minimum_required(VERSION 2.8)
project(lua-zmq C)
@ -9,65 +9,32 @@ set(BUILD_SHARED_LIBS TRUE)
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
set(INSTALL_LMOD ${CMAKE_INSTALL_PREFIX}/share/lua/ CACHE PATH
"Directory to install Lua source modules (configure lua via LUA_PATH)")
set(INSTALL_CMOD ${CMAKE_INSTALL_PREFIX}/lib/lua/ CACHE PATH
"Directory to install Lua binary modules (configure lua via LUA_CPATH)")
set(ZMQ_PATH "" CACHE PATH
"Directory to libzmq. (by default use pkg-config to detect path)")
set(INSTALL_CMOD share/lua/cmod CACHE PATH "Directory to install Lua binary modules (configure lua via LUA_CPATH)")
set(LUA_NATIVE_OBJECTS_PATH ../LuaNativeObjects CACHE PATH
"Directory to LuaNativeObjects bindings generator.")
set(USE_PRE_GENERATED_BINDINGS TRUE CACHE BOOL
"Set this to FALSE to re-generate bindings using LuaNativeObjects")
set(COMMON_CFLAGS "${CFLAGS}")
set(COMMON_LDFLAGS)
set(COMMON_LIBS)
## Lua 5.x
include(FindLua)
if(NOT ${LUA_FOUND})
message(FATAL_ERROR "The FindLua module could not find lua :-(")
## Lua 5.1.x
include(FindLua51)
if(NOT ${LUA51_FOUND})
message(FATAL_ERROR "The FindLua51 module could not find lua :-(")
endif()
set(COMMON_LIBS "${COMMON_LIBS};${LUA_LIBRARIES}")
if(WIN32)
set(COMMON_CFLAGS "${COMMON_CFLAGS} -I${LUA_INCLUDE_DIR}")
set(COMMON_LDFLAGS "${COMMON_LDFLAGS} ${LUA_LIBRARY}")
if(NOT MSVC)
set(COMMON_LDFLAGS "${COMMON_LDFLAGS} -Wl,--export-all-symbols")
endif()
endif()
## MAC OSX needs extra linker flags
if(APPLE)
set(COMMON_LDFLAGS "${COMMON_LDFLAGS} -undefined dynamic_lookup")
endif()
## LibZMQ
if(WIN32)
## need ZMQ_PATH
if(IS_DIRECTORY "${ZMQ_PATH}")
else()
message(FATAL_ERROR "Please set the ZMQ_PATH CMake variable.")
endif()
endif()
if(IS_DIRECTORY ${ZMQ_PATH})
set(COMMON_CFLAGS "${COMMON_CFLAGS} -I${ZMQ_PATH}/include")
if(MSVC)
set(COMMON_LIBS "${COMMON_LIBS};libzmq")
else()
set(COMMON_LDFLAGS "${COMMON_LDFLAGS} -L${ZMQ_PATH}/lib")
set(COMMON_LIBS "${COMMON_LIBS};zmq")
endif()
link_directories(${ZMQ_PATH}/lib)
else()
## fallback to using pkg-config
include(FindPkgConfig)
pkg_search_module(ZMQ REQUIRED libzmq)
set(COMMON_CFLAGS "${COMMON_CFLAGS} ${ZMQ_CFLAGS}")
set(COMMON_LDFLAGS "${COMMON_LDFLAGS} ${ZMQ_LDFLAGS}")
set(COMMON_LIBS "${COMMON_LIBS};${ZMQ_LIBRARIES}")
endif()
## LuaNativeObjects
include(LuaNativeObjects)
include(CustomMacros)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
@ -78,14 +45,8 @@ set(LUA_ZMQ_SRC
zmq.nobj.lua
)
## LuaZMQ Lua source modules
set(LUA_ZMQ_SRC_LUA_MODS
src/poller.lua
src/threads.lua
)
if(${USE_PRE_GENERATED_BINDINGS})
set(LUA_ZMQ_SRC src/pre_generated-zmq.nobj.c)
set(LUA_ZMQ_SRC pre_generated-zmq.nobj.c)
else()
# Generate Lua bindings.
GenLuaNativeObjects(LUA_ZMQ_SRC)
@ -94,13 +55,9 @@ endif()
add_library(lua-zmq MODULE ${LUA_ZMQ_SRC})
target_link_libraries(lua-zmq ${COMMON_LIBS})
set_target_properties(lua-zmq PROPERTIES PREFIX "")
add_target_properties(lua-zmq COMPILE_FLAGS "${COMMON_CFLAGS}")
add_target_properties(lua-zmq LINK_FLAGS "${LD_FLAGS} ${COMMON_LDFLAGS}")
set_target_properties(lua-zmq PROPERTIES COMPILE_FLAGS "${COMMON_CFLAGS}")
set_target_properties(lua-zmq PROPERTIES OUTPUT_NAME zmq)
install(TARGETS lua-zmq
DESTINATION "${INSTALL_CMOD}")
install(FILES ${LUA_ZMQ_SRC_LUA_MODS}
DESTINATION "${INSTALL_LMOD}/zmq")

@ -1,19 +0,0 @@
Copyright (c) 2011 by Robert G. Jakabosky <bobby@neoawareness.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

@ -1,115 +1,17 @@
About
=====
[![travis-ci status](https://secure.travis-ci.org/Neopallium/lua-zmq.png?branch=master)](http://travis-ci.org/Neopallium/lua-zmq/builds)
Lua bindings to zeromq2. Check out the [ZeroMQ Guide with Lua examples](http://zguide.zeromq.org/lua:all).
Windows
=======
Download a compiled version of [LuaJIT 2.0.0-beta11 + lua-zmq + zeromq2.2.0](https://github.com/downloads/Neopallium/lua-zmq/luajit2.0_beta11_zmq2.2_llthreads.zip) 32bit & 64bit.
API
===
See [API.md](https://github.com/Neopallium/lua-zmq/blob/master/API.md) and
[ØMQ docs](http://api.zero.mq/2-1-3:_start).
Requirements
============
* ZeroMQ version 2.1, 2.2 or 3.2.
* Might work with some 2.0.x versions (2.0.6 and lower are not supported).
For Ubuntu 10.10 users:
* The version of ZeroMQ (2.0.6beta) that comes with Ubuntu 10.10 will not work with these bindings. Please upgrade to [version 2.1](http://fanf42.blogspot.com/2011/02/installing-zeromq-and-java-bindings-on.html).
Lua bindings to zeromq2.
Installation
============
It is recommended to either compile Lua with the "-pthread" flag or preload libpthread.so on Linux when using this module ([see this glibc bug report](http://sourceware.org/bugzilla/show_bug.cgi?id=10652)):
$ LD_PRELOAD=/lib/libpthread.so lua
Release 1.0
-----------
lua-zmq:
$ sudo luarocks install lua-zmq
lua-zmq-threads:
$ sudo luarocks install lua-llthreads
$ sudo luarocks install lua-zmq-threads
Latest Git revision
-------------------
With LuaRocks 2.0.4.1:
$ sudo luarocks install https://raw.github.com/Neopallium/lua-zmq/master/rockspecs/lua-zmq-scm-1.rockspec
For threads support:
$ sudo luarocks install https://raw.github.com/Neopallium/lua-llthreads/master/rockspecs/lua-llthreads-scm-0.rockspec
$ sudo luarocks install https://raw.github.com/Neopallium/lua-zmq/master/rockspecs/lua-zmq-threads-scm-0.rockspec
With CMake:
$ git clone git://github.com/Neopallium/lua-zmq.git
$ cd lua-zmq ; mkdir build ; cd build
$ cmake ..
$ make
$ sudo make install
Throughput benchmark
====================
Throughput benchmark using the tcp transport over localhost:
message size: 30 [B]
message count: 100000000
Using send/recv functions running under Lua 5.1.4:
mean throughput: 1577407 [msg/s]
mean throughput: 378.578 [Mb/s]
Using send/recv functions running under LuaJIT2 (git HEAD):
mean throughput: 5112158 [msg/s]
mean throughput: 1226.918 [Mb/s]
Using send_msg/recv_msg functions running under LuaJIT2 (git HEAD):
mean throughput: 6160911 [msg/s]
mean throughput: 1478.619 [Mb/s]
C++ code:
mean throughput: 6241452 [msg/s]
mean throughput: 1497.948 [Mb/s]
Running benchmarks
==================
When running the benchmarks you will need run two different scripts (one 'local' and one 'remote'). Both scripts can be run on the same computer or on different computers. Make sure to start the 'local' script first.
Throughput benchmark:
# first start local script
$ luajit-2 perf/local_thr.lua "tcp://lo:5555" 30 1000000
# then in another window start remote script
$ luajit-2 perf/remote_thr.lua "tcp://localhost:5555" 30 1000000
Latency benchmark:
# first start local script
$ luajit-2 perf/local_lat.lua "tcp://lo:5555" 1 100000
# then in another window start remote script
$ luajit-2 perf/remote_lat.lua "tcp://localhost:5555" 1 100000
<pre>
$ make install
</pre>
API
===
See [API.md](http://github.com/iamaleksey/lua-zmq/blob/master/API.md) and
[ØMQ docs](http://www.zeromq.org/area:docs-v20).

@ -1,13 +0,0 @@
To re-generating the bindings
-----------------------------
You will need to install LuaNativeObjects and set the CMake variable `USE_PRE_GENERATED_BINDINGS` to FALSE.
By default CMake will use the pre-generated bindings that are include in the project.
Build Dependencies
------------------
Optional dependency for re-generating Lua bindings from `*.nobj.lua` files:
* [LuaNativeObjects](https://github.com/Neopallium/LuaNativeObjects), this is the bindings generator used to convert the `*.nobj.lua` files into a native Lua module.

@ -1,47 +0,0 @@
Steps to install on Windows XP (using MinGW+MSYS)
-------------------------------------------------
1. Download source code of ZeroMQ-2.1.7
2. Use mingw+msys to compile
$ sh configure --prefix=c:/zeromq
$ make
$ make install
copy the header & lib to c:\mingw\include_or_lib
3. Download source code of luajit-2.0.0-beta7
$ make
$ make install
copy the header & lib to c:\mingw\include_or_lib
4. Install cmake-2.8.4-win32-x86
5. Download Neopallium-lua-zmq-1.1
6. Use cmake+mingw+msys to build
$ mkdir build
$ cd build
$ cmake -G "MSYS Makefiles" -D ZMQ_PATH=c:/zeromq ..
$ make
$ make install
Files zmq.dll, poller.lua and threads.lua are installed in c:\program files\lua-zmq
Author
------
xumingyong@gmail.com
xumingyong@ehdc.com.cn

@ -1,61 +0,0 @@
## Orignal Macros copied from lighttpd 2.0
## modules are without the "lib" prefix
macro(setup_static_modules TARGET)
file(WRITE ${TARGET}_builtins.h "/* auto-generated by CMake build do not edit */\n\n")
endmacro(setup_static_modules)
macro(add_module TARGET MODNAME)
set(_static_mod ${BUILD_STATIC})
## create list of module source files.
set(_srcfiles)
set(_def_module_src ${CMAKE_CURRENT_SOURCE_DIR}/modules/${MODNAME}.c)
if(EXISTS ${_def_module_src})
set(_srcfiles ${_def_module_src})
endif(EXISTS ${_def_module_src})
foreach(_srcfile ${ARGN})
if(_srcfile STREQUAL "STATIC")
set(_static_mod TRUE)
else(_srcfile STREQUAL "STATIC")
set(_srcfiles ${_srcfiles} ${_srcfile})
endif(_srcfile STREQUAL "STATIC")
endforeach(_srcfile)
if(_static_mod)
set(STATIC_MODULE_SRC ${STATIC_MODULE_SRC} ${_srcfiles})
file(APPEND ${TARGET}_builtins.h "STATIC_MOD(${MODNAME})\n")
else(_static_mod)
add_library(${MODNAME} MODULE ${_srcfiles})
set(MODULE_TARGETS ${MODULE_TARGETS} ${MODNAME})
add_target_properties(${MODNAME} LINK_FLAGS ${COMMON_LDFLAGS})
add_target_properties(${MODNAME} COMPILE_FLAGS ${COMMON_CFLAGS})
set_target_properties(${MODNAME} PROPERTIES CMAKE_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX})
## Windows likes to link it this way back to app!
if(WIN32)
set_target_properties(${MODNAME} PROPERTIES LINK_FLAGS ${TARGET}.lib)
endif(WIN32)
if(APPLE)
set_target_properties(${MODNAME} PROPERTIES LINK_FLAGS "-flat_namespace -undefined suppress")
endif(APPLE)
endif(_static_mod)
endmacro(add_module)
macro(add_target_properties _target _name)
set(_properties)
foreach(_prop ${ARGN})
set(_properties "${_properties} ${_prop}")
endforeach(_prop)
get_target_property(_old_properties ${_target} ${_name})
##message(STATUS "adding property to ${_target} ${_name}:" ${_properties})
if(NOT _old_properties)
# in case it's NOTFOUND
set(_old_properties)
endif(NOT _old_properties)
set_target_properties(${_target} PROPERTIES ${_name} "${_old_properties} ${_properties}")
endmacro(add_target_properties)

@ -1,39 +1,19 @@
#
# Lua Native Objects
#
find_program(LUA_NATIVE_OBJECTS_EXECUTABLE native_objects.lua
PATHS ${CMAKE_SOURCE_DIR}/../LuaNativeObjects
DOC "LuaNativeObjects executable path")
set(USE_PRE_GENERATED_BINDINGS TRUE CACHE BOOL
"Set this to FALSE to re-generate bindings using LuaNativeObjects")
set(GENERATE_LUADOCS TRUE CACHE BOOL
"Set this to FALSE to avoid generation of docs using LuaDoc")
macro(GenLuaNativeObjects _src_files_var)
set(_new_src_files)
foreach(_src_file ${${_src_files_var}})
if(_src_file MATCHES ".nobj.lua")
string(REGEX REPLACE ".nobj.lua" ".nobj.c" _src_file_out ${_src_file})
string(REGEX REPLACE ".nobj.lua" ".nobj.ffi.lua" _ffi_file_out ${_src_file})
add_custom_command(OUTPUT ${_src_file_out} ${_ffi_file_out}
COMMAND ${LUA_NATIVE_OBJECTS_EXECUTABLE} -outpath ${CMAKE_CURRENT_BINARY_DIR} -gen lua ${_src_file}
string(REGEX REPLACE ".nobj.lua" ".nobj.h" _header_file_out ${_src_file})
add_custom_command(OUTPUT ${_src_file_out} ${_header_file_out}
COMMAND lua ${LUA_NATIVE_OBJECTS_PATH}/native_objects.lua -outpath ${CMAKE_CURRENT_BINARY_DIR} -gen lua ${_src_file}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
DEPENDS ${_src_file}
)
set_source_files_properties(${_src_file_out} PROPERTIES GENERATED TRUE)
set_source_files_properties(${_ffi_file_out} PROPERTIES GENERATED TRUE)
if (${GENERATE_LUADOCS})
string(REGEX REPLACE ".nobj.lua" "" _doc_base ${_src_file})
string(REGEX REPLACE ".nobj.lua" ".luadoc" _doc_file_out ${_src_file})
add_custom_target(${_doc_file_out} ALL
COMMAND ${LUA_NATIVE_OBJECTS_EXECUTABLE} -outpath docs -gen luadoc ${_src_file}
COMMAND luadoc -nofiles -d docs docs
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
DEPENDS ${_src_file}
)
endif()
set_source_files_properties(${_doc_file_out} PROPERTIES GENERATED TRUE)
set_source_files_properties(${_header_file_out} PROPERTIES GENERATED TRUE)
set(_new_src_files ${_new_src_files} ${_src_file_out})
else(_src_file MATCHES ".nobj.lua")
set(_new_src_files ${_new_src_files} ${_src_file})

@ -18,24 +18,15 @@
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-- THE SOFTWARE.
local zmq = require"zmq"
require("zmq")
local N=tonumber(arg[1] or 100)
local ctx = zmq.init()
local ctx = zmq.init(1)
local s = ctx:socket(zmq.REQ)
s:connect("tcp://localhost:5555")
for i=1,N do
s:send("SELECT * FROM mytable")
local data, err = s:recv()
if data then
print(data)
else
print("s:recv() error:", err)
end
end
print(s:recv())
s:close()
ctx:term()

@ -18,26 +18,17 @@
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-- THE SOFTWARE.
local zmq = require"zmq"
require("zmq")
local N=tonumber(arg[1] or 100)
local ctx = zmq.init()
local ctx = zmq.init(1)
local s = ctx:socket(zmq.REQ)
s:connect("tcp://localhost:5555")
for i=1,N do
s:send("SELECT * FROM mytable ", zmq.SNDMORE)
s:send("WHERE library = 'zmq'")
local data, err = s:recv()
if data then
print(data)
else
print("s:recv() error:", err)
end
end
print(s:recv())
s:close()
ctx:term()

@ -1,108 +0,0 @@
-- Copyright (c) 2012 Robert G. Jakabosky <bobby@sharedrealm.com>
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-- THE SOFTWARE.
local poller = require"examples.poller"
local poll = poller.new()
local zmq = require"zmq"
local z_NOBLOCK = zmq.NOBLOCK
local z_EVENTS = zmq.EVENTS
local z_POLLIN = zmq.POLLIN
local z_POLLOUT = zmq.POLLOUT
local z_POLLIN_OUT = z_POLLIN + z_POLLOUT
local N=tonumber(arg[1] or 100)
local ctx = zmq.init()
local s = ctx:socket(zmq.REQ)
local s_FD = s:getopt(zmq.FD)
s:connect("tcp://localhost:5555")
-- current socket state
local blocked_state
local blocked_event
local on_sock_recv
local on_sock_send
-- IO event callback when socket was blocked
local function on_sock_io()
local events = s:getopt(z_EVENTS)
local unblocked = false
if events == blocked_event then
-- got the event the socket was blocked on.
unblocked = true
elseif events == z_POLLIN_OUT then
-- got both in & out events
unblocked = true
end
if unblocked then
-- got the event we are blocked on resume.
blocked_event = nil
blocked_state()
-- check if blocked event was processed.
if not blocked_event then
poll:remove_read(s_FD)
end
end
end
local function sock_blocked(state, event)
if not blocked_event then
-- need to register socket's fd with event loop
poll:add_read(s_FD, on_sock_io)
end
blocked_state = state
blocked_event = event
end
-- sock state functions
function on_sock_send()
N = N - 1
if N == 0 then
return poll:stop()
end
local sent, err = s:send("SELECT * FROM mytable", z_NOBLOCK)
if not sent then
assert(err == 'timeout', "Bad error on zmq socket.")
return sock_blocked(on_sock_send, z_POLLOUT)
end
-- yield back to event loop
poll:add_work(on_sock_recv)
end
function on_sock_recv()
local data, err = s:recv(z_NOBLOCK)
if not data then
assert(err == 'timeout', "Bad error on zmq socket.")
return sock_blocked(on_sock_recv, z_POLLIN)
end
print(data)
return on_sock_send()
end
-- start processing of the socket.
poll:add_work(on_sock_send)
-- start event loop
poll:start()
s:close()
ctx:term()

@ -1,4 +1,4 @@
-- Copyright (c) 2012 Robert G. Jakabosky <bobby@sharedrealm.com>
-- Copyright (c) 2010 Aleksey Yeschenko <aleksey@yeschenko.com>
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
@ -18,12 +18,7 @@
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-- THE SOFTWARE.
local zmq = require"zmq"
local z_NOBLOCK = zmq.NOBLOCK
local z_EVENTS = zmq.EVENTS
local z_POLLIN = zmq.POLLIN
local z_POLLOUT = zmq.POLLOUT
local z_POLLIN_OUT = z_POLLIN + z_POLLOUT
require("zmq")
local ev = require'ev'
local loop = ev.Loop.default
@ -56,43 +51,27 @@ local function sub_worker(loop, ctx, msg_cb)
-- need idle watcher since ZeroMQ sockets are edge-triggered instead of level-triggered
local s_io_idle
local s_io_read
local max_recvs = 10
local function s_recv(recv_cnt)
local msg, err = s:recv(z_NOBLOCK)
if err == 'timeout' then
-- need to block on read IO
return false
end
self:msg_cb(msg)
if recv_cnt > 1 then
return s_recv(recv_cnt - 1)
end
return true
end
s_io_idle = ev.Idle.new(function()
if not s_recv(max_recvs) then
local msg, err = s:recv(zmq.NOBLOCK)
if err == 'timeout' then
-- need to block on read IO
s_io_idle:stop(loop)
s_io_read:start(loop)
return
end
self:msg_cb(msg)
end)
s_io_idle:start(loop)
s_io_read = ev.IO.new(function()
local events = s:getopt(z_EVENTS)
if events == z_POLLIN or events == z_POLLIN_OUT then
if s_recv(max_recvs) then
-- read IO is not block, enable idle watcher to handle reads.
s_io_idle:start(loop)
s_io_read:stop(loop)
end
end
end, s:getopt(zmq.FD), ev.READ)
self.s_io_idle = s_io_idle
self.s_io_read = s_io_read
return self
end
local ctx = zmq.init()
local ctx = zmq.init(1)
-- message handling function.
local function handle_msg(worker, msg)

@ -1,39 +0,0 @@
local zmq = require'zmq'
local poller = require"examples.poller"
local poll_zsock = require"examples.poll_zsock"
local poll = poller.new()
poll_zsock.set_poller(poll)
local c = zmq.init(1)
local xreq = poll_zsock(c:socket(zmq.XREQ))
xreq:bind('tcp://127.0.0.1:13333')
local xrep = poll_zsock(c:socket(zmq.XREP))
xrep:bind('tcp://127.0.0.1:13334')
local max_recv = 10
local function forward_io(src,dst)
src.on_data = function()
for i=1,max_recv do
repeat
local data, err = src:recv(zmq.NOBLOCK)
if not data then
if err == 'timeout' then
return
else
error("socket recv error:" .. err)
end
end
local more = src:getopt(zmq.RCVMORE) > 0
dst:send(data,more and zmq.SNDMORE or 0)
until not more
end
end
end
forward_io(xrep,xreq)
forward_io(xreq,xrep)
poll:start()

@ -1,177 +0,0 @@
-- Copyright (c) 2012 Robert G. Jakabosky <bobby@sharedrealm.com>
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-- THE SOFTWARE.
local zmq = require"zmq"
local z_EVENTS = zmq.EVENTS
local z_POLLIN = zmq.POLLIN
local z_POLLOUT = zmq.POLLOUT
local z_POLLIN_OUT = z_POLLIN + z_POLLOUT
local poll
local meths = {}
local zsock_mt = { __index=meths }
local function zsock_check_events(self)
if not self.check_enabled then
-- enable 'on_work' callback to handle checking for socket events.
self.check_enabled = true
poll:add_work(self.on_work)
end
end
function meths:events()
zsock_check_events(self)
return self.sock:events()
end
function meths:getopt(opt)
if (opt == z_EVENTS) then
zsock_check_events(self)
end
return self.sock:getopt(opt)
end
function meths:setopt(opt,val)
return self.sock:setopt(opt,val)
end
function meths:sub(topic)
return self.sock:sub(topic)
end
function meths:unsub(topic)
return self.sock:unsub(topic)
end
function meths:identity(id)
return self.sock:identity(id)
end
function meths:bind(addr)
return self.sock:bind(addr)
end
function meths:connect(addr)
return self.sock:connect(addr)
end
function meths:close()
return self.sock:close()
end
function meths:send(msg, flags)
zsock_check_events(self)
local sent, err = self.sock:send(msg, flags)
if not sent and err == 'timeout' then
self.send_blocked = true
end
return sent, err
end
function meths:send_msg(msg, flags)
zsock_check_events(self)
local sent, err = self.sock:send_msg(msg, flags)
if not sent and err == 'timeout' then
self.send_blocked = true
end
return sent, err
end
function meths:recv(flags)
zsock_check_events(self)
local msg, err = self.sock:recv(flags)
if not msg and err == 'timeout' then
self.recv_blocked = true
end
return msg, err
end
function meths:recv_msg(msg, flags)
zsock_check_events(self)
local stat, err = self.sock:recv_msg(msg, flags)
if not stat and err == 'timeout' then
self.recv_blocked = true
end
return stat, err
end
local function nil_cb()
end
local function wrap_zsock(sock, on_data, on_drain)
local self = setmetatable({
sock = sock,
on_data = on_data or nil_cb,
on_drain = on_drain or nil_cb,
recv_blocked = false,
send_blocked = false,
check_enabled = false,
}, zsock_mt)
local function on_work()
self.check_enabled = false
local events = sock:events()
local read = false
local write = false
if events == z_POLLIN_OUT then
read = true
write = true
elseif events == z_POLLIN then
read = true
elseif events == z_POLLOUT then
write = true
else
return
end
if read then
self.recv_blocked = false
self:on_data(sock)
-- there might be more messages to read.
if not self.recv_blocked then
zsock_check_events(self)
end
end
if write and self.send_blocked then
self:on_drain(sock)
end
end
self.on_work = on_work
-- listen for read events to enable socket.
poll:add_read(sock:fd(), function()
on_work()
end)
zsock_check_events(self)
return self
end
return setmetatable({
set_poller = function(poller)
local old = poll
poll = poller
return old
end,
wrap_zsock = wrap_zsock,
}, { __call = function(tab, ...) return wrap_zsock(...) end})

@ -1,45 +0,0 @@
-- Copyright (c) 2012 Robert G. Jakabosky <bobby@sharedrealm.com>
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-- THE SOFTWARE.
-- safe require.
local require = require
local function safe_require(...)
return pcall(require, ...)
end
local mod_name = ...
local backends = {
"epoll",
"ev",
}
for i=1,#backends do
local backend = backends[i]
local name = mod_name .. '.' .. backend
local status, mod = safe_require(name)
if status then
--print("Loaded backend:", name)
return mod
end
end
error("Failed to load backend for: " .. mod_name)

@ -1,121 +0,0 @@
-- Copyright (c) 2012 Robert G. Jakabosky <bobby@sharedrealm.com>
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-- THE SOFTWARE.
local epoll = require"epoll"
local EPOLLIN = epoll.EPOLLIN
local EPOLLOUT = epoll.EPOLLOUT
local poller_meths = {}
local poller_mt = {__index = poller_meths}
local function poller_new()
local reads = {}
-- create closure for epoll io_event callback.
local function do_io_event(fd, ev)
local cb = reads[fd]
return cb(fd, ev)
end
return setmetatable({
work_cur = {},
work_last = {},
reads = reads,
io_events = 0,
do_io_event = do_io_event,
poller = epoll.new(),
}, poller_mt)
end
function poller_meths:add_work(task)
-- add task to current work queue.
self.work_cur[#self.work_cur + 1] = task
end
function poller_meths:add_read(fd, cb)
-- make sure read event hasn't been registered yet.
if not self.reads[fd] then
self.io_events = self.io_events + 1
self.reads[fd] = cb
return self.poller:add(fd, EPOLLIN, fd)
else
-- update read callback?
self.reads[fd] = cb
end
end
function poller_meths:remove_read(fd)
-- make sure there was a read event registered.
if self.reads[fd] then
self.io_events = self.io_events - 1
self.reads[fd] = nil
return self.poller:del(fd)
end
end
local function poller_do_work(self)
local tasks = #self.work_cur
-- check if there is any work
if tasks > 0 then
-- swap work queues.
local last, cur = self.work_cur, self.work_last
self.work_cur, self.work_last = cur, last
for i=1,tasks do
local task = last[i]
last[i] = nil
task()
end
-- return new work queue length.
return #cur
end
return tasks
end
function poller_meths:start()
local do_io_event = self.do_io_event
local poller = self.poller
self.is_running = true
while self.is_running do
-- run work task
local new_work = poller_do_work(self)
-- wait == 0, if there is work to do, else wait == -1
local wait = (new_work > 0) and 0 or -1
-- poll for fd events, if there are events to poll for.
--print("poller:step()", new_work, self.io_events)
if self.io_events > 0 then
assert(poller:wait_callback(do_io_event, wait))
else
-- no io events to poll, do we still have work?
if #self.work_cur == 0 then
-- nothing to do, exit event loop
self.is_running = false
return
end
end
end
end
function poller_meths:stop()
self.is_running = false
end
-- module only exports a 'new' function.
return {
new = poller_new,
}

@ -1,119 +0,0 @@
-- Copyright (c) 2012 Robert G. Jakabosky <bobby@sharedrealm.com>
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-- THE SOFTWARE.
local ev = require'ev'
local ev_READ = ev.READ
local ev_WRITE = ev.WRITE
local loop = ev.Loop.default
assert(ev.Idle,"Need version > 1.3 of lua-ev that supports Idle watchers.")
local poller_meths = {}
local poller_mt = {__index = poller_meths}
local function poller_new()
local self = {
work_cur = {},
work_last = {},
io_events = 0,
reads = {},
idle_enabled = false,
}
self.idle = ev.Idle.new(function()
local tasks = #self.work_cur
-- check if there is any work
if tasks > 0 then
-- swap work queues.
local last, cur = self.work_cur, self.work_last
self.work_cur, self.work_last = cur, last
for i=1,tasks do
local task = last[i]
last[i] = nil
task()
end
-- check if there is more work.
if #cur > 0 then
return -- don't disable idle watcher, when we have work.
end
end
--print("STOP IDLE:", #self.work_cur, #self.work_last)
-- stop idle watcher, no work.
self.idle_enabled = false
self.idle:stop(loop)
end)
-- set priority to max, to make sure the work queue is processed on each loop.
self.idle:priority(ev.MAXPRI)
return setmetatable(self, poller_mt)
end
function poller_meths:add_work(task)
local idx = #self.work_cur + 1
-- add task to current work queue.
self.work_cur[idx] = task
-- make sure the idle watcher is enabled.
if not self.idle_enabled then
self.idle_enabled = true
self.idle:start(loop)
end
end
function poller_meths:add_read(fd, cb)
local io_read = self.reads[fd]
-- make sure read event hasn't been registered yet.
if not io_read then
self.io_events = self.io_events + 1
io_read = ev.IO.new(function()
cb(fd)
end, fd, ev_READ)
self.reads[fd] = io_read
io_read:start(loop)
else
-- update read callback?
io_read:callback(cb)
-- need to re-start watcher?
if not io_read:is_active() then
io_read:start(loop)
end
end
end
function poller_meths:remove_read(fd)
local io_read = self.reads[fd]
-- make sure there was a read event registered.
if io_read then
self.io_events = self.io_events - 1
io_read:stop(loop)
end
end
function poller_meths:start()
return loop:loop()
end
function poller_meths:stop()
return loop:unloop()
end
-- module only exports a 'new' function.
return {
new = poller_new,
}

@ -18,9 +18,9 @@
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-- THE SOFTWARE.
local zmq = require"zmq"
require("zmq")
local ctx = zmq.init()
local ctx = zmq.init(1)
local s = ctx:socket(zmq.PUB)
s:bind("tcp://lo:5555")

@ -1,95 +0,0 @@
-- Copyright (c) 2012 Robert G. Jakabosky <bobby@sharedrealm.com>
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-- THE SOFTWARE.
local poller = require"examples.poller"
local poll = poller.new()
local zmq = require"zmq"
local z_NOBLOCK = zmq.NOBLOCK
local z_EVENTS = zmq.EVENTS
local z_POLLIN = zmq.POLLIN
local z_POLLOUT = zmq.POLLOUT
local z_POLLIN_OUT = z_POLLIN + z_POLLOUT
local ctx = zmq.init()
local s = ctx:socket(zmq.PUB)
local s_FD = s:getopt(zmq.FD)
s:bind("tcp://lo:5555")
-- current socket state
local blocked_state
local blocked_event
local on_sock_recv
local on_sock_send
-- IO event callback when socket was blocked
local function on_sock_io()
local events = s:getopt(z_EVENTS)
local unblocked = false
if events == blocked_event then
-- got the event the socket was blocked on.
unblocked = true
elseif events == z_POLLIN_OUT then
-- got both in & out events
unblocked = true
end
if unblocked then
-- got the event we are blocked on resume.
blocked_event = nil
blocked_state()
-- check if blocked event was processed.
if not blocked_event then
poll:remove_read(s_FD)
end
end
end
local function sock_blocked(state, event)
if not blocked_event then
-- need to register socket's fd with event loop
poll:add_read(s_FD, on_sock_io)
end
blocked_state = state
blocked_event = event
end
-- sock state functions
local msg_id = 1
function on_sock_send()
local sent, err = s:send(tostring(msg_id), z_NOBLOCK)
if not sent then
assert(err == 'timeout', "Bad error on zmq socket.")
return sock_blocked(on_sock_send, z_POLLOUT)
end
-- message sent, inc. id
msg_id = msg_id + 1
-- yield back to event loop
poll:add_work(on_sock_send)
end
-- start processing of the socket.
poll:add_work(on_sock_send)
-- start event loop
poll:start()
s:close()
ctx:term()

@ -18,9 +18,9 @@
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-- THE SOFTWARE.
local zmq = require"zmq"
require("zmq")
local ctx = zmq.init()
local ctx = zmq.init(1)
local s = ctx:socket(zmq.REP)
s:bind("tcp://lo:5555")

@ -18,9 +18,9 @@
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-- THE SOFTWARE.
local zmq = require"zmq"
require("zmq")
local ctx = zmq.init()
local ctx = zmq.init(1)
local s = ctx:socket(zmq.REP)
s:bind("tcp://lo:5555")

@ -1,102 +0,0 @@
-- Copyright (c) 2012 Robert G. Jakabosky <bobby@sharedrealm.com>
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-- THE SOFTWARE.
local poller = require"examples.poller"
local poll = poller.new()
local zmq = require"zmq"
local z_NOBLOCK = zmq.NOBLOCK
local z_EVENTS = zmq.EVENTS
local z_POLLIN = zmq.POLLIN
local z_POLLOUT = zmq.POLLOUT
local z_POLLIN_OUT = z_POLLIN + z_POLLOUT
local ctx = zmq.init()
local s = ctx:socket(zmq.REP)
local s_FD = s:getopt(zmq.FD)
s:bind("tcp://lo:5555")
-- current socket state
local blocked_state
local blocked_event
local on_sock_recv
local on_sock_send
-- IO event callback when socket was blocked
local function on_sock_io()
local events = s:getopt(z_EVENTS)
local unblocked = false
if events == blocked_event then
-- got the event the socket was blocked on.
unblocked = true
elseif events == z_POLLIN_OUT then
-- got both in & out events
unblocked = true
end
if unblocked then
-- got the event we are blocked on resume.
blocked_event = nil
blocked_state()
-- check if blocked event was processed.
if not blocked_event then
poll:remove_read(s_FD)
end
end
end
local function sock_blocked(state, event)
if not blocked_event then
-- need to register socket's fd with event loop
poll:add_read(s_FD, on_sock_io)
end
blocked_state = state
blocked_event = event
end
-- sock state functions
function on_sock_recv()
local data, err = s:recv(z_NOBLOCK)
if not data then
assert(err == 'timeout', "Bad error on zmq socket.")
return sock_blocked(on_sock_recv, z_POLLIN)
end
print(string.format("Received query: '%s'", data))
return on_sock_send()
end
function on_sock_send()
local sent, err = s:send("OK", z_NOBLOCK)
if not sent then
assert(err == 'timeout', "Bad error on zmq socket.")
return sock_blocked(on_sock_send, z_POLLOUT)
end
-- yield back to event loop
poll:add_work(on_sock_recv)
end
-- start processing of the socket.
poll:add_work(on_sock_recv)
-- start event loop
poll:start()
s:close()
ctx:term()

@ -18,9 +18,9 @@
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-- THE SOFTWARE.
local zmq = require"zmq"
require("zmq")
local ctx = zmq.init()
local ctx = zmq.init(1)
local s = ctx:socket(zmq.SUB)
s:setopt(zmq.SUBSCRIBE, "")
s:connect("tcp://localhost:5555")

@ -1,96 +0,0 @@
-- Copyright (c) 2012 Robert G. Jakabosky <bobby@sharedrealm.com>
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-- THE SOFTWARE.
local poller = require"examples.poller"
local poll = poller.new()
local zmq = require"zmq"
local z_NOBLOCK = zmq.NOBLOCK
local z_EVENTS = zmq.EVENTS
local z_POLLIN = zmq.POLLIN
local z_POLLOUT = zmq.POLLOUT
local z_POLLIN_OUT = z_POLLIN + z_POLLOUT
local N=tonumber(arg[1] or 100)
local ctx = zmq.init()
local s = ctx:socket(zmq.SUB)
local s_FD = s:getopt(zmq.FD)
s:setopt(zmq.SUBSCRIBE, "")
s:connect("tcp://localhost:5555")
-- current socket state
local blocked_state
local blocked_event
local on_sock_recv
local on_sock_send
-- IO event callback when socket was blocked
local function on_sock_io()
local events = s:getopt(z_EVENTS)
local unblocked = false
if events == blocked_event then
-- got the event the socket was blocked on.
unblocked = true
elseif events == z_POLLIN_OUT then
-- got both in & out events
unblocked = true
end
if unblocked then
-- got the event we are blocked on resume.
blocked_event = nil
blocked_state()
-- check if blocked event was processed.
if not blocked_event then
poll:remove_read(s_FD)
end
end
end
local function sock_blocked(state, event)
if not blocked_event then
-- need to register socket's fd with event loop
poll:add_read(s_FD, on_sock_io)
end
blocked_state = state
blocked_event = event
end
-- sock state functions
function on_sock_recv()
local data, err = s:recv(z_NOBLOCK)
if not data then
assert(err == 'timeout', "Bad error on zmq socket.")
return sock_blocked(on_sock_recv, z_POLLIN)
end
local msg_id = tonumber(data)
if (msg_id % 10000) == 0 then print(data) end
return on_sock_recv()
end
-- start processing of the socket.
poll:add_work(on_sock_recv)
-- start event loop
poll:start()
s:close()
ctx:term()

@ -19,42 +19,32 @@
-- THE SOFTWARE.
if not arg[3] then
print("usage: lua local_lat.lua <bind-to> <message-size> <roundtrip-count>")
print("usage: lua local_lat.lua <bind-to> <message-size> <roundtrip-count> [<zmq-module>]")
os.exit()
end
local bind_to = arg[1]
local message_size = tonumber(arg[2])
local roundtrip_count = tonumber(arg[3])
local mod = arg[4] or "zmq"
if mod == 'disable_ffi' then
disable_ffi = true
mod = 'zmq'
end
local zmq = require"zmq"
local zmq = require(mod)
local ctx = zmq.init(1)
local s = assert(ctx:socket(zmq.REP))
assert(s:bind(bind_to))
local msg = zmq.zmq_msg_t()
local s = ctx:socket(zmq.REP)
s:bind(bind_to)
local timer
local msg
for i = 1, roundtrip_count do
assert(s:recv_msg(msg))
if not timer then
timer = zmq.stopwatch_start()
msg = s:recv()
assert(#msg == message_size, "Invalid message size")
s:send(msg)
end
assert(msg:size() == message_size, "Invalid message size")
assert(s:send_msg(msg))
end
local elapsed = timer:stop()
s:close()
ctx:term()
local latency = elapsed / roundtrip_count / 2
print(string.format("mean latency: %.3f [us]", latency))
local secs = elapsed / (1000 * 1000)
print(string.format("elapsed = %f", secs))
print(string.format("msg/sec = %f", roundtrip_count / secs))

@ -1,69 +0,0 @@
-- Copyright (c) 2010 Aleksey Yeschenko <aleksey@yeschenko.com>
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-- THE SOFTWARE.
if not arg[3] then
print("usage: lua local_thr.lua <bind-to> <message-size> <message-count>")
os.exit()
end
local bind_to = arg[1]
local message_size = tonumber(arg[2])
local message_count = tonumber(arg[3])
local zmq = require"zmq"
local ctx = zmq.init(1)
local s = assert(ctx:socket(zmq.PULL))
--s:setopt(zmq.SUBSCRIBE, "");
assert(s:bind(bind_to))
local function recv_msg(s,msg)
assert(s:recv_msg(msg))
assert(msg:size() == message_size/2, "Invalid message size")
assert(s:getopt(zmq.RCVMORE) == 1, "Message not multipart")
assert(s:recv_msg(msg))
assert(msg:size() == message_size/2, "Invalid message size")
assert(s:getopt(zmq.RCVMORE) == 0, "Message has too many parts")
end
local msg
msg = zmq.zmq_msg_t()
recv_msg(s, msg)
local timer = zmq.stopwatch_start()
for i = 1, message_count - 1 do
recv_msg(s, msg)
end
local elapsed = timer:stop()
s:close()
ctx:term()
if elapsed == 0 then elapsed = 1 end
local throughput = message_count / (elapsed / 1000000)
local megabits = throughput * message_size * 8 / 1000000
print(string.format("message size: %i [B]", message_size))
print(string.format("message count: %i", message_count))
print(string.format("mean throughput: %i [msg/s]", throughput))
print(string.format("mean throughput: %.3f [Mb/s]", megabits))

@ -1,62 +0,0 @@
-- Copyright (c) 2011 Robert G. Jakabosky <bobby@sharedrealm.com>
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-- THE SOFTWARE.
if not arg[3] then
print("usage: lua local_thr.lua <bind-to> <message-size> <message-count>")
os.exit()
end
local bind_to = arg[1]
local message_size = tonumber(arg[2])
local message_count = tonumber(arg[3])
local zmq = require"zmq"
local ctx = zmq.init(1)
local s = assert(ctx:socket(zmq.PULL))
assert(s:bind(bind_to))
print(string.format("message size: %i [B]", message_size))
print(string.format("message count: %i", message_count))
local msg
msg = zmq.zmq_msg_t()
assert(s:recv_msg(msg))
local timer = zmq.stopwatch_start()
for i = 1, message_count - 1 do
assert(s:recv_msg(msg))
assert(msg:size() == message_size, "Invalid message size")
end
local elapsed = timer:stop()
s:close()
ctx:term()
if elapsed == 0 then elapsed = 1 end
local throughput = message_count / (elapsed / 1000000)
local megabits = throughput * message_size * 8 / 1000000
print(string.format("mean throughput: %i [msg/s]", throughput))
print(string.format("mean throughput: %.3f [Mb/s]", megabits))

@ -19,44 +19,50 @@
-- THE SOFTWARE.
if not arg[3] then
print("usage: lua local_thr.lua <bind-to> <message-size> <message-count>")
print("usage: lua local_thr.lua <bind-to> <message-size> <message-count> [<zmq-module>]")
os.exit()
end
local bind_to = arg[1]
local message_size = tonumber(arg[2])
local message_count = tonumber(arg[3])
local mod = arg[4] or "zmq"
if mod == 'disable_ffi' then
disable_ffi = true
mod = 'zmq'
end
local zmq = require"zmq"
local zmq = require(mod)
local ctx = zmq.init(1)
local s = assert(ctx:socket(zmq.PULL))
assert(s:bind(bind_to))
local socket = require"socket"
local time = socket.gettime
print(string.format("message size: %i [B]", message_size))
print(string.format("message count: %i", message_count))
local ctx = zmq.init(1)
local s = ctx:socket(zmq.SUB)
s:setopt(zmq.SUBSCRIBE, "");
s:bind(bind_to)
local msg
msg = zmq.zmq_msg_t()
assert(s:recv_msg(msg))
local msg = s:recv()
local timer = zmq.stopwatch_start()
local start_time = time()
for i = 1, message_count - 1 do
assert(s:recv_msg(msg))
assert(msg:size() == message_size, "Invalid message size")
msg = s:recv()
assert(#msg == message_size, "Invalid message size")
end
local elapsed = timer:stop()
local end_time = time()
s:close()
ctx:term()
local elapsed = end_time - start_time
if elapsed == 0 then elapsed = 1 end
local throughput = message_count / (elapsed / 1000000)
local throughput = message_count / elapsed
local megabits = throughput * message_size * 8 / 1000000
print(string.format("message size: %i [B]", message_size))
print(string.format("message count: %i", message_count))
print(string.format("mean throughput: %i [msg/s]", throughput))
print(string.format("mean throughput: %.3f [Mb/s]", megabits))

@ -1,77 +0,0 @@
-- Copyright (c) 2010 Aleksey Yeschenko <aleksey@yeschenko.com>
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-- THE SOFTWARE.
if not arg[3] then
print("usage: lua local_thr.lua <bind-to> <message-size> <message-count>")
os.exit()
end
local bind_to = arg[1]
local message_size = tonumber(arg[2])
local message_count = tonumber(arg[3])
local zmq = require"zmq"
local z_poller = require"zmq.poller"
local z_NOBLOCK = zmq.NOBLOCK
local poller = z_poller(64)
local ctx = zmq.init(1)
local s = assert(ctx:socket(zmq.SUB))
assert(s:setopt(zmq.SUBSCRIBE, ""))
assert(s:bind(bind_to))
print(string.format("message size: %i [B]", message_size))
print(string.format("message count: %i", message_count))
local msg
msg = zmq.zmq_msg_t()
local cnt = 0
poller:add(s, zmq.POLLIN, function(sock)
while s:recv_msg(msg, z_NOBLOCK) do
--assert(msg:size() == message_size, "Invalid message size")
cnt = cnt + 1
if cnt == message_count then
poller:stop()
end
end
end)
-- wait for first message
assert(s:recv_msg(msg))
cnt = 1
local timer = zmq.stopwatch_start()
poller:start()
local elapsed = timer:stop()
s:close()
ctx:term()
if elapsed == 0 then elapsed = 1 end
local throughput = message_count / (elapsed / 1000000)
local megabits = throughput * message_size * 8 / 1000000
print(string.format("mean throughput: %i [msg/s]", throughput))
print(string.format("mean throughput: %.3f [Mb/s]", megabits))

@ -1,45 +0,0 @@
-- Copyright (c) 2010 Aleksey Yeschenko <aleksey@yeschenko.com>
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-- THE SOFTWARE.
if not arg[3] then
print("usage: lua local_lat.lua <bind-to> <message-size> <roundtrip-count>")
os.exit()
end
local bind_to = arg[1]
local message_size = tonumber(arg[2])
local roundtrip_count = tonumber(arg[3])
local zmq = require'zmq'
local ctx = zmq.init(1)
local s = ctx:socket(zmq.REP)
s:bind(bind_to)
local msg
for i = 1, roundtrip_count do
msg = s:recv()
assert(#msg == message_size, "Invalid message size")
s:send(msg)
end
s:close()
ctx:term()

@ -1,60 +0,0 @@
-- Copyright (c) 2010 Aleksey Yeschenko <aleksey@yeschenko.com>
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-- THE SOFTWARE.
if not arg[3] then
print("usage: lua local_thr.lua <bind-to> <message-size> <message-count>")
os.exit()
end
local bind_to = arg[1]
local message_size = tonumber(arg[2])
local message_count = tonumber(arg[3])
local zmq = require'zmq'
local ctx = zmq.init(1)
local s = ctx:socket(zmq.SUB)
s:setopt(zmq.SUBSCRIBE, "");
s:bind(bind_to)
local msg
msg = s:recv()
local timer = zmq.stopwatch_start()
for i = 1, message_count - 1 do
msg = s:recv()
assert(#msg == message_size, "Invalid message size")
end
local elapsed = timer:stop()
s:close()
ctx:term()
if elapsed == 0 then elapsed = 1 end
local throughput = message_count / (elapsed / 1000000)
local megabits = throughput * message_size * 8 / 1000000
print(string.format("message size: %i [B]", message_size))
print(string.format("message count: %i", message_count))
print(string.format("mean throughput: %i [msg/s]", throughput))
print(string.format("mean throughput: %.3f [Mb/s]", megabits))

@ -1,55 +0,0 @@
-- Copyright (c) 2010 Aleksey Yeschenko <aleksey@yeschenko.com>
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-- THE SOFTWARE.
if not arg[3] then
print("usage: lua remote_lat.lua <connect-to> <message-size> <roundtrip-count>")
os.exit()
end
local connect_to = arg[1]
local message_size = tonumber(arg[2])
local roundtrip_count = tonumber(arg[3])
local zmq = require'zmq'
local ctx = zmq.init(1)
local s = ctx:socket(zmq.REQ)
s:connect(connect_to)
local msg = ("0"):rep(message_size)
local timer = zmq.stopwatch_start()
for i = 1, roundtrip_count do
s:send(msg)
msg = s:recv()
assert(#msg == message_size, "Invalid message size")
end
local elapsed = timer:stop()
s:close()
ctx:term()
local latency = elapsed / roundtrip_count / 2
print(string.format("message size: %i [B]", message_size))
print(string.format("roundtrip count: %i", roundtrip_count))
print(string.format("mean latency: %.3f [us]", latency))

@ -1,45 +0,0 @@
-- Copyright (c) 2010 Aleksey Yeschenko <aleksey@yeschenko.com>
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-- THE SOFTWARE.
if not arg[3] then
print("usage: lua remote_thr.lua <connect-to> <message-size> <message-count>")
os.exit()
end
local connect_to = arg[1]
local message_size = tonumber(arg[2])
local message_count = tonumber(arg[3])
local zmq = require'zmq'
local ctx = zmq.init(1)
local s = ctx:socket(zmq.PUB)
s:connect(connect_to)
local msg = ("0"):rep(message_size)
for i = 1, message_count do
s:send(msg)
end
--os.execute("sleep " .. 10)
s:close()
ctx:term()

@ -19,42 +19,47 @@
-- THE SOFTWARE.
if not arg[3] then
print("usage: lua remote_lat.lua <connect-to> <message-size> <roundtrip-count>")
print("usage: lua remote_lat.lua <connect-to> <message-size> <roundtrip-count> [<zmq-module>]")
os.exit()
end
local connect_to = arg[1]
local message_size = tonumber(arg[2])
local roundtrip_count = tonumber(arg[3])
local mod = arg[4] or "zmq"
if mod == 'disable_ffi' then
disable_ffi = true
mod = 'zmq'
end
local zmq = require(mod)
local zmq = require"zmq"
local socket = require"socket"
local time = socket.gettime
local ctx = zmq.init(1)
local s = assert(ctx:socket(zmq.REQ))
assert(s:connect(connect_to))
local s = ctx:socket(zmq.REQ)
s:connect(connect_to)
local data = ("0"):rep(message_size)
local msg = zmq.zmq_msg_t.init_size(message_size)
local msg = ""
for i = 1, message_size do msg = msg .. "0" end
local timer = zmq.stopwatch_start()
local start_time = time()
for i = 1, roundtrip_count do
assert(s:send_msg(msg))
assert(s:recv_msg(msg))
assert(msg:size() == message_size, "Invalid message size")
s:send(msg)
msg = s:recv()
assert(#msg == message_size, "Invalid message size")
end
local elapsed = timer:stop()
local end_time = time()
s:close()
ctx:term()
local latency = elapsed / roundtrip_count / 2
local elapsed = end_time - start_time
local latency = elapsed * 1000000 / roundtrip_count / 2
print(string.format("message size: %i [B]", message_size))
print(string.format("roundtrip count: %i", roundtrip_count))
print(string.format("mean latency: %.3f [us]", latency))
local secs = elapsed / (1000 * 1000)
print(string.format("Elapsed: %f secs", secs))
print(string.format("throughput %f msg/secs", roundtrip_count / secs))

@ -1,50 +0,0 @@
-- Copyright (c) 2010 Aleksey Yeschenko <aleksey@yeschenko.com>
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-- THE SOFTWARE.
if not arg[3] then
print("usage: lua remote_thr.lua <connect-to> <message-size> <message-count>")
os.exit()
end
local connect_to = arg[1]
local message_size = tonumber(arg[2])
local message_count = tonumber(arg[3])
local zmq = require"zmq"
local z_SNDMORE = zmq.SNDMORE
local ctx = zmq.init(1)
local s = assert(ctx:socket(zmq.PUSH))
assert(s:connect(connect_to))
local data = ("0"):rep(message_size/2)
local msg = zmq.zmq_msg_t.init_size(message_size/2)
for i = 1, message_count do
msg:set_data(data)
assert(s:send_msg(msg, z_SNDMORE))
msg:set_data(data)
assert(s:send_msg(msg))
end
os.execute("sleep " .. 1)
s:close()
ctx:term()

@ -1,47 +0,0 @@
-- Copyright (c) 2010 Aleksey Yeschenko <aleksey@yeschenko.com>
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-- THE SOFTWARE.
if not arg[3] then
print("usage: lua remote_thr.lua <connect-to> <message-size> <message-count>")
os.exit()
end
local connect_to = arg[1]
local message_size = tonumber(arg[2])
local message_count = tonumber(arg[3])
local zmq = require"zmq"
local ctx = zmq.init(1)
local s = assert(ctx:socket(zmq.PUSH))
assert(s:connect(connect_to))
local data = ("0"):rep(message_size)
local msg = zmq.zmq_msg_t.init_size(message_size)
for i = 1, message_count do
msg:set_data(data)
assert(s:send_msg(msg))
end
--os.execute("sleep " .. 10)
s:close()
ctx:term()

@ -19,31 +19,33 @@
-- THE SOFTWARE.
if not arg[3] then
print("usage: lua remote_thr.lua <connect-to> <message-size> <message-count>")
print("usage: lua remote_thr.lua <connect-to> <message-size> <message-count> [<zmq-module>]")
os.exit()
end
local connect_to = arg[1]
local message_size = tonumber(arg[2])
local message_count = tonumber(arg[3])
local mod = arg[4] or "zmq"
if mod == 'disable_ffi' then
disable_ffi = true
mod = 'zmq'
end
local zmq = require"zmq"
local zmq = require(mod)
local ctx = zmq.init(1)
local s = assert(ctx:socket(zmq.PUSH))
assert(s:connect(connect_to))
zmq.sleep(1)
local s = ctx:socket(zmq.PUB)
s:connect(connect_to)
local data = ("0"):rep(message_size)
local msg_data = zmq.zmq_msg_t.init_data(data)
local msg = zmq.zmq_msg_t.init()
local msg = ""
for i = 1, message_size do msg = msg .. "0" end
for i = 1, message_count do
msg:copy(msg_data)
assert(s:send_msg(msg))
s:send(msg)
end
--os.execute("sleep " .. 10)
s:close()
ctx:term()

@ -1,89 +0,0 @@
-- Copyright (c) 2011 Robert G. Jakabosky <bobby@sharedrealm.com>
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-- THE SOFTWARE.
if #arg < 1 then
print("usage: lua " .. arg[0] .. " [message-size] [roundtrip-count] [bind-to] [connect-to]")
end
local message_size = tonumber(arg[1] or 1)
local roundtrip_count = tonumber(arg[2] or 100000)
local bind_to = arg[3] or 'inproc://thread_lat_test'
local connect_to = arg[4] or 'inproc://thread_lat_test'
local zmq = require"zmq"
local zthreads = require"zmq.threads"
local child_code = [[
local connect_to, message_size, roundtrip_count = ...
local zmq = require"zmq"
local zthreads = require"zmq.threads"
local ctx = zthreads.get_parent_ctx()
local s = ctx:socket(zmq.REP)
s:connect(connect_to)
local msg = zmq.zmq_msg_t()
for i = 1, roundtrip_count do
assert(s:recv_msg(msg))
assert(msg:size() == message_size, "Invalid message size")
assert(s:send_msg(msg))
end
s:close()
]]
local ctx = zmq.init(1)
local s = assert(ctx:socket(zmq.REQ))
assert(s:bind(bind_to))
local child_thread = zthreads.runstring(ctx, child_code, connect_to, message_size, roundtrip_count)
child_thread:start()
local data = ("0"):rep(message_size)
local msg = zmq.zmq_msg_t.init_size(message_size)
print(string.format("message size: %i [B]", message_size))
print(string.format("roundtrip count: %i", roundtrip_count))
zmq.sleep(2) -- wait for child thread to connect.
local timer = zmq.stopwatch_start()
for i = 1, roundtrip_count do
assert(s:send_msg(msg))
assert(s:recv_msg(msg))
assert(msg:size() == message_size, "Invalid message size")
end
local elapsed = timer:stop()
s:close()
child_thread:join()
ctx:term()
local latency = elapsed / roundtrip_count / 2
print(string.format("mean latency: %.3f [us]", latency))
local secs = elapsed / (1000 * 1000)
print(string.format("elapsed = %f", secs))
print(string.format("msg/sec = %f", roundtrip_count / secs))

@ -1,104 +0,0 @@
-- Copyright (c) 2011 Robert G. Jakabosky <bobby@sharedrealm.com>
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-- THE SOFTWARE.
if #arg < 1 then
print("usage: lua " .. arg[0] .. " [message-size] [message-count] [bind-to] [connect-to]")
end
local message_size = tonumber(arg[1] or 1)
local message_count = tonumber(arg[2] or 100000)
local bind_to = arg[3] or 'inproc://thread_lat_test'
local connect_to = arg[4] or 'inproc://thread_lat_test'
local zmq = require"zmq"
local zthreads = require"zmq.threads"
local child_code = [[
local connect_to, message_size, message_count = ...
local zmq = require"zmq"
local zthreads = require"zmq.threads"
local ctx = zthreads.get_parent_ctx()
local s = assert(ctx:socket(zmq.PUSH))
assert(s:setopt(zmq.HWM, message_count/4))
assert(s:connect(connect_to))
local data = ("0"):rep(message_size)
local msg_data = zmq.zmq_msg_t.init_data(data)
local msg = zmq.zmq_msg_t.init()
local timer = zmq.stopwatch_start()
for i = 1, message_count do
msg:copy(msg_data)
assert(s:send_msg(msg))
end
local elapsed = timer:stop()
s:close()
if elapsed == 0 then elapsed = 1 end
local throughput = message_count / (elapsed / 1000000)
local megabits = throughput * message_size * 8 / 1000000
print(string.format("Sender mean throughput: %i [msg/s]", throughput))
print(string.format("Sender mean throughput: %.3f [Mb/s]", megabits))
print("sending thread finished.")
]]
local ctx = zmq.init(1)
local s = assert(ctx:socket(zmq.PULL))
assert(s:bind(bind_to))
print(string.format("message size: %i [B]", message_size))
print(string.format("message count: %i", message_count))
local child_thread = zthreads.runstring(ctx, child_code, connect_to, message_size, message_count)
child_thread:start()
local msg
msg = zmq.zmq_msg_t()
assert(s:recv_msg(msg))
local timer = zmq.stopwatch_start()
for i = 1, message_count - 1 do
assert(s:recv_msg(msg))
assert(msg:size() == message_size, "Invalid message size")
end
local elapsed = timer:stop()
s:close()
child_thread:join()
ctx:term()
if elapsed == 0 then elapsed = 1 end
local throughput = message_count / (elapsed / 1000000)
local megabits = throughput * message_size * 8 / 1000000
print(string.format("mean throughput: %i [msg/s]", throughput))
print(string.format("mean throughput: %.3f [Mb/s]", megabits))

@ -1,103 +0,0 @@
-- Copyright (c) 2011 Robert G. Jakabosky <bobby@sharedrealm.com>
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-- THE SOFTWARE.
if #arg < 1 then
print("usage: lua " .. arg[0] .. " [message-size] [message-count] [bind-to] [connect-to]")
end
local message_size = tonumber(arg[1] or 1)
local message_count = tonumber(arg[2] or 100000)
local bind_to = arg[3] or 'inproc://thread_thr_test'
local connect_to = arg[4] or 'inproc://thread_thr_test'
local zmq = require"zmq"
local zthreads = require"zmq.threads"
local child_code = [[
local connect_to, message_size, message_count = ...
local zmq = require"zmq"
local zthreads = require"zmq.threads"
local ctx = zthreads.get_parent_ctx()
local s = assert(ctx:socket(zmq.PUSH))
assert(s:connect(connect_to))
local data = ("0"):rep(message_size)
local msg_data = zmq.zmq_msg_t.init_data(data)
local msg = zmq.zmq_msg_t.init()
local timer = zmq.stopwatch_start()
for i = 1, message_count do
msg:copy(msg_data)
assert(s:send_msg(msg))
end
local elapsed = timer:stop()
s:close()
if elapsed == 0 then elapsed = 1 end
local throughput = message_count / (elapsed / 1000000)
local megabits = throughput * message_size * 8 / 1000000
print(string.format("Sender mean throughput: %i [msg/s]", throughput))
print(string.format("Sender mean throughput: %.3f [Mb/s]", megabits))
print("sending thread finished.")
]]
local ctx = zmq.init(1)
local s = assert(ctx:socket(zmq.PULL))
assert(s:bind(bind_to))
print(string.format("message size: %i [B]", message_size))
print(string.format("message count: %i", message_count))
local child_thread = zthreads.runstring(ctx, child_code, connect_to, message_size, message_count)
child_thread:start()
local msg
msg = zmq.zmq_msg_t()
assert(s:recv_msg(msg))
local timer = zmq.stopwatch_start()
for i = 1, message_count - 1 do
assert(s:recv_msg(msg))
assert(msg:size() == message_size, "Invalid message size")
end
local elapsed = timer:stop()
s:close()
child_thread:join()
ctx:term()
if elapsed == 0 then elapsed = 1 end
local throughput = message_count / (elapsed / 1000000)
local megabits = throughput * message_size * 8 / 1000000
print(string.format("mean throughput: %i [msg/s]", throughput))
print(string.format("mean throughput: %.3f [Mb/s]", megabits))

@ -1,36 +0,0 @@
package = "lua-zmq"
version = "1.0-1"
source = {
url = "git://github.com/Neopallium/lua-zmq.git",
branch = "v1.0",
}
description = {
summary = "Lua bindings to zeromq2, with LuaJIT2 FFI support.",
homepage = "http://github.com/Neopallium/lua-zmq",
license = "MIT/X11",
}
dependencies = {
"lua >= 5.1",
}
external_dependencies = {
ZEROMQ = {
header = "zmq.h",
library = "zmq",
}
}
build = {
type = "builtin",
modules = {
zmq = {
sources = {"src/pre_generated-zmq.nobj.c"},
incdirs = "$(ZEROMQ_INCDIR)",
libdirs = "$(ZEROMQ_LIBDIR)",
libraries = {"zmq"},
},
},
install = {
lua = {
['zmq.poller'] = "src/poller.lua",
}
}
}

@ -1,36 +0,0 @@
package = "lua-zmq"
version = "1.1-1"
source = {
url = "git://github.com/Neopallium/lua-zmq.git",
branch = "v1.1",
}
description = {
summary = "Lua bindings to zeromq2, with LuaJIT2 FFI support.",
homepage = "http://github.com/Neopallium/lua-zmq",
license = "MIT/X11",
}
dependencies = {
"lua >= 5.1",
}
external_dependencies = {
ZEROMQ = {
header = "zmq.h",
library = "zmq",
}
}
build = {
type = "builtin",
modules = {
zmq = {
sources = {"src/pre_generated-zmq.nobj.c"},
incdirs = "$(ZEROMQ_INCDIR)",
libdirs = "$(ZEROMQ_LIBDIR)",
libraries = {"zmq"},
},
},
install = {
lua = {
['zmq.poller'] = "src/poller.lua",
}
}
}

@ -1,36 +0,0 @@
package = "lua-zmq"
version = "1.2-1"
source = {
url = "git://github.com/Neopallium/lua-zmq.git",
branch = "v1.2",
}
description = {
summary = "Lua bindings to zeromq2, with LuaJIT2 FFI support.",
homepage = "http://github.com/Neopallium/lua-zmq",
license = "MIT/X11",
}
dependencies = {
"lua >= 5.1, < 5.5",
}
external_dependencies = {
ZEROMQ = {
header = "zmq.h",
library = "zmq",
}
}
build = {
type = "builtin",
modules = {
zmq = {
sources = {"src/pre_generated-zmq.nobj.c"},
incdirs = "$(ZEROMQ_INCDIR)",
libdirs = "$(ZEROMQ_LIBDIR)",
libraries = {"zmq"},
},
},
install = {
lua = {
['zmq.poller'] = "src/poller.lua",
}
}
}

@ -1,51 +1,22 @@
package = "lua-zmq"
version = "scm-1"
source = {
url = "git+https://brejela.club/gitea/brejela/lua-zmq.git",
url = "git://github.com/Neopallium/lua-zmq.git"
}
description = {
summary = "Lua bindings to zeromq2, with LuaJIT2 FFI support.",
homepage = "http://github.com/Neopallium/lua-zmq",
license = "MIT/X11",
license = "MIT/X11"
}
dependencies = {
"lua >= 5.1, < 5.5",
}
external_dependencies = {
platforms = {
windows = {
ZEROMQ = {
library = "libzmq",
}
},
},
ZEROMQ = {
header = "zmq.h",
library = "zmq",
}
"lua >= 5.1"
}
build = {
platforms = {
windows = {
modules = {
zmq = {
libraries = {"libzmq"},
}
}
},
},
type = "builtin",
modules = {
zmq = {
sources = {"src/pre_generated-zmq.nobj.c"},
incdirs = "$(ZEROMQ_INCDIR)",
libdirs = "$(ZEROMQ_LIBDIR)",
libraries = {"zmq"},
},
},
install = {
lua = {
['zmq.poller'] = "src/poller.lua",
},
},
libraries = {"zmq"}
}
}
}

@ -1,51 +0,0 @@
package = "lua-zmq"
version = "scm-2"
source = {
url = "git://github.com/Neopallium/lua-zmq.git",
}
description = {
summary = "Lua bindings to zeromq2, with LuaJIT2 FFI support.",
homepage = "http://github.com/Neopallium/lua-zmq",
license = "MIT/X11",
}
dependencies = {
"lua >= 5.1, < 5.5",
}
external_dependencies = {
platforms = {
windows = {
ZEROMQ = {
library = "libzmq",
}
},
},
ZEROMQ = {
header = "zmq.h",
library = "zmq",
}
}
build = {
platforms = {
windows = {
modules = {
zmq = {
libraries = {"libzmq"},
}
}
},
},
type = "builtin",
modules = {
zmq = {
sources = {"src/pre_generated-zmq.nobj.c"},
incdirs = "$(ZEROMQ_INCDIR)",
libdirs = "$(ZEROMQ_LIBDIR)",
libraries = {"zmq"},
},
},
install = {
lua = {
['zmq.poller'] = "src/poller.lua",
},
},
}

@ -1,23 +0,0 @@
package = "lua-zmq-threads"
version = "1.0-1"
source = {
url = "git://github.com/Neopallium/lua-zmq.git",
branch = "v1.0",
}
description = {
summary = "Lua bindings to zeromq2, with LuaJIT2 FFI support.",
homepage = "http://github.com/Neopallium/lua-zmq",
license = "MIT/X11"
}
dependencies = {
"lua-zmq",
"lua-llthreads",
}
build = {
type = "none",
install = {
lua = {
['zmq.threads'] = "src/threads.lua",
}
}
}

@ -1,23 +0,0 @@
package = "lua-zmq-threads"
version = "1.1-1"
source = {
url = "git://github.com/Neopallium/lua-zmq.git",
branch = "v1.1",
}
description = {
summary = "Lua bindings to zeromq2, with LuaJIT2 FFI support.",
homepage = "http://github.com/Neopallium/lua-zmq",
license = "MIT/X11"
}
dependencies = {
"lua-zmq >= 1.1-1",
"lua-llthreads >= 1.1-1",
}
build = {
type = "none",
install = {
lua = {
['zmq.threads'] = "src/threads.lua",
}
}
}

@ -1,23 +0,0 @@
package = "lua-zmq-threads"
version = "1.2-1"
source = {
url = "git://github.com/Neopallium/lua-zmq.git",
branch = "v1.2",
}
description = {
summary = "Lua bindings to zeromq2, with LuaJIT2 FFI support.",
homepage = "http://github.com/Neopallium/lua-zmq",
license = "MIT/X11"
}
dependencies = {
"lua-zmq >= 1.2-1",
"lua-llthreads >= 1.3-1",
}
build = {
type = "none",
install = {
lua = {
['zmq.threads'] = "src/threads.lua",
}
}
}

@ -1,22 +0,0 @@
package = "lua-zmq-threads"
version = "scm-0"
source = {
url = "git+https://brejela.club/gitea/brejela/lua-zmq.git",
}
description = {
summary = "Lua bindings to zeromq2, with LuaJIT2 FFI support.",
homepage = "http://github.com/Neopallium/lua-zmq",
license = "MIT/X11",
}
dependencies = {
"lua-zmq = scm-1",
"lua-llthreads = scm-0",
}
build = {
type = "none",
install = {
lua = {
['zmq.threads'] = "src/threads.lua",
},
},
}

@ -1,22 +0,0 @@
package = "lua-zmq-wireshark"
version = "scm-0"
source = {
url = "git://github.com/Neopallium/lua-zmq.git",
}
description = {
summary = "Lua Wireshark dissector for the ZeroMQ protocol.",
homepage = "http://github.com/Neopallium/lua-zmq",
-- Wireshark requires dissectors to be licensed under the GPL.
license = "GPL",
}
dependencies = {}
build = {
type = "none",
install = {
lua = {
['zmq.ws.dissector'] = "ws/dissector.lua",
['zmq.ws.tap'] = "ws/tap.lua",
['zmq.ws.stats_tap'] = "ws/stats_tap.lua",
},
},
}

@ -1,4 +1,4 @@
-- Copyright (c) 2011 by Robert G. Jakabosky <bobby@sharedrealm.com>
-- Copyright (c) 2010 by Robert G. Jakabosky <bobby@sharedrealm.com>
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
@ -19,30 +19,20 @@
-- THE SOFTWARE.
object "ZMQ_Ctx" {
sys_include"string.h",
error_on_null = "get_zmq_strerror()",
c_source [[
typedef struct ZMQ_Ctx ZMQ_Ctx;
typedef void * ZMQ_Ctx;
]],
destructor "term" {
c_method_call "ZMQ_Error" "zmq_term" {}
c_call "ZMQ_Error" "zmq_term" {}
},
method "lightuserdata" {
var_out{ "void *", "ptr" },
method "socket" {
var_in{ "int", "type" },
var_out{ "ZMQ_Socket", "sock", own = true },
var_out{ "ZMQ_Error", "err"},
c_source[[
${ptr} = ${this};
${sock} = zmq_socket(${this}, ${type});
if(${sock} == NULL) ${err} = -1;
]]
},
method "socket" {
c_method_call "!ZMQ_Socket *" "zmq_socket" { "int", "type"}
},
method "set" {
if_defs = { "VERSION_3_2", "VERSION_4_0" },
c_method_call "int" "zmq_ctx_set" { "int", "flag", "int", "value" }
},
method "get" {
if_defs = { "VERSION_3_2", "VERSION_4_0" },
c_method_call "int" "zmq_ctx_get" { "int", "flag" }
},
}

@ -1,4 +1,4 @@
-- Copyright (c) 2011 by Robert G. Jakabosky <bobby@sharedrealm.com>
-- Copyright (c) 2010 by Robert G. Jakabosky <bobby@sharedrealm.com>
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
@ -18,296 +18,25 @@
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-- THE SOFTWARE.
-- E* error values.
meta_object "ZErrors" {
export_definitions {
-- Native 0MQ error codes.
"EFSM",
"ENOCOMPATPROTO",
"ETERM",
"EMTHREAD",
"EPERM", -- Operation not permitted
"ENOENT", -- No such file or directory
"ESRCH", -- No such process
"EINTR", -- Interrupted system call
"EIO", -- I/O error
"ENXIO", -- No such device or address
"E2BIG", -- Argument list too long
"ENOEXEC", -- Exec format error
"EBADF", -- Bad file number
"ECHILD", -- No child processes
"EAGAIN", -- Try again
"ENOMEM", -- Out of memory
"EACCES", -- Permission denied
"EFAULT", -- Bad address
"ENOTBLK", -- Block device required
"EBUSY", -- Device or resource busy
"EEXIST", -- File exists
"EXDEV", -- Cross-device link
"ENODEV", -- No such device
"ENOTDIR", -- Not a directory
"EISDIR", -- Is a directory
"EINVAL", -- Invalid argument
"ENFILE", -- File table overflow
"EMFILE", -- Too many open files
"ENOTTY", -- Not a typewriter
"ETXTBSY", -- Text file busy
"EFBIG", -- File too large
"ENOSPC", -- No space left on device
"ESPIPE", -- Illegal seek
"EROFS", -- Read-only file system
"EMLINK", -- Too many links
"EPIPE", -- Broken pipe
"EDOM", -- Math argument out of domain of func
"ERANGE", -- Math result not representable
"EDEADLK", -- Resource deadlock would occur
"EDEADLOCK", -- EDEADLK
"ENAMETOOLONG", -- File name too long
"ENOLCK", -- No record locks available
"ENOSYS", -- Function not implemented
"ENOTEMPTY", -- Directory not empty
"ELOOP", -- Too many symbolic links encountered
"EWOULDBLOCK", -- Operation would block
"ENOMSG", -- No message of desired type
"EIDRM", -- Identifier removed
"ECHRNG", -- Channel number out of range
"EL2NSYNC", -- Level 2 not synchronized
"EL3HLT", -- Level 3 halted
"EL3RST", -- Level 3 reset
"ELNRNG", -- Link number out of range
"EUNATCH", -- Protocol driver not attached
"ENOCSI", -- No CSI structure available
"EL2HLT", -- Level 2 halted
"EBADE", -- Invalid exchange
"EBADR", -- Invalid request descriptor
"EXFULL", -- Exchange full
"ENOANO", -- No anode
"EBADRQC", -- Invalid request code
"EBADSLT", -- Invalid slot
"EBFONT", -- Bad font file format
"ENOSTR", -- Device not a stream
"ENODATA", -- No data available
"ETIME", -- Timer expired
"ENOSR", -- Out of streams resources
"ENONET", -- Machine is not on the network
"ENOPKG", -- Package not installed
"EREMOTE", -- Object is remote
"ENOLINK", -- Link has been severed
"EADV", -- Advertise error
"ESRMNT", -- Srmount error
"ECOMM", -- Communication error on send
"EPROTO", -- Protocol error
"EMULTIHOP", -- Multihop attempted
"EDOTDOT", -- RFS specific error
"EBADMSG", -- Not a data message
"EOVERFLOW", -- Value too large for defined data type
"ENOTUNIQ", -- Name not unique on network
"EBADFD", -- File descriptor in bad state
"EREMCHG", -- Remote address changed
"ELIBACC", -- Can not access a needed shared library
"ELIBBAD", -- Accessing a corrupted shared library
"ELIBSCN", -- .lib section in a.out corrupted
"ELIBMAX", -- Attempting to link in too many shared libraries
"ELIBEXEC", -- Cannot exec a shared library directly
"EILSEQ", -- Illegal byte sequence
"ERESTART", -- Interrupted system call should be restarted
"ESTRPIPE", -- Streams pipe error
"EUSERS", -- Too many users
"ENOTSOCK", -- Socket operation on non-socket
"EDESTADDRREQ", -- Destination address required
"EMSGSIZE", -- Message too long
"EPROTOTYPE", -- Protocol wrong type for socket
"ENOPROTOOPT", -- Protocol not available
"EPROTONOSUPPORT", -- Protocol not supported
"ESOCKTNOSUPPORT", -- Socket type not supported
"EOPNOTSUPP", -- Operation not supported on transport endpoint
"EPFNOSUPPORT", -- Protocol family not supported
"EAFNOSUPPORT", -- Address family not supported by protocol
"EADDRINUSE", -- Address already in use
"EADDRNOTAVAIL", -- Cannot assign requested address
"ENETDOWN", -- Network is down
"ENETUNREACH", -- Network is unreachable
"ENETRESET", -- Network dropped connection because of reset
"ECONNABORTED", -- Software caused connection abort
"ECONNRESET", -- Connection reset by peer
"ENOBUFS", -- No buffer space available
"EISCONN", -- Transport endpoint is already connected
"ENOTCONN", -- Transport endpoint is not connected
"ESHUTDOWN", -- Cannot send after transport endpoint shutdown
"ETOOMANYREFS", -- Too many references: cannot splice
"ETIMEDOUT", -- Connection timed out
"ECONNREFUSED", -- Connection refused
"EHOSTDOWN", -- Host is down
"EHOSTUNREACH", -- No route to host
"EALREADY", -- Operation already in progress
"EINPROGRESS", -- Operation now in progress
"ESTALE", -- Stale NFS file handle
"EUCLEAN", -- Structure needs cleaning
"ENOTNAM", -- Not a XENIX named type file
"ENAVAIL", -- No XENIX semaphores available
"EISNAM", -- Is a named type file
"EREMOTEIO", -- Remote I/O error
"EDQUOT", -- Quota exceeded
"ENOMEDIUM", -- No medium found
"EMEDIUMTYPE", -- Wrong medium type
"ECANCELED", -- Operation Canceled
"ENOKEY", -- Required key not available
"EKEYEXPIRED", -- Key has expired
"EKEYREVOKED", -- Key has been revoked
"EKEYREJECTED", -- Key was rejected by service
-- for robust mutexes
"EOWNERDEAD", -- Owner died
"ENOTRECOVERABLE", -- State not recoverable
"ERFKILL", -- Operation not possible due to RF-kill
},
method "description" {
var_in{ "<any>", "err" },
var_out{ "const char *", "msg" },
c_source "pre" [[
int err_type;
int err_num = -1;
]],
c_source[[
err_type = lua_type(L, ${err::idx});
if(err_type == LUA_TSTRING) {
lua_pushvalue(L, ${err::idx});
lua_rawget(L, ${this::idx});
if(lua_isnumber(L, -1)) {
err_num = lua_tointeger(L, -1);
}
lua_pop(L, 1);
} else if(err_type == LUA_TNUMBER) {
err_num = lua_tointeger(L, ${err::idx});
} else {
return luaL_argerror(L, ${err::idx}, "expected string/number");
}
if(err_num < 0) {
lua_pushnil(L);
lua_pushliteral(L, "UNKNOWN ERROR");
return 2;
}
${msg} = strerror(err_num);
]],
},
method "__index" {
var_in{ "int", "err" },
var_out{ "const char *", "msg" },
-- Convert ZMQ Error codes into strings.
error_code "ZMQ_Error" "int" {
is_error_check = function(rec) return "(0 != ${" .. rec.name .. "})" end,
default = "0",
c_source [[
switch(${err}) {
case EAGAIN:
${msg} = "timeout";
break;
case EINTR:
${msg} = "interrupted";
break;
#if defined(ETERM)
case ETERM:
${msg} = "closed";
break;
#endif
default:
${msg} = zmq_strerror(${err});
break;
}
lua_pushvalue(L, ${err::idx});
lua_pushstring(L, ${msg});
lua_rawset(L, ${this::idx});
]],
},
}
ffi_cdef[[
int zmq_errno (void);
]]
ffi_source "ffi_src" [[
-- get ZErrors table to map errno to error name.
local ZError_names = _M.ZErrors
local function get_zmq_strerror()
return ZError_names[C.zmq_errno()]
end
]]
c_source "extra_code" [[
static char *zmq_ZErrors_key = "zmq_ZErrors_key";
/*
* This wrapper function is to make the EAGAIN/ETERM error messages more like
* what is returned by LuaSocket.
*/
static const char *get_zmq_strerror() {
int err = zmq_errno();
if(err != 0) {
err = zmq_errno();
switch(err) {
case EAGAIN:
return "timeout";
err_str = "timeout";
break;
case EINTR:
return "interrupted";
break;
#if defined(ETERM)
case ETERM:
return "closed";
err_str = "closed";
break;
#endif
default:
err_str = zmq_strerror(err);
break;
}
return zmq_strerror(err);
}
]]
c_source "module_init_src" [[
/* Cache reference to zmq.ZErrors table for errno->string convertion. */
lua_pushlightuserdata(L, zmq_ZErrors_key);
lua_getfield(L, -2, "ZErrors");
lua_rawset(L, LUA_REGISTRYINDEX);
]]
-- Convert ZMQ Error codes into strings.
--
-- This is an error code wrapper object, it converts C-style 'int' return error code
-- into Lua-style 'nil, "Error message"' return values.
--
error_code "ZMQ_Error" "int" {
ffi_type = "int",
is_error_check = function(rec) return "(-1 == ${" .. rec.name .. "})" end,
ffi_is_error_check = function(rec) return "(-1 == ${" .. rec.name .. "})" end,
default = "0",
c_source [[
int num;
if(-1 == err) {
/* get ZErrors table. */
lua_pushlightuserdata(L, zmq_ZErrors_key);
lua_rawget(L, LUA_REGISTRYINDEX);
/* convert zmq_errno to string. */
num = zmq_errno();
lua_pushinteger(L, num);
lua_gettable(L, -2);
/* remove ZErrors table. */
lua_remove(L, -2);
if(!lua_isnil(L, -1)) {
/* found error. */
return;
}
/* Unknown error. */
lua_pop(L, 1);
lua_pushfstring(L, "UNKNOWN ERROR(%d)", num);
return;
}
]],
ffi_source [[
if(-1 == err) then
err_str = ZError_names[C.zmq_errno()]
end
]],
}

@ -1,162 +0,0 @@
-- Copyright (c) 2011 by Robert G. Jakabosky <bobby@sharedrealm.com>
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-- THE SOFTWARE.
object "zmq_msg_t" {
-- store the `zmq_msg_t` structure in Lua userdata object
userdata_type = "embed",
implements "Buffer" {
implement_method "const_data" {
c_function = "zmq_msg_data"
},
implement_method "get_size" {
c_function = "zmq_msg_size"
},
},
implements "MutableBuffer" {
implement_method "data" {
c_function = "zmq_msg_data"
},
implement_method "get_size" {
c_function = "zmq_msg_size"
},
},
--
-- Define zmq_msq_t type & function API for FFI
--
ffi_cdef[[
struct zmq_msg_t
{
unsigned char _ [64];
};
int zmq_msg_init (zmq_msg_t *msg);
int zmq_msg_init_size (zmq_msg_t *msg, size_t size);
]],
constructor "init" {
c_method_call "ZMQ_Error" "zmq_msg_init" {},
},
constructor "init_size" {
c_method_call "ZMQ_Error" "zmq_msg_init_size" { "size_t", "size" },
},
constructor "init_data" {
var_in{ "const char *", "data" },
c_method_call { "ZMQ_Error", "err" } "zmq_msg_init_size" { "size_t", "#data" },
c_source[[
if(0 == ${err}) {
/* fill message */
memcpy(zmq_msg_data(${this}), ${data}, ${data_len});
}
]],
ffi_source[[
if(0 == ${err}) then
-- fill message
ffi.copy(C.zmq_msg_data(${this}), ${data}, ${data_len})
end
]],
},
destructor {
c_method_call "ZMQ_Error" "zmq_msg_close" {}
},
method "close" {
c_method_call "ZMQ_Error" "zmq_msg_close" {}
},
method "move" {
c_method_call "ZMQ_Error" "zmq_msg_move" { "zmq_msg_t *", "src" }
},
method "copy" {
c_method_call "ZMQ_Error" "zmq_msg_copy" { "zmq_msg_t *", "src" }
},
method "set_data" {
var_in{ "const char *", "data" },
var_out{ "ZMQ_Error", "err" },
c_source[[
/* check message data size. */
if(zmq_msg_size(${this}) != ${data_len}) {
/* need to resize message. */
zmq_msg_close(${this}); /* close old message, to free old data. */
${err} = zmq_msg_init_size(${this}, ${data_len}); /* re-initialize message. */
if(0 != ${err}) {
luaL_error(L, "set_data() failed: %s", get_zmq_strerror());
}
}
/* copy data into message */
memcpy(zmq_msg_data(${this}), ${data}, ${data_len});
]],
ffi_source[[
-- check message data size.
if (C.zmq_msg_size(${this}) ~= ${data_len}) then
-- need to resize message.
C.zmq_msg_close(${this}); -- close old message, to free old data.
${err} = C.zmq_msg_init_size(${this}, ${data_len}); -- re-initialize message.
if (0 ~= ${err}) then
error("set_data() failed: " .. get_zmq_strerror());
end
end
-- copy data into message
ffi.copy(C.zmq_msg_data(${this}), ${data}, ${data_len});
]],
},
method "data" {
c_method_call "void *" "zmq_msg_data" {}
},
method "set_size" {
var_in{ "size_t", "size" },
var_out{ "ZMQ_Error", "err" },
c_source[[
/* check message data size. */
if(zmq_msg_size(${this}) != ${size}) {
/* need to resize message. */
zmq_msg_close(${this}); /* close old message, to free old data. */
${err} = zmq_msg_init_size(${this}, ${size}); /* re-initialize message. */
if(0 != ${err}) {
luaL_error(L, "set_size() failed: %s", get_zmq_strerror());
}
}
]],
ffi_source[[
-- check message data size.
if (C.zmq_msg_size(${this}) ~= ${size}) then
-- need to resize message.
C.zmq_msg_close(${this}); -- close old message, to free old data.
${err} = C.zmq_msg_init_size(${this}, ${size}); -- re-initialize message.
if (0 ~= ${err}) then
error("set_size() failed: " .. get_zmq_strerror());
end
end
]],
},
method "size" {
c_method_call { "size_t", "size", ffi_wrap = "tonumber"} "zmq_msg_size" {}
},
method "__tostring" {
var_out{ "const char *", "data", has_length = true },
c_source[[
${data} = zmq_msg_data(${this});
${data_len} = zmq_msg_size(${this});
]],
ffi_source[[
${data} = C.zmq_msg_data(${this});
${data_len} = C.zmq_msg_size(${this});
]],
},
}

@ -1,97 +0,0 @@
-- Copyright (c) 2011 by Robert G. Jakabosky <bobby@sharedrealm.com>
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-- THE SOFTWARE.
--
-- zmq.poller wraps the low-level zmq.ZMQ_Poller object.
--
-- This wrapper simplifies the event polling loop.
--
local zmq = require"zmq"
local setmetatable = setmetatable
local tonumber = tonumber
local assert = assert
local poller_mt = {}
poller_mt.__index = poller_mt
function poller_mt:add(sock, events, cb)
local id = self.poller:add(sock, events)
self.callbacks[id] = function(revents) return cb(sock, revents) end
end
function poller_mt:modify(sock, events, cb)
local id
if events ~= 0 and cb then
id = self.poller:modify(sock, events)
self.callbacks[id] = function(revents) return cb(sock, revents) end
else
id = self:remove(sock)
self.callbacks[id] = nil
end
end
function poller_mt:remove(sock)
local id = self.poller:remove(sock)
self.callbacks[id] = nil
end
function poller_mt:poll(timeout)
local poller = self.poller
local count, err = poller:poll(timeout)
if not count then
return nil, err
end
local callbacks = self.callbacks
for i=1,count do
local id, revents = poller:next_revents_idx()
callbacks[id](revents)
end
return count
end
function poller_mt:start()
self.is_running = true
while self.is_running do
status, err = self:poll(-1)
if not status then
return false, err
end
end
return true
end
function poller_mt:stop()
self.is_running = false
end
local M = {}
function M.new(pre_alloc)
return setmetatable({
poller = zmq.ZMQ_Poller(pre_alloc),
callbacks = {},
}, poller_mt)
end
zmq.poller = M
return setmetatable(M, {__call = function(tab, ...) return M.new(...) end})

@ -1,462 +0,0 @@
-- Copyright (c) 2011 by Robert G. Jakabosky <bobby@sharedrealm.com>
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-- THE SOFTWARE.
local ZMQ_Poller_type = [[
struct ZMQ_Poller {
zmq_pollitem_t *items;
int next;
int count;
int free_list;
int len;
};
]]
object "ZMQ_Poller" {
-- store the `ZMQ_Poller` structure in Lua userdata object
userdata_type = "embed",
c_source(ZMQ_Poller_type),
c_source[[
typedef struct ZMQ_Poller ZMQ_Poller;
#define FREE_ITEM_EVENTS_TAG ((short)0xFFFF)
#define ITEM_TO_INDEX(items, item) (item - (items))
static int poller_resize_items(ZMQ_Poller *poller, int len) {
int old_len = poller->len;
/* make sure new length is atleast as large as items count. */
len = (poller->count <= len) ? len : poller->count;
/* if the new length is the same as the old length, then don't try to resize. */
if(old_len == len) return len;
poller->items = (zmq_pollitem_t *)realloc(poller->items, len * sizeof(zmq_pollitem_t));
poller->len = len;
if(len > old_len) {
/* clear new space. */
memset(&(poller->items[old_len]), 0, (len - old_len) * sizeof(zmq_pollitem_t));
}
return len;
}
void poller_init(ZMQ_Poller *poller, int length) {
poller->items = (zmq_pollitem_t *)calloc(length, sizeof(zmq_pollitem_t));
poller->next = -1;
poller->count = 0;
poller->len = length;
poller->free_list = -1;
}
void poller_cleanup(ZMQ_Poller *poller) {
free(poller->items);
poller->items = NULL;
poller->next = -1;
poller->count = 0;
poller->len = 0;
poller->free_list = -1;
}
int poller_find_sock_item(ZMQ_Poller *poller, ZMQ_Socket *sock) {
zmq_pollitem_t *items;
int count;
int n;
/* find ZMQ_Socket */
items = poller->items;
count = poller->count;
for(n=0; n < count; n++) {
if(items[n].socket == sock) return n;
}
/* not found. */
return -1;
}
int poller_find_fd_item(ZMQ_Poller *poller, socket_t fd) {
zmq_pollitem_t *items;
int count;
int n;
/* find fd */
items = poller->items;
count = poller->count;
for(n=0; n < count; n++) {
if(items[n].fd == fd) return n;
}
/* not found. */
return -1;
}
void poller_remove_item(ZMQ_Poller *poller, int idx) {
zmq_pollitem_t *items;
int free_list;
int count;
count = poller->count;
/* no item to remove. */
if(idx >= count || count == 0) return;
items = poller->items;
free_list = poller->free_list;
/* link new free slot to head of free list. */
if(free_list >= 0 && free_list < count) {
/* use socket pointer for free list's 'next' field. */
items[idx].socket = &(items[free_list]);
} else {
/* free list is empty mark poller slot as the end. */
items[idx].socket = NULL;
}
poller->free_list = idx;
/* mark poller slot as a free slot. */
items[idx].events = FREE_ITEM_EVENTS_TAG;
/* clear old revents. */
items[idx].revents = 0;
}
int poller_get_free_item(ZMQ_Poller *poller) {
zmq_pollitem_t *curr;
zmq_pollitem_t *next;
int count;
int idx;
count = poller->count;
idx = poller->free_list;
/* check for a free slot in the free list. */
if(idx >= 0 && idx < count) {
/* remove free slot from free list. */
curr = &(poller->items[idx]);
/* valid free slot. */
assert(curr->events == FREE_ITEM_EVENTS_TAG);
/* is poller the last free slot? */
next = ((zmq_pollitem_t *)curr->socket);
if(next != NULL) {
/* set next free slot as head of free list. */
poller->free_list = ITEM_TO_INDEX(poller->items, next);
} else {
/* free list is empty now. */
poller->free_list = -1;
}
/* clear slot */
memset(curr, 0, sizeof(zmq_pollitem_t));
return idx;
}
idx = count;
poller->count = ++count;
/* make room for new item. */
if(count >= poller->len) {
poller_resize_items(poller, poller->len + 10);
}
return idx;
}
static int poller_compact_items(ZMQ_Poller *poller) {
zmq_pollitem_t *items;
int count;
int old_count;
int next;
count = poller->count;
/* if no free slot, then return. */
if(poller->free_list < 0) return count;
old_count = count;
items = poller->items;
next = 0;
/* find first free slot. */
while(next < count && items[next].events != FREE_ITEM_EVENTS_TAG) {
++next;
}
/* move non-free slots into free slot. */
count = next;
++next;
while(next < old_count) {
if(items[next].events != FREE_ITEM_EVENTS_TAG) {
/* found non-free slot, move it to the current free slot. */
items[count] = items[next];
++count;
}
++next;
}
/* clear old used-space */
memset(&(items[count]), 0, ((old_count - count) * sizeof(zmq_pollitem_t)));
poller->count = count;
poller->free_list = -1; /* free list is now empty. */
assert(count <= poller->len);
return count;
}
int poller_poll(ZMQ_Poller *poller, long timeout) {
int count;
/* remove free slots from items list. */
if(poller->free_list >= 0) {
count = poller_compact_items(poller);
} else {
count = poller->count;
}
/* poll for events. */
return zmq_poll(poller->items, count, timeout);
}
int poller_next_revents(ZMQ_Poller *poller, int *revents) {
zmq_pollitem_t *items;
int count;
int idx;
int next;
idx = poller->next;
/* do we need to poll for more events? */
if(idx < 0) {
return idx;
}
items = poller->items;
count = poller->count;
/* find next item with pending events. */
for(;idx < count; ++idx) {
/* did we find a pending event? */
if(items[idx].revents != 0) {
*revents = items[idx].revents;
poller->next = idx+1;
return idx;
}
}
/* processed all pending events. */
poller->next = -1;
*revents = 0;
return -1;
}
]],
--
-- Define ZMQ_Poller type & function API for FFI
--
ffi_cdef[[
typedef int socket_t;
typedef struct zmq_pollitem_t {
ZMQ_Socket *socket;
socket_t fd;
short events;
short revents;
} zmq_pollitem_t;
int poller_find_sock_item(ZMQ_Poller *poller, ZMQ_Socket *sock);
int poller_find_fd_item(ZMQ_Poller *poller, socket_t fd);
int poller_get_free_item(ZMQ_Poller *poller);
int poller_poll(ZMQ_Poller *poller, long timeout);
void poller_remove_item(ZMQ_Poller *poller, int idx);
]],
ffi_cdef(ZMQ_Poller_type),
constructor "new" {
var_in{ "unsigned int", "length", is_optional = true, default = 10 },
c_export_method_call "void" "poller_init" { "unsigned int", "length" },
},
destructor "close" {
c_export_method_call "void" "poller_cleanup" {},
},
method "add" {
var_in{ "<any>", "sock" },
var_in{ "short", "events" },
var_out{ "int", "idx" },
c_source "pre" [[
zmq_pollitem_t *item;
ZMQ_Socket *sock = NULL;
socket_t fd = 0;
]],
c_source[[
if(lua_isuserdata(L, ${sock::idx})) {
sock = obj_type_ZMQ_Socket_check(L, ${sock::idx});
} else if(lua_isnumber(L, ${sock::idx})) {
fd = lua_tonumber(L, ${sock::idx});
} else {
return luaL_typerror(L, ${sock::idx}, "number or ZMQ_Socket");
}
${idx} = poller_get_free_item(${this});
item = &(${this}->items[${idx}]);
item->socket = sock;
item->fd = fd;
item->events = ${events};
]],
ffi_source[[
local fd = 0
local sock_type = type(${sock})
local sock
if sock_type == 'cdata' then
sock = obj_type_ZMQ_Socket_check(${sock})
elseif sock_type == 'number' then
fd = ${sock}
else
error("expected number or ZMQ_Socket")
end
${idx} = Cmod.poller_get_free_item(${this})
local item = ${this}.items[${idx}]
item.socket = sock
item.fd = fd
item.events = ${events}
]],
},
method "modify" {
var_in{ "<any>", "sock" },
var_in{ "short", "events" },
var_out{ "int", "idx" },
c_source "pre" [[
zmq_pollitem_t *item;
ZMQ_Socket *sock = NULL;
socket_t fd = 0;
]],
c_source[[
if(lua_isuserdata(L, ${sock::idx})) {
sock = obj_type_ZMQ_Socket_check(L, ${sock::idx});
/* find sock in items list. */
${idx} = poller_find_sock_item(${this}, sock);
} else if(lua_isnumber(L, ${sock::idx})) {
fd = lua_tonumber(L, ${sock::idx});
/* find fd in items list. */
${idx} = poller_find_fd_item(${this}, fd);
} else {
return luaL_typerror(L, ${sock::idx}, "number or ZMQ_Socket");
}
if(${events} != 0) {
/* add/modify. */
if(${idx} < 0) {
${idx} = poller_get_free_item(${this});
}
item = &(${this}->items[${idx}]);
item->socket = sock;
item->fd = fd;
item->events = ${events};
} else if(${idx} >= 0) {
/* no events remove socket/fd. */
poller_remove_item(${this}, ${idx});
}
]],
ffi_source[[
local fd = 0
local sock_type = type(${sock})
local sock
if sock_type == 'cdata' then
sock = obj_type_ZMQ_Socket_check(${sock})
-- find sock in items list.
${idx} = Cmod.poller_find_sock_item(${this}, sock)
elseif sock_type == 'number' then
fd = ${sock}
-- find fd in items list.
${idx} = Cmod.poller_find_fd_item(${this}, fd);
else
error("expected number or ZMQ_Socket")
end
if ${events} ~= 0 then
local item = ${this}.items[${idx}]
item.socket = sock
item.fd = fd
item.events = ${events}
else
Cmod.poller_remove_item(${this}, ${idx})
end
]],
},
method "remove" {
var_in{ "<any>", "sock" },
var_out{ "int", "idx" },
c_source "pre" [[
ZMQ_Socket *sock;
socket_t fd;
]],
c_source[[
/* ZMQ_Socket or fd */
if(lua_isuserdata(L, ${sock::idx})) {
sock = obj_type_ZMQ_Socket_check(L, ${sock::idx});
/* find sock in items list. */
${idx} = poller_find_sock_item(${this}, sock);
} else if(lua_isnumber(L, ${sock::idx})) {
fd = lua_tonumber(L, ${sock::idx});
/* find fd in items list. */
${idx} = poller_find_fd_item(${this}, fd);
} else {
return luaL_typerror(L, ${sock::idx}, "number or ZMQ_Socket");
}
/* if sock/fd was found. */
if(${idx} >= 0) {
poller_remove_item(${this}, ${idx});
}
]],
ffi_source[[
local fd = 0
local sock_type = type(${sock})
local sock
if sock_type == 'cdata' then
sock = obj_type_ZMQ_Socket_check(${sock})
-- find sock in items list.
${idx} = Cmod.poller_find_sock_item(${this}, sock)
elseif sock_type == 'number' then
fd = ${sock}
-- find fd in items list.
${idx} = Cmod.poller_find_fd_item(${this}, fd);
else
error("expected number or ZMQ_Socket")
end
if ${idx} >= 0 then
Cmod.poller_remove_item(${this}, ${idx})
end
]],
},
method "poll" {
var_out{ "int", "count" },
-- poll for events
c_export_method_call { "ZMQ_Error", "err>2" } "poller_poll" { "long", "timeout" },
c_source[[
if(${err} > 0) {
${this}->next = 0;
${count} = ${err};
} else {
${this}->next = -1;
${count} = 0;
}
]],
ffi_source[[
if(${err} > 0) then
${this}.next = 0
${count} = ${err}
else
${this}.next = -1
${count} = 0
end
]],
},
method "next_revents_idx" {
c_export_method_call { "int", "idx>1" } "poller_next_revents" { "int", "&revents>2" },
},
method "count" {
var_out{ "int", "count" },
c_source[[
${count} = ${this}->count;
]],
ffi_source[[
${count} = ${this}.count;
]],
},
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -1,35 +0,0 @@
-- Copyright (c) 2011 by Robert G. Jakabosky <bobby@sharedrealm.com>
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-- THE SOFTWARE.
object "ZMQ_StopWatch" {
c_source[[
#if (ZMQ_VERSION_MAJOR <= 4) && (ZMQ_VERSION_MINOR <= 1)
#include "zmq_utils.h"
#endif
typedef struct ZMQ_StopWatch ZMQ_StopWatch;
]],
constructor "start" {
c_call "ZMQ_StopWatch *" "zmq_stopwatch_start" {},
},
destructor "stop" {
c_method_call { "unsigned long", "usecs", ffi_wrap = 'tonumber' } "zmq_stopwatch_stop" {},
},
}

@ -1,94 +0,0 @@
-- Copyright (c) 2011 by Robert G. Jakabosky <bobby@sharedrealm.com>
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-- THE SOFTWARE.
--
-- zmq.thread wraps the low-level threads object & a zmq context.
--
local zmq = require"zmq"
local llthreads = require"llthreads"
local bootstrap_pre = [[
local action, action_arg, parent_ctx = ...
local func
]]
local bootstrap_post = [[
-- copy parent ZeroMQ context to this child thread.
local zmq = require"zmq"
local zthreads = require"zmq.threads"
if parent_ctx then
zthreads.set_parent_ctx(zmq.init_ctx(parent_ctx))
end
-- create global 'arg'
arg = { select(4, ...) }
-- load Lua code.
if action == 'runfile' then
func = assert(loadfile(action_arg))
-- script name
arg[0] = action_arg
elseif action == 'runstring' then
func = assert(loadstring(action_arg))
-- fake script name
arg[0] = '=(loadstring)'
end
-- run loaded code.
return func(select(4, ...))
]]
local bootstrap_code = bootstrap_pre..bootstrap_post
local function new_thread(ctx, action, action_arg, ...)
-- convert ZMQ_Ctx to lightuserdata.
if ctx then
ctx = ctx:lightuserdata()
end
return llthreads.new(bootstrap_code, action, action_arg, ctx, ...)
end
local M = {}
function M.set_bootstrap_prelude(code)
bootstrap_code = bootstrap_pre .. code .. bootstrap_post
end
function M.runfile(ctx, file, ...)
return new_thread(ctx, 'runfile', file, ...)
end
function M.runstring(ctx, code, ...)
return new_thread(ctx, 'runstring', code, ...)
end
local parent_ctx = nil
function M.set_parent_ctx(ctx)
parent_ctx = ctx
end
function M.get_parent_ctx(ctx)
return parent_ctx
end
zmq.threads = M
return M

@ -0,0 +1,294 @@
ffi_source "ffi_src" [==================[
local zmq = ...
-- try loading luajit's ffi
local stat, ffi=pcall(require,"ffi")
if not stat then
print("No FFI module: ZMQ using standard Lua api interface.")
return
end
-- check if ffi is disabled.
if disable_ffi then
print("FFI disabled: ZMQ using standard Lua api interface.")
return
end
local setmetatable = setmetatable
local print = print
local pairs = pairs
local error = error
local type = type
local assert = assert
local tostring = tostring
local tonumber = tonumber
local z_SUBSCRIBE = zmq.SUBSCRIBE
local z_UNSUBSCRIBE = zmq.UNSUBSCRIBE
local z_IDENTITY = zmq.IDENTITY
local z_NOBLOCK = zmq.NOBLOCK
local z_RCVMORE = zmq.RCVMORE
local z_SNDMORE = zmq.SNDMORE
local z_EVENTS = zmq.EVENTS
local z_POLLIN = zmq.POLLIN
local z_POLLOUT = zmq.POLLOUT
local z_POLLIN_OUT = z_POLLIN + z_POLLOUT
ffi.cdef[[
void zmq_version (int *major, int *minor, int *patch);
int zmq_errno ();
const char *zmq_strerror (int errnum);
typedef struct zmq_msg_t
{
void *content;
unsigned char flags;
unsigned char vsm_size;
unsigned char vsm_data [30];
} zmq_msg_t;
typedef void (zmq_free_fn) (void *data, void *hint);
int zmq_msg_init (zmq_msg_t *msg);
int zmq_msg_init_size (zmq_msg_t *msg, size_t size);
int zmq_msg_init_data (zmq_msg_t *msg, void *data, size_t size, zmq_free_fn *ffn, void *hint);
int zmq_msg_close (zmq_msg_t *msg);
int zmq_msg_move (zmq_msg_t *dest, zmq_msg_t *src);
int zmq_msg_copy (zmq_msg_t *dest, zmq_msg_t *src);
void *zmq_msg_data (zmq_msg_t *msg);
size_t zmq_msg_size (zmq_msg_t *msg);
void *zmq_init (int io_threads);
int zmq_term (void *context);
void *zmq_socket (void *context, int type);
int zmq_close (void *s);
int zmq_setsockopt (void *s, int option, const void *optval, size_t optvallen);
int zmq_getsockopt (void *s, int option, void *optval, size_t *optvallen);
int zmq_bind (void *s, const char *addr);
int zmq_connect (void *s, const char *addr);
int zmq_send (void *s, zmq_msg_t *msg, int flags);
int zmq_recv (void *s, zmq_msg_t *msg, int flags);
int zmq_device (int device, void * insocket, void* outsocket);
]]
require"utils"
local C = ffi.load"zmq"
--module(...)
zmq._M = zmq
setfenv(1, zmq)
function version()
local major = ffi.new('int[1]',0)
local minor = ffi.new('int[1]',0)
local patch = ffi.new('int[1]',0)
C.zmq_version(major, minor, patch)
return {major[0], minor[0], patch[0]}
end
local function zmq_error()
local errno = C.zmq_errno()
local err = ffi.string(C.zmq_strerror(errno))
if err == "Resource temporarily unavailable" then err = "timeout" end
if err == "Context was terminated" then err = "closed" end
return nil, err
end
--
-- ZMQ socket
--
local sock_mt = {}
sock_mt.__index = sock_mt
local function new_socket(ctx, sock_type)
local sock = C.zmq_socket(ctx, sock_type)
if not sock then
return zmq_error()
end
return setmetatable({ sock = sock }, sock_mt)
end
function sock_mt:close()
local ret = C.zmq_close(self.sock)
self.sock = nil
if ret ~= 0 then
return zmq_error()
end
return true
end
local option_types = {
[zmq.HWM] = 'uint64_t[1]',
[zmq.SWAP] = 'int64_t[1]',
[zmq.AFFINITY] = 'uint64_t[1]',
[zmq.IDENTITY] = 'string',
[zmq.SUBSCRIBE] = 'string',
[zmq.UNSUBSCRIBE] = 'string',
[zmq.RATE] = 'int64_t[1]',
[zmq.RECOVERY_IVL] = 'int64_t[1]',
[zmq.MCAST_LOOP] = 'int64_t[1]',
[zmq.SNDBUF] = 'uint64_t[1]',
[zmq.RCVBUF] = 'uint64_t[1]',
[zmq.RCVMORE] = 'int64_t[1]',
[zmq.FD] = 'int[1]',
[zmq.EVENTS] = 'uint32_t[1]',
[zmq.TYPE] = 'int[1]',
[zmq.LINGER] = 'int[1]',
[zmq.RECONNECT_IVL] = 'int[1]',
[zmq.BACKLOG] = 'int[1]',
}
local option_len = {}
local option_tmps = {}
for k,v in pairs(option_types) do
if v ~= 'string' then
option_len[k] = ffi.sizeof(v)
option_tmps[k] = ffi.new(v, 0)
end
end
function sock_mt:setopt(opt, opt_val)
local ctype = option_types[opt]
local val_len = 0
if ctype == 'string' then
--val = ffi.cast('void *', tostring(val))
val = tostring(opt_val)
val_len = #val
else
val = option_tmps[opt]
val[0] = opt_val
val_len = option_len[opt]
end
local ret = C.zmq_setsockopt(self.sock, opt, val, val_len)
if ret ~= 0 then
return zmq_error()
end
return true
end
local tmp_val_len = ffi.new('size_t[1]', 4)
function sock_mt:getopt(opt)
local ctype = option_types[opt]
local val
local val_len = tmp_val_len
if ctype == 'string' then
val_len[0] = 255
val = ffi.new('uint8_t[?]', val_len[0])
ffi.fill(val, val_len[0])
else
val = option_tmps[opt]
val[0] = 0
val_len[0] = option_len[opt]
end
local ret = C.zmq_getsockopt(self.sock, opt, val, val_len)
if ret ~= 0 then
return zmq_error()
end
if ctype == 'string' then
val_len = val_len[0]
return ffi.string(val, val_len)
else
val = val[0]
end
return tonumber(val)
end
local tmp32 = ffi.new('uint32_t[1]', 0)
local tmp32_len = ffi.new('size_t[1]', 4)
function sock_mt:events()
local val = tmp32
local val_len = tmp32_len
val[0] = 0
val_len[0] = 4
local ret = C.zmq_getsockopt(self.sock, 15, val, val_len)
if ret ~= 0 then
return zmq_error()
end
return val[0]
end
function sock_mt:bind(addr)
local ret = C.zmq_bind(self.sock, addr)
if ret ~= 0 then
return zmq_error()
end
return true
end
function sock_mt:connect(addr)
local ret = C.zmq_connect(self.sock, addr)
if ret ~= 0 then
return zmq_error()
end
return true
end
local tmp_msg = ffi.new('zmq_msg_t')
function sock_mt:send(data, flags)
local msg = tmp_msg
local msg_len = #data
-- initialize message
if C.zmq_msg_init_size(msg, msg_len) < 0 then
return zmq_error()
end
-- copy data into message.
ffi.copy(C.zmq_msg_data(msg), data, msg_len)
-- send message
local ret = C.zmq_send(self.sock, msg, flags or 0)
-- close message before processing return code
C.zmq_msg_close(msg)
-- now process send return code
if ret ~= 0 then
return zmq_error()
end
return true
end
function sock_mt:recv(flags)
local msg = tmp_msg
-- initialize blank message.
if C.zmq_msg_init(msg) < 0 then
return zmq_error()
end
-- receive message
local ret = C.zmq_recv(self.sock, msg, flags or 0)
if ret ~= 0 then
local data, err = zmq_error()
C.zmq_msg_close(msg)
return data, err
end
local data = ffi.string(C.zmq_msg_data(msg), C.zmq_msg_size(msg))
-- close message
C.zmq_msg_close(msg)
return data
end
--
-- ZMQ context
--
local ctx_mt = {}
ctx_mt.__index = ctx_mt
function ctx_mt:term()
if C.zmq_term(self.ctx) ~= 0 then
return zmq_error()
end
return true
end
function ctx_mt:socket(sock_type)
return new_socket(self.ctx, sock_type)
end
function init(io_threads)
print("ZMQ using FFI interface.")
local ctx = C.zmq_init(io_threads)
if not ctx then
return zmq_error()
end
return setmetatable({ ctx = ctx }, ctx_mt)
end
]==================]

@ -1,75 +0,0 @@
-- Copyright (c) 2011 Robert G. Jakabosky <bobby@sharedrealm.com>
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-- THE SOFTWARE.
if #arg < 1 then
print("usage: lua " .. arg[0] .. " [message-size] [roundtrip-count] [bind-to] [connect-to]")
end
local message_size = tonumber(arg[1] or 1)
local roundtrip_count = tonumber(arg[2] or 100)
local bind_to = arg[3] or 'inproc://thread_lat_test'
local connect_to = arg[4] or 'inproc://thread_lat_test'
local zmq = require"zmq"
local ctx = zmq.init(1)
local server = assert(ctx:socket(zmq.REQ))
assert(server:bind(bind_to))
local client = ctx:socket(zmq.REP)
client:connect(connect_to)
local data = ("0"):rep(message_size)
local msg = zmq.zmq_msg_t.init_size(message_size)
local client_msg = zmq.zmq_msg_t()
print(string.format("message size: %i [B]", message_size))
print(string.format("roundtrip count: %i", roundtrip_count))
local timer = zmq.stopwatch_start()
for i = 1, roundtrip_count do
-- server send
assert(server:send_msg(msg))
-- client recv
assert(client:recv_msg(client_msg))
assert(client_msg:size() == message_size, "Invalid message size")
-- client send
assert(client:send_msg(client_msg))
-- server recv
assert(server:recv_msg(msg))
assert(msg:size() == message_size, "Invalid message size")
end
local elapsed = timer:stop()
server:close()
client:close()
ctx:term()
local latency = elapsed / roundtrip_count / 2
print(string.format("mean latency: %.3f [us]", latency))
local secs = elapsed / (1000 * 1000)
print(string.format("elapsed = %f", secs))
print(string.format("msg/sec = %f", roundtrip_count / secs))

@ -1,674 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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
(at your option) 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/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

@ -1,306 +0,0 @@
-- Copyright (c) 2011, Robert G. Jakabosky <bobby@sharedrealm.com> All rights reserved.
-- cache globals to local for speed.
local format=string.format
local tostring=tostring
local tonumber=tonumber
local sqrt=math.sqrt
local pairs=pairs
-- wireshark API globals
local Pref = Pref
local Proto = Proto
local ProtoField = ProtoField
local DissectorTable = DissectorTable
local ByteArray = ByteArray
local PI_MALFORMED = PI_MALFORMED
local PI_ERROR = PI_ERROR
-- zmq protocol example
-- declare our protocol
local zmq_proto = Proto("zmq","ZMQ","ZeroMQ Protocol")
-- setup preferences
zmq_proto.prefs["tcp_port_start"] =
Pref.string("TCP port range start", "5555", "First TCP port to decode as this protocol")
zmq_proto.prefs["tcp_port_end"] =
Pref.string("TCP port range end", "5555", "Last TCP port to decode as this protocol")
-- current preferences settings.
local current_settings = {
tcp_port_start = -1,
tcp_port_end = -1,
}
-- setup protocol fields.
zmq_proto.fields = {}
local fds = zmq_proto.fields
fds.frame = ProtoField.new("Frame", "zmq.frame", "ftypes.BYTES", nil, "base.NONE")
fds.length = ProtoField.new("Frame Length", "zmq.frame.len", "ftypes.UINT64", nil, "base.DEC")
fds.length8 = ProtoField.new("Frame 8bit Length", "zmq.frame.len8", "ftypes.UINT8", nil, "base.DEC")
fds.length64 = ProtoField.new("Frame 64bit Length", "zmq.frame.len64", "ftypes.UINT64", nil, "base.DEC")
fds.flags = ProtoField.new("Frame Flags", "zmq.frame.flags", "ftypes.UINT8", nil, "base.HEX", "0xFF")
fds.flags_more = ProtoField.new("More", "zmq.frame.flags.more", "ftypes.UINT8", nil, "base.HEX", "0x01")
fds.body = ProtoField.new("Frame body", "zmq.frame.body", "ftypes.BYTES", nil, "base.NONE")
-- un-register zmq to handle tcp port range
local function unregister_tcp_port_range(start_port, end_port)
if not start_port or start_port <= 0 or not end_port or end_port <= 0 then
return
end
local tcp_port_table = DissectorTable.get("tcp.port")
for port = start_port,end_port do
tcp_port_table:remove(port,zmq_proto)
end
end
-- register zmq to handle tcp port range
local function register_tcp_port_range(start_port, end_port)
if not start_port or start_port <= 0 or not end_port or end_port <= 0 then
return
end
local tcp_port_table = DissectorTable.get("tcp.port")
for port = start_port,end_port do
tcp_port_table:add(port,zmq_proto)
end
end
-- handle preferences changes.
function zmq_proto.init(arg1, arg2)
local old_start, old_end
local new_start, new_end
-- check if preferences have changed.
for pref_name,old_v in pairs(current_settings) do
local new_v = zmq_proto.prefs[pref_name]
if new_v ~= old_v then
if pref_name == "tcp_port_start" then
old_start = old_v
new_start = new_v
elseif pref_name == "tcp_port_end" then
old_end = old_v
new_end = new_v
end
-- save new value.
current_settings[pref_name] = new_v
end
end
-- un-register old port range
if old_start and old_end then
unregister_tcp_port_range(tonumber(old_start), tonumber(old_end))
end
-- register new port range.
if new_start and new_end then
register_tcp_port_range(tonumber(new_start), tonumber(new_end))
end
end
-- parse flag bits.
local BITS = {
MORE = 0x01,
RESERVED = 0x7E,
}
local flag_names = {"MORE"}
local bits_lookup = {}
local bits_list = {
{},
{MORE = true},
{MORE = true, RESERVED = true},
{RESERVED = true},
}
local function parse_flags(flags)
return bits_lookup[flags] or bits_lookup[1]
end
-- make bits object
local function make_bits(bits)
local proxy = newproxy(true)
local meta = getmetatable(proxy)
meta.__index = bits
meta.__tostring = function()
return bits.flags
end
-- combind bits into string description.
local flags = nil
for i=1,#flag_names do
local name = flag_names[i]
if bits[name] then
if flags then
flags = flags .. ',' .. name
else
flags = name
end
end
end
-- combind bits into one byte value.
local byte = 0x00
for k,v in pairs(bits) do
local bit = assert(BITS[k], "Invalid bit name.")
byte = byte + BITS[k]
end
bits.flags = flags or ''
bits.byte = byte
return proxy
end
-- make bits objects in bis_lookup
for i=1,#bits_list do
local bits = bits_list[i]
bits = make_bits(bits)
bits_lookup[bits.byte] = bits
end
local function zmq_dissect_frame(buffer, pinfo, frame_tree, tap)
local rang,offset
-- Frame length
offset = 0
local len_off = offset
local len8_rang = buffer(offset,1)
local len_rang = len8_rang
local frame_len = len8_rang:uint()
-- 8bit length field
local ti = frame_tree:add(fds.length8, len8_rang)
ti:set_hidden()
offset = offset + 1
if frame_len == 255 then
local len64_rang = buffer(offset, 8)
len_rang = buffer(len_off, 9)
frame_len = tonumber(tostring(len64_rang:uint64()))
-- 64bit length field.
local ti = frame_tree:add(fds.length64, len64_rang)
ti:set_hidden()
offset = offset + 8
local ti = frame_tree:add(fds.length, len_rang)
ti:set_text(format("Frame Length: %d", frame_length))
else
frame_tree:add(fds.length, len_rang)
end
-- Frame flags
rang = buffer(offset,1)
local flags = rang:uint()
local flags_bits = parse_flags(flags)
local flags_list = flags_bits.flags
local flags_tree = frame_tree:add(fds.flags, rang)
flags_tree:set_text(format('Flags: 0x%02X (%s)', flags, flags_list))
flags_tree:add(fds.flags_more, rang)
offset = offset + 1
if flags_bits.MORE then
tap.more = tap.more + 1
else
-- if the 'more' flag is not set then this is the last frame in a message.
tap.msgs = tap.msgs + 1
end
-- Frame body
local body_len = frame_len - 1
local body = ''
if body_len > 0 then
tap.body_bytes = tap.body_bytes + body_len
rang = buffer(offset, body_len)
local ti = frame_tree:add_le(fds.body, rang)
if body_len <= 4 then
body = format("%08x", rang:uint())
else
body = tostring(rang)
end
ti:set_text(format("%s", body))
end
offset = offset + body_len
-- frame summary
if body_len > 0 then
if flags_bits.MORE then
frame_tree:set_text(format("Frame: [MORE] Body[%u]=%s", body_len, body))
else
frame_tree:set_text(format("Frame: Body[%u]=%s", body_len, body))
end
else
if flags_bits.MORE then
frame_tree:set_text(format("Frame: [MORE] No data"))
else
frame_tree:set_text(format("Frame: No data"))
end
end
end
local DESEGMENT_ONE_MORE_SEGMENT = 0x0fffffff
local DESEGMENT_UNTIL_FIN = 0x0ffffffe
-- packet dissector
function zmq_proto.dissector(tvb,pinfo,tree)
local offset = 0
local tvb_length = tvb:len()
local reported_length = tvb:reported_len()
local length_remaining
local zmq_tree
local rang
local frames = 0
local tap = {}
tap.frames = 0
tap.msgs = 0
tap.more = 0
tap.body_bytes = 0
while(offset < reported_length and offset < tvb_length) do
length_remaining = tvb_length - offset
-- check for fixed part of PDU
if length_remaining < 2 then
pinfo.desegment_offset = offset
pinfo.desegment_len = DESEGMENT_ONE_MORE_SEGMENT
break
end
-- decode frame length
-- decode single byte frame length
rang = tvb(offset, 1)
local frame_len = rang:le_uint()
local pdu_len = frame_len + 1
if frame_len == 255 then
-- make sure there is enough bytes
if length_remaining < 10 then
pinfo.desegment_offset = offset
pinfo.desegment_len = DESEGMENT_ONE_MORE_SEGMENT
break
end
-- decode extra long frame length.
rang = tvb(offset + 1, 8)
frame_len = tonumber(tostring(rang:uint64()))
pdu_len = frame_len + 9
end
-- provide hints to tcp
if not pinfo.visited then
local remaining_bytes = reported_length - offset
if pdu_len > remaining_bytes then
pinfo.want_pdu_tracking = 2
pinfo.bytes_until_next_pdu = pdu_len - remaining_bytes
end
end
-- check if we need more bytes to dissect this frame.
if length_remaining < pdu_len then
pinfo.desegment_offset = offset
pinfo.desegment_len = (pdu_len - length_remaining)
break
end
-- dissect zmq frame
if not zmq_tree then
zmq_tree = tree:add(zmq_proto,tvb(),"ZMQ frames")
end
rang = tvb(offset, pdu_len)
local frame_tree = zmq_tree:add(fds.frame, rang)
zmq_dissect_frame(rang:tvb(), pinfo, frame_tree, tap)
frames = frames + 1
-- step to next frame.
local offset_before = offset
offset = offset + pdu_len
if offset < offset_before then break end
end
if zmq_tree then
zmq_tree:set_text(format("ZMQ frames=%u", frames))
end
if frames > 0 then
tap.frames = frames
pinfo.tap_data = tap
end
-- Info column
pinfo.cols.protocol = "ZMQ"
pinfo.cols.info = format('ZMQ frames=%u',frames)
end
-- register zmq to handle tcp ports 5550-5560
register_tcp_port_range(5550,5560)

@ -1,16 +0,0 @@
local prequire = function(name)
local status, result1 = pcall(require, name)
if not status then
debug("Failed to load " .. name .. ": " .. result1)
end
return result1
end
prequire("zmq.ws.dissector")
-- if running from wireshark, register all taps.
if gui_enabled() then
prequire("zmq.ws.stats_tap")
end

@ -1,58 +0,0 @@
-- Copyright (c) 2011, Robert G. Jakabosky <bobby@sharedrealm.com> All rights reserved.
local tap = require"zmq.ws.tap"
local format = string.format
local stats_tap_mt = {}
stats_tap_mt.__index = stats_tap_mt
function stats_tap_mt:packet(pinfo, tvb, tree, data)
-- count all ZeroMQ packets
self.count = self.count + 1
data = data or pinfo.tap_data
if not data then
return
end
-- frames
self.frames = self.frames + (data.frames or 0)
-- frames with more flag set
self.more = self.more + (data.more or 0)
-- whole messages.
self.msgs = self.msgs + (data.msgs or 0)
-- total bytes in frame bodies.
self.body_bytes = self.body_bytes + (data.body_bytes or 0)
end
function stats_tap_mt:draw()
return format([[
ZeroMQ Packets: %d
Frames: %d
Messages: %d
Flags: More: %d
Payload bytes: %d
]],
self.count,
self.frames,
self.msgs,
self.more,
self.body_bytes)
end
function stats_tap_mt:reset()
self.count = 0
self.frames = 0
self.msgs = 0
self.more = 0
self.body_bytes = 0
end
local function create_stats_tap()
local tap = setmetatable({}, stats_tap_mt)
tap:reset() -- initialize tap.
return tap, 'zmq', 'lua'
end
tap("ZeroMQ stats tap", create_stats_tap)

@ -1,84 +0,0 @@
-- Copyright (c) 2011, Robert G. Jakabosky <bobby@sharedrealm.com> All rights reserved.
local gui_enabled = gui_enabled
local register_menu = register_menu
local MENU_TOOLS_UNSORTED = MENU_TOOLS_UNSORTED
local win_instances = 0
local function create_window_tap(name, create)
win_instances = win_instances + 1
local td, tap_filter, tap_type = create()
-- tap's output window.
local win = TextWindow.new(name .. " " .. win_instances)
-- this tap will be local to the menu_function that called it
local tap = Listener.new(tap_type, tap_filter)
-- callback to remove the tap when the text window closes
function remove_tap()
if tap and tap.remove then
tap:remove()
end
end
-- make sure the tap doesn't hang around after the window was closed
win:set_atclose(remove_tap)
-- this function will be called for every packet
function tap.packet(pinfo,tvb, tree, tapdata)
return td:packet(pinfo, tvb, tree, tapdata)
end
-- this function will be called once every few seconds to redraw the window
function tap.draw()
local text = td:draw()
win:set(text)
end
-- this function will be called at the end of the capture run.
function tap.reset()
return td:reset()
end
end
local function create_tshark_tap(name, create)
local td, tap_filter, tap_type = create()
-- this tap will be local to the menu_function that called it
local tap = Listener.new(tap_type, tap_filter)
-- this function will be called for every packet
function tap.packet(pinfo,tvb,tapdata)
return td:packet(pinfo, tvb, tapdata)
end
-- this function will be called once every few seconds to redraw the window
function tap.draw()
local text = td:draw()
debug(name .. " results:\n" .. text)
end
-- this function will be called at the end of the capture run.
function tap.reset()
return td:reset()
end
end
return function (name, create)
if gui_enabled() then
-- menu callback.
local create_tap = function()
create_window_tap(name, create)
end
-- register menu item if running from wireshark
register_menu(name, create_tap, MENU_TOOLS_UNSORTED)
else
-- we are running from tshark, create a non-gui tap now.
create_tshark_tap(name, create)
end
end

@ -1,268 +1,69 @@
-- Copyright (c) 2011 by Robert G. Jakabosky <bobby@sharedrealm.com>
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-- THE SOFTWARE.
-- make generated variable nicer.
set_variable_format "%s%d"
c_module "zmq" {
-- module settings.
module_globals = true, -- support old code that doesn't do: local zmq = require"zmq"
use_globals = false,
hide_meta_info = true,
luajit_ffi = true,
-- needed for functions exported from module.
luajit_ffi_load_cmodule = true,
ffi_load {
"zmq", -- default lib name.
Windows = "libzmq", -- lib name for on windows.
},
sys_include "string.h",
include "zmq.h",
c_source "typedefs" [[
/* detect zmq version */
#define VERSION_2_0 1
#define VERSION_2_1 0
#define VERSION_2_2 0
#define VERSION_3_0 0
#define VERSION_3_2 0
#define VERSION_4_0 0
#if defined(ZMQ_VERSION_MAJOR)
# if (ZMQ_VERSION_MAJOR == 2) && (ZMQ_VERSION_MINOR == 2)
# undef VERSION_2_2
# define VERSION_2_2 1
# undef VERSION_2_1
# define VERSION_2_1 1
# endif
# if (ZMQ_VERSION_MAJOR == 2) && (ZMQ_VERSION_MINOR == 1)
# undef VERSION_2_1
# define VERSION_2_1 1
# endif
# if (ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR == 3)
# undef VERSION_2_0
# define VERSION_2_0 0
# undef VERSION_3_2
# define VERSION_3_2 1
# undef VERSION_3_0
# define VERSION_3_0 1
# endif
# if (ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR == 2)
# undef VERSION_2_0
# define VERSION_2_0 0
# undef VERSION_3_2
# define VERSION_3_2 1
# undef VERSION_3_0
# define VERSION_3_0 1
# endif
# if (ZMQ_VERSION_MAJOR == 3)
# undef VERSION_2_0
# define VERSION_2_0 0
# undef VERSION_3_0
# define VERSION_3_0 1
# endif
# if (ZMQ_VERSION_MAJOR == 4)
# undef VERSION_2_0
# define VERSION_2_0 0
# undef VERSION_3_2
# define VERSION_3_2 0
# undef VERSION_3_0
# define VERSION_3_0 0
# undef VERSION_4_0
# define VERSION_4_0 1
# endif
#endif
/* make sure ZMQ_DONTWAIT & ZMQ_NOBLOCK are both defined. */
#ifndef ZMQ_DONTWAIT
# define ZMQ_DONTWAIT ZMQ_NOBLOCK
#endif
#ifndef ZMQ_NOBLOCK
# define ZMQ_NOBLOCK ZMQ_DONTWAIT
#endif
/* make sure DEALER/ROUTER & XREQ/XREP are all defined. */
#ifndef ZMQ_DEALER
# define ZMQ_DEALER ZMQ_XREQ
#endif
#ifndef ZMQ_ROUTER
# define ZMQ_ROUTER ZMQ_XREP
#endif
#ifndef ZMQ_XREQ
# define ZMQ_XREQ ZMQ_DEALER
#endif
#ifndef ZMQ_XREP
# define ZMQ_XREP ZMQ_ROUTER
#endif
#if VERSION_2_0
# define ZMQ_POLL_MSEC 1000 // zmq_poll is usec
#elif VERSION_3_0 || VERSION_4_0
# define ZMQ_POLL_MSEC 1 // zmq_poll is msec
# ifndef ZMQ_HWM
# define ZMQ_HWM 1 // backwards compatibility
# endif
#endif
]],
--
-- Module constants
--
export_definitions {
MAX_VSM_SIZE = "ZMQ_MAX_VSM_SIZE",
-- context settings
MAX_SOCKETS = "ZMQ_MAX_SOCKETS",
IO_THREADS = "ZMQ_IO_THREADS",
const "MAX_VSM_SIZE" { 30 },
-- message types
DELIMITER = "ZMQ_DELIMITER",
VSM = "ZMQ_VSM",
const "DELIMITER" { 31 },
const "VSM" { 32 },
-- message flags
MSG_MORE = "ZMQ_MSG_MORE",
MSG_SHARED = "ZMQ_MSG_SHARED",
const "MSG_MORE" { 1 },
const "MSG_SHARED" { 128 },
-- socket types
PAIR = "ZMQ_PAIR",
PUB = "ZMQ_PUB",
SUB = "ZMQ_SUB",
REQ = "ZMQ_REQ",
REP = "ZMQ_REP",
PULL = "ZMQ_PULL",
PUSH = "ZMQ_PUSH",
DEALER = "ZMQ_DEALER",
ROUTER = "ZMQ_ROUTER",
XREQ = "ZMQ_XREQ",
XREP = "ZMQ_XREP",
-- new 3.1 socket types
XPUB = "ZMQ_XPUB",
XSUB = "ZMQ_XSUB",
const "PAIR" { 0 },
const "PUB" { 1 },
const "SUB" { 2 },
const "REQ" { 3 },
const "REP" { 4 },
const "XREQ" { 5 },
const "XREP" { 6 },
const "PULL" { 7 },
const "PUSH" { 8 },
-- socket options
HWM = "ZMQ_HWM",
SWAP = "ZMQ_SWAP",
AFFINITY = "ZMQ_AFFINITY",
IDENTITY = "ZMQ_IDENTITY",
SUBSCRIBE = "ZMQ_SUBSCRIBE",
UNSUBSCRIBE = "ZMQ_UNSUBSCRIBE",
RATE = "ZMQ_RATE",
RECOVERY_IVL = "ZMQ_RECOVERY_IVL",
MCAST_LOOP = "ZMQ_MCAST_LOOP",
SNDBUF = "ZMQ_SNDBUF",
RCVBUF = "ZMQ_RCVBUF",
RCVMORE = "ZMQ_RCVMORE",
FD = "ZMQ_FD",
EVENTS = "ZMQ_EVENTS",
TYPE = "ZMQ_TYPE",
LINGER = "ZMQ_LINGER",
RECONNECT_IVL = "ZMQ_RECONNECT_IVL",
RECONNECT_IVL_MSEC= "ZMQ_RECONNECT_IVL_MSEC",
BACKLOG = "ZMQ_BACKLOG",
RECONNECT_IVL_MAX = "ZMQ_RECONNECT_IVL_MAX",
MAXMSGSIZE = "ZMQ_MAXMSGSIZE",
SNDHWM = "ZMQ_SNDHWM",
RCVHWM = "ZMQ_RCVHWM",
MULTICAST_HOPS = "ZMQ_MULTICAST_HOPS",
RCVTIMEO = "ZMQ_RCVTIMEO",
SNDTIMEO = "ZMQ_SNDTIMEO",
RCVLABEL = "ZMQ_RCVLABEL",
LAST_ENDPOINT = "ZMQ_LAST_ENDPOINT",
ROUTER_MANDATORY = "ZMQ_ROUTER_MANDATORY",
TCP_KEEPALIVE = "ZMQ_TCP_KEEPALIVE",
TCP_KEEPALIVE_CNT = "ZMQ_TCP_KEEPALIVE_CNT",
TCP_KEEPALIVE_IDLE= "ZMQ_TCP_KEEPALIVE_IDLE",
TCP_KEEPALIVE_INTVL= "ZMQ_TCP_KEEPALIVE_INTVL",
TCP_ACCEPT_FILTER = "ZMQ_TCP_ACCEPT_FILTER",
IMMEDIATE = "ZMQ_IMMEDIATE",
XPUB_VERBOSE = "ZMQ_XPUB_VERBOSE",
ROUTER_RAW = "ZMQ_ROUTER_RAW",
IPV6 = "ZMQ_IPV6",
MECHANISM = "ZMQ_MECHANISM",
PLAIN_SERVER = "ZMQ_PLAIN_SERVER",
PLAIN_USERNAME = "ZMQ_PLAIN_USERNAME",
PLAIN_PASSWORD = "ZMQ_PLAIN_PASSWORD",
CURVE_SERVER = "ZMQ_CURVE_SERVER",
CURVE_PUBLICKEY = "ZMQ_CURVE_PUBLICKEY",
CURVE_SECRETKEY = "ZMQ_CURVE_SECRETKEY",
CURVE_SERVERKEY = "ZMQ_CURVE_SERVERKEY",
PROBE_ROUTER = "ZMQ_PROBE_ROUTER",
REQ_CORRELATE = "ZMQ_REQ_CORRELATE",
REQ_RELAXED = "ZMQ_REQ_RELAXED",
CONFLATE = "ZMQ_CONFLATE",
ZAP_DOMAIN = "ZMQ_ZAP_DOMAIN",
const "HWM" { 1 },
const "SWAP" { 3 },
const "AFFINITY" { 4 },
const "IDENTITY" { 5 },
const "SUBSCRIBE" { 6 },
const "UNSUBSCRIBE" { 7 },
const "RATE" { 8 },
const "RECOVERY_IVL" { 9 },
const "MCAST_LOOP" { 10 },
const "SNDBUF" { 11 },
const "RCVBUF" { 12 },
const "RCVMORE" { 13 },
const "FD" { 14 },
const "EVENTS" { 15 },
const "TYPE" { 16 },
const "LINGER" { 17 },
const "RECONNECT_IVL" { 18 },
const "BACKLOG" { 19 },
-- send/recv flags
NOBLOCK = "ZMQ_NOBLOCK",
DONTWAIT = "ZMQ_DONTWAIT",
SNDMORE = "ZMQ_SNDMORE",
SNDLABEL = "ZMQ_SNDLABEL",
-- Security mechanisms
NULL = "ZMQ_NULL",
PLAIN = "ZMQ_PLAIN",
CURVE = "ZMQ_CURVE",
const "NOBLOCK" { 1 },
const "SNDMORE" { 2 },
-- poll events
POLLIN = "ZMQ_POLLIN",
POLLOUT = "ZMQ_POLLOUT",
POLLERR = "ZMQ_POLLERR",
-- poll milliseconds.
POLL_MSEC = "ZMQ_POLL_MSEC",
-- Socket Monitor events.
EVENT_CONNECTED = "ZMQ_EVENT_CONNECTED",
EVENT_CONNECT_DELAYED = "ZMQ_EVENT_CONNECT_DELAYED",
EVENT_CONNECT_RETRIED = "ZMQ_EVENT_CONNECT_RETRIED",
EVENT_LISTENING = "ZMQ_EVENT_LISTENING",
EVENT_BIND_FAILED = "ZMQ_EVENT_BIND_FAILED",
EVENT_ACCEPTED = "ZMQ_EVENT_ACCEPTED",
EVENT_ACCEPT_FAILED= "ZMQ_EVENT_ACCEPT_FAILED",
EVENT_CLOSED = "ZMQ_EVENT_CLOSED",
EVENT_CLOSE_FAILED= "ZMQ_EVENT_CLOSE_FAILED",
EVENT_DISCONNECTED= "ZMQ_EVENT_DISCONNECTED",
EVENT_MONITOR_STOPPED = "ZMQ_EVENT_MONITOR_STOPPED",
EVENT_ALL = "ZMQ_EVENT_ALL",
const "POLLIN" { 1 },
const "POLLOUT" { 2 },
const "POLLERR" { 4 },
-- devices
STREAMER = "ZMQ_STREAMER",
FORWARDER = "ZMQ_FORWARDER",
QUEUE = "ZMQ_QUEUE",
},
subfiles {
"src/error.nobj.lua",
"src/msg.nobj.lua",
"src/socket.nobj.lua",
"src/poller.nobj.lua",
"src/ctx.nobj.lua",
"src/stopwatch.nobj.lua",
},
const "STREAMER" { 1 },
const "FORWARDER" { 2 },
const "QUEUE" { 3 },
--
-- Module static functions
@ -281,50 +82,27 @@ c_function "version" {
lua_rawseti(L, -2, 2);
lua_pushinteger(L, patch);
lua_rawseti(L, -2, 3);
]],
]]
},
c_function "init" {
var_in{ "int", "io_threads?", default = "1" },
c_call "!ZMQ_Ctx *" "zmq_init" { "int", "io_threads" },
},
c_function "init_ctx" {
var_in{ "<any>", "ptr" },
var_out{ "ZMQ_Ctx *", "ctx" },
var_in{ "int", "io_threads" },
var_out{ "ZMQ_Ctx", "ctx", own = true },
var_out{ "ZMQ_Error", "err"},
c_source[[
if(lua_isuserdata(L, ${ptr::idx})) {
${ctx} = lua_touserdata(L, ${ptr::idx});
} else {
return luaL_argerror(L, ${ptr::idx}, "expected lightuserdata");
}
]],
ffi_source[[
local p_type = type(${ptr})
if p_type == 'userdata' then
${ctx} = ffi.cast('ZMQ_Ctx *', ${ptr});
elseif p_type == 'cdata' and ffi.istype('void *', ${ptr}) then
${ctx} = ffi.cast('ZMQ_Ctx *', ${ptr});
else
return error("expected lightuserdata/cdata<void *>");
end
]],
${ctx} = zmq_init(${io_threads});
if(${ctx} == NULL) ${err} = -1;
]]
},
c_function "device" { if_defs = { "VERSION_2_0", "VERSION_3_2" },
c_function "device" {
c_call "ZMQ_Error" "zmq_device"
{ "int", "device", "ZMQ_Socket *", "insock", "ZMQ_Socket *", "outsock" },
},
c_function "proxy" { if_defs = "VERSION_3_2",
c_call "ZMQ_Error" "zmq_proxy"
{ "ZMQ_Socket *", "frontend", "ZMQ_Socket *", "backend", "ZMQ_Socket *", "capture?" },
{ "int", "device", "ZMQ_Socket", "insock", "ZMQ_Socket", "outsock" },
},
--
-- utils
--
c_function "stopwatch_start" {
c_call "!ZMQ_StopWatch *" "zmq_stopwatch_start" {},
},
c_function "sleep" {
c_call "void" "zmq_sleep" { "int", "seconds_" },
subfiles {
"src/zmq_ffi.nobj.lua",
"src/error.nobj.lua",
"src/ctx.nobj.lua",
"src/socket.nobj.lua",
},
}

@ -0,0 +1,348 @@
--[[
--
-- This is just an normal LuaJIT2 FFI based bindings for zmq.
-- It is only for testing and comparison.
--
--]]
local setmetatable = setmetatable
local print = print
local pairs = pairs
local error = error
local type = type
local assert = assert
local tostring = tostring
local tonumber = tonumber
local zmq = {
MAX_VSM_SIZE = 30,
-- message types
DELIMITER = 31,
VSM = 32,
-- message flags
MSG_MORE = 1,
MSG_SHARED = 128,
-- socket types
PAIR = 0,
PUB = 1,
SUB = 2,
REQ = 3,
REP = 4,
XREQ = 5,
XREP = 6,
PULL = 7,
PUSH = 8,
-- socket options
HWM = 1,
SWAP = 3,
AFFINITY = 4,
IDENTITY = 5,
SUBSCRIBE = 6,
UNSUBSCRIBE = 7,
RATE = 8,
RECOVERY_IVL = 9,
MCAST_LOOP = 10,
SNDBUF = 11,
RCVBUF = 12,
RCVMORE = 13,
FD = 14,
EVENTS = 15,
TYPE = 16,
LINGER = 17,
RECONNECT_IVL = 18,
BACKLOG = 19,
-- send/recv flags
NOBLOCK = 1,
SNDMORE = 2,
-- poll events
POLLIN = 1,
POLLOUT = 2,
POLLERR = 4,
-- devices
STREAMER = 1,
FORWARDER = 2,
QUEUE = 3,
}
local z_SUBSCRIBE = zmq.SUBSCRIBE
local z_UNSUBSCRIBE = zmq.UNSUBSCRIBE
local z_IDENTITY = zmq.IDENTITY
local z_NOBLOCK = zmq.NOBLOCK
local z_RCVMORE = zmq.RCVMORE
local z_SNDMORE = zmq.SNDMORE
local z_EVENTS = zmq.EVENTS
local z_POLLIN = zmq.POLLIN
local z_POLLOUT = zmq.POLLOUT
local z_POLLIN_OUT = z_POLLIN + z_POLLOUT
local ffi=require"ffi"
ffi.cdef[[
void zmq_version (int *major, int *minor, int *patch);
int zmq_errno ();
const char *zmq_strerror (int errnum);
typedef struct zmq_msg_t
{
void *content;
unsigned char flags;
unsigned char vsm_size;
unsigned char vsm_data [30];
} zmq_msg_t;
typedef void (zmq_free_fn) (void *data, void *hint);
int zmq_msg_init (zmq_msg_t *msg);
int zmq_msg_init_size (zmq_msg_t *msg, size_t size);
int zmq_msg_init_data (zmq_msg_t *msg, void *data, size_t size, zmq_free_fn *ffn, void *hint);
int zmq_msg_close (zmq_msg_t *msg);
int zmq_msg_move (zmq_msg_t *dest, zmq_msg_t *src);
int zmq_msg_copy (zmq_msg_t *dest, zmq_msg_t *src);
void *zmq_msg_data (zmq_msg_t *msg);
size_t zmq_msg_size (zmq_msg_t *msg);
void *zmq_init (int io_threads);
int zmq_term (void *context);
void *zmq_socket (void *context, int type);
int zmq_close (void *s);
int zmq_setsockopt (void *s, int option, const void *optval, size_t optvallen);
int zmq_getsockopt (void *s, int option, void *optval, size_t *optvallen);
int zmq_bind (void *s, const char *addr);
int zmq_connect (void *s, const char *addr);
int zmq_send (void *s, zmq_msg_t *msg, int flags);
int zmq_recv (void *s, zmq_msg_t *msg, int flags);
int zmq_device (int device, void * insocket, void* outsocket);
]]
require"utils"
local c_zmq = ffi.load"zmq"
module(...)
-- copy constants
for k,v in pairs(zmq) do
-- only copy upper-case string values.
if type(k) == 'string' and k == k:upper() then
_M[k] = v
end
end
function version()
local major = ffi.new('int[1]',0)
local minor = ffi.new('int[1]',0)
local patch = ffi.new('int[1]',0)
c_zmq.zmq_version(major, minor, patch)
return {major[0], minor[0], patch[0]}
end
local function zmq_error()
local errno = c_zmq.zmq_errno()
local err = ffi.string(c_zmq.zmq_strerror(errno))
if err == "Resource temporarily unavailable" then err = "timeout" end
if err == "Context was terminated" then err = "closed" end
return nil, err
end
--
-- ZMQ socket
--
local sock_mt = {}
sock_mt.__index = sock_mt
local function new_socket(ctx, sock_type)
local sock = c_zmq.zmq_socket(ctx, sock_type)
if not sock then
return zmq_error()
end
return setmetatable({ sock = sock }, sock_mt)
end
function sock_mt:close()
local ret = c_zmq.zmq_close(self.sock)
self.sock = nil
if ret ~= 0 then
return zmq_error()
end
return true
end
local option_types = {
[zmq.HWM] = 'uint64_t[1]',
[zmq.SWAP] = 'int64_t[1]',
[zmq.AFFINITY] = 'uint64_t[1]',
[zmq.IDENTITY] = 'string',
[zmq.SUBSCRIBE] = 'string',
[zmq.UNSUBSCRIBE] = 'string',
[zmq.RATE] = 'int64_t[1]',
[zmq.RECOVERY_IVL] = 'int64_t[1]',
[zmq.MCAST_LOOP] = 'int64_t[1]',
[zmq.SNDBUF] = 'uint64_t[1]',
[zmq.RCVBUF] = 'uint64_t[1]',
[zmq.RCVMORE] = 'int64_t[1]',
[zmq.FD] = 'int[1]',
[zmq.EVENTS] = 'uint32_t[1]',
[zmq.TYPE] = 'int[1]',
[zmq.LINGER] = 'int[1]',
[zmq.RECONNECT_IVL] = 'int[1]',
[zmq.BACKLOG] = 'int[1]',
}
local option_len = {}
local option_tmps = {}
for k,v in pairs(option_types) do
if v ~= 'string' then
option_len[k] = ffi.sizeof(v)
option_tmps[k] = ffi.new(v, 0)
end
end
function sock_mt:setopt(opt, opt_val)
local ctype = option_types[opt]
local val_len = 0
if ctype == 'string' then
--val = ffi.cast('void *', tostring(val))
val = tostring(opt_val)
val_len = #val
else
val = option_tmps[opt]
val[0] = opt_val
val_len = option_len[opt]
end
local ret = c_zmq.zmq_setsockopt(self.sock, opt, val, val_len)
if ret ~= 0 then
return zmq_error()
end
return true
end
local tmp_val_len = ffi.new('size_t[1]', 4)
function sock_mt:getopt(opt)
local ctype = option_types[opt]
local val
local val_len = tmp_val_len
if ctype == 'string' then
val_len[0] = 255
val = ffi.new('uint8_t[?]', val_len[0])
ffi.fill(val, val_len[0])
else
val = option_tmps[opt]
val[0] = 0
val_len[0] = option_len[opt]
end
local ret = c_zmq.zmq_getsockopt(self.sock, opt, val, val_len)
if ret ~= 0 then
return zmq_error()
end
if ctype == 'string' then
val_len = val_len[0]
return ffi.string(val, val_len)
else
val = val[0]
end
return tonumber(val)
end
local tmp32 = ffi.new('uint32_t[1]', 0)
local tmp32_len = ffi.new('size_t[1]', 4)
function sock_mt:events()
local val = tmp32
local val_len = tmp32_len
val[0] = 0
val_len[0] = 4
local ret = c_zmq.zmq_getsockopt(self.sock, 15, val, val_len)
if ret ~= 0 then
return zmq_error()
end
return val[0]
end
function sock_mt:bind(addr)
local ret = c_zmq.zmq_bind(self.sock, addr)
if ret ~= 0 then
return zmq_error()
end
return true
end
function sock_mt:connect(addr)
local ret = c_zmq.zmq_connect(self.sock, addr)
if ret ~= 0 then
return zmq_error()
end
return true
end
local tmp_msg = ffi.new('zmq_msg_t')
function sock_mt:send(data, flags)
local msg = tmp_msg
local msg_len = #data
-- initialize message
if c_zmq.zmq_msg_init_size(msg, msg_len) < 0 then
return zmq_error()
end
-- copy data into message.
ffi.copy(c_zmq.zmq_msg_data(msg), data, msg_len)
-- send message
local ret = c_zmq.zmq_send(self.sock, msg, flags or 0)
-- close message before processing return code
c_zmq.zmq_msg_close(msg)
-- now process send return code
if ret ~= 0 then
return zmq_error()
end
return true
end
function sock_mt:recv(flags)
local msg = tmp_msg
-- initialize blank message.
if c_zmq.zmq_msg_init(msg) < 0 then
return zmq_error()
end
-- receive message
local ret = c_zmq.zmq_recv(self.sock, msg, flags or 0)
if ret ~= 0 then
local data, err = zmq_error()
c_zmq.zmq_msg_close(msg)
return data, err
end
local data = ffi.string(c_zmq.zmq_msg_data(msg), c_zmq.zmq_msg_size(msg))
-- close message
c_zmq.zmq_msg_close(msg)
return data
end
--
-- ZMQ context
--
local ctx_mt = {}
ctx_mt.__index = ctx_mt
function ctx_mt:term()
if c_zmq.zmq_term(self.ctx) ~= 0 then
return zmq_error()
end
return true
end
function ctx_mt:socket(sock_type)
return new_socket(self.ctx, sock_type)
end
function init(io_threads)
local ctx = c_zmq.zmq_init(io_threads)
if not ctx then
return zmq_error()
end
return setmetatable({ ctx = ctx }, ctx_mt)
end
Loading…
Cancel
Save