diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100755 index 0000000..55f3872 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,63 @@ +# +# Lua bindings for 0MQ +# +cmake_minimum_required(VERSION 2.8) + +project(lua-zmq C) + +set(BUILD_SHARED_LIBS TRUE) + +set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) + +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.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}") + +## LibZMQ +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}") + +## LuaNativeObjects +include(LuaNativeObjects) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ${LUA_INCLUDE_DIR}) + +## LuaZMQ +set(LUA_ZMQ_SRC + zmq.nobj.lua +) + +if(${USE_PRE_GENERATED_BINDINGS}) + set(LUA_ZMQ_SRC pre_generated-zmq.nobj.c) +else() + # Generate Lua bindings. + GenLuaNativeObjects(LUA_ZMQ_SRC) +endif() + +add_library(lua-zmq MODULE ${LUA_ZMQ_SRC}) +target_link_libraries(lua-zmq ${COMMON_LIBS}) +set_target_properties(lua-zmq PROPERTIES PREFIX "") +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}") + diff --git a/Makefile b/Makefile deleted file mode 100644 index 65425b4..0000000 --- a/Makefile +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright (c) 2010 Aleksey Yeschenko -# -# 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. - -CC = gcc -CFLAGS = `pkg-config lua5.1 --cflags` -fPIC -O3 -Wall -LFLAGS = -shared `pkg-config --libs --cflags libzmq` -INSTALL_PATH = `pkg-config lua5.1 --variable=INSTALL_CMOD` - - -all: zmq.so - - -zmq.lo: zmq.c - $(CC) -o zmq.lo -c $(CFLAGS) zmq.c - - -zmq.so: zmq.lo - $(CC) -o zmq.so $(LFLAGS) zmq.lo - - -install: zmq.so - install -D -s zmq.so $(INSTALL_PATH)/zmq.so - - -clean: - rm -f zmq.so zmq.lo diff --git a/cmake/LuaNativeObjects.cmake b/cmake/LuaNativeObjects.cmake new file mode 100644 index 0000000..a1b0e2d --- /dev/null +++ b/cmake/LuaNativeObjects.cmake @@ -0,0 +1,24 @@ +# +# Lua Native Objects +# +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.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(${_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}) + endif(_src_file MATCHES ".nobj.lua") + endforeach(_src_file) + set(${_src_files_var} ${_new_src_files}) +endmacro(GenLuaNativeObjects _src_files_var) + diff --git a/ctx.nobj.lua b/ctx.nobj.lua new file mode 100644 index 0000000..6f230e6 --- /dev/null +++ b/ctx.nobj.lua @@ -0,0 +1,38 @@ +-- Copyright (c) 2010 by Robert G. Jakabosky +-- +-- 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_Ctx" { + c_source [[ +typedef void * ZMQ_Ctx; +]], + destructor "term" { + c_call "ZMQ_Error" "zmq_term" {} + }, + method "socket" { + var_in{ "int", "type" }, + var_out{ "ZMQ_Socket", "sock", own = true }, + var_out{ "ZMQ_Error", "err"}, + c_source[[ + ${sock} = zmq_socket(${this}, ${type}); + if(${sock} == NULL) ${err} = -1; +]] + }, +} + diff --git a/error.nobj.lua b/error.nobj.lua new file mode 100644 index 0000000..80a4629 --- /dev/null +++ b/error.nobj.lua @@ -0,0 +1,42 @@ +-- Copyright (c) 2010 by Robert G. Jakabosky +-- +-- 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. + +-- 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 [[ + if(err != 0) { + err = zmq_errno(); + switch(err) { + case EAGAIN: + err_str = "timeout"; + break; + case ETERM: + err_str = "closed"; + break; + default: + err_str = zmq_strerror(err); + break; + } + } +]], +} + diff --git a/socket.nobj.lua b/socket.nobj.lua new file mode 100644 index 0000000..3eef790 --- /dev/null +++ b/socket.nobj.lua @@ -0,0 +1,264 @@ +-- Copyright (c) 2010 by Robert G. Jakabosky +-- +-- 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_Socket" { + c_source [[ +/* detect zmq version >= 2.1.0 */ +#define VERSION_2_1 0 +#if defined(ZMQ_VERSION) +#if (ZMQ_VERSION >= ZMQ_MAKE_VERSION(2,1,0)) +#undef VERSION_2_1 +#define VERSION_2_1 1 +#endif +#endif + +typedef void * ZMQ_Socket; + +#if VERSION_2_1 +#ifdef _WIN32 +#include +typedef SOCKET socket_t; +#else +typedef int socket_t; +#endif +#endif + +/* socket option types. */ +#define OPT_TYPE_NONE 0 +#define OPT_TYPE_INT 1 +#define OPT_TYPE_UINT32 2 +#define OPT_TYPE_UINT64 3 +#define OPT_TYPE_INT64 4 +#define OPT_TYPE_STR 5 +#define OPT_TYPE_FD 6 + +static const int opt_types[] = { + OPT_TYPE_NONE, /* unused */ + OPT_TYPE_UINT64, /* ZMQ_HWM */ + OPT_TYPE_INT64, /* ZMQ_SWAP */ + OPT_TYPE_UINT64, /* ZMQ_AFFINITY */ + OPT_TYPE_STR, /* ZMQ_IDENTITY */ + OPT_TYPE_STR, /* ZMQ_SUBSCRIBE */ + OPT_TYPE_STR, /* ZMQ_UNSUBSCRIBE */ + OPT_TYPE_INT64, /* ZMQ_RATE */ + OPT_TYPE_INT64, /* ZMQ_RECOVERY_IVL */ + OPT_TYPE_INT64, /* ZMQ_MCAST_LOOP */ + OPT_TYPE_UINT64, /* ZMQ_SNDBUF */ + OPT_TYPE_UINT64, /* ZMQ_RCVBUF */ + OPT_TYPE_INT64, /* ZMQ_RCVMORE */ + +#if VERSION_2_1 + OPT_TYPE_FD, /* ZMQ_FD */ + OPT_TYPE_UINT32, /* ZMQ_EVENTS */ + OPT_TYPE_INT, /* ZMQ_TYPE */ + OPT_TYPE_INT, /* ZMQ_LINGER */ + OPT_TYPE_INT, /* ZMQ_RECONNECT_IVL */ + OPT_TYPE_INT, /* ZMQ_BACKLOG */ +#endif +}; +#define MAX_OPTS ZMQ_BACKLOG + +]], + + destructor "close" { + c_call "ZMQ_Error" "zmq_close" {} + }, + method "bind" { + c_call "ZMQ_Error" "zmq_bind" { "const char *", "addr" } + }, + method "connect" { + c_call "ZMQ_Error" "zmq_connect" { "const char *", "addr" } + }, + method "setopt" { + var_in{ "uint32_t", "opt" }, + var_in{ "", "val" }, + var_out{ "ZMQ_Error", "err" }, + c_source[[ + size_t val_len; + const void *val; + + socket_t fd_val; + int int_val; + uint32_t uint32_val; + uint64_t uint64_val; + int64_t int64_val; + + if(${opt} > MAX_OPTS) { + return luaL_argerror(L, ${opt::idx}, "Invalid socket option."); + } + + switch(opt_types[${opt}]) { + case OPT_TYPE_FD: + fd_val = luaL_checklong(L, ${val::idx}); + val = &fd_val; + val_len = sizeof(fd_val); + break; + case OPT_TYPE_INT: + int_val = luaL_checklong(L, ${val::idx}); + val = &int_val; + val_len = sizeof(int_val); + break; + case OPT_TYPE_UINT32: + uint32_val = luaL_checklong(L, ${val::idx}); + val = &uint32_val; + val_len = sizeof(uint32_val); + break; + case OPT_TYPE_UINT64: + uint64_val = luaL_checklong(L, ${val::idx}); + val = &uint64_val; + val_len = sizeof(uint64_val); + break; + case OPT_TYPE_INT64: + int64_val = luaL_checklong(L, ${val::idx}); + val = &int64_val; + val_len = sizeof(int64_val); + break; + case OPT_TYPE_STR: + val = luaL_checklstring(L, ${val::idx}, &(val_len)); + break; + default: + printf("Invalid socket option type, this shouldn't happen.\n"); + abort(); + break; + } + ${err} = zmq_setsockopt(${this}, ${opt}, val, val_len); +]] + }, + method "getopt" { + var_in{ "uint32_t", "opt" }, + var_out{ "", "val" }, + var_out{ "ZMQ_Error", "err" }, + c_source[[ + size_t val_len; + + socket_t fd_val; + int int_val; + uint32_t uint32_val; + uint64_t uint64_val; + int64_t int64_val; +#define STR_MAX 255 + char str_val[STR_MAX]; + + if(${opt} > MAX_OPTS) { + lua_pushnil(L); + lua_pushliteral(L, "Invalid socket option."); + return 2; + } + + switch(opt_types[${opt}]) { + case OPT_TYPE_FD: + val_len = sizeof(fd_val); + ${err} = zmq_getsockopt(${this}, ${opt}, &fd_val, &val_len); + if(0 == ${err}) { + lua_pushinteger(L, (lua_Integer)fd_val); + return 1; + } + break; + case OPT_TYPE_INT: + val_len = sizeof(int_val); + ${err} = zmq_getsockopt(${this}, ${opt}, &int_val, &val_len); + if(0 == ${err}) { + lua_pushinteger(L, (lua_Integer)int_val); + return 1; + } + break; + case OPT_TYPE_UINT32: + val_len = sizeof(uint32_val); + ${err} = zmq_getsockopt(${this}, ${opt}, &uint32_val, &val_len); + if(0 == ${err}) { + lua_pushinteger(L, (lua_Integer)uint32_val); + return 1; + } + break; + case OPT_TYPE_UINT64: + val_len = sizeof(uint64_val); + ${err} = zmq_getsockopt(${this}, ${opt}, &uint64_val, &val_len); + if(0 == ${err}) { + lua_pushinteger(L, (lua_Integer)uint64_val); + return 1; + } + break; + case OPT_TYPE_INT64: + val_len = sizeof(int64_val); + ${err} = zmq_getsockopt(${this}, ${opt}, &int64_val, &val_len); + if(0 == ${err}) { + lua_pushinteger(L, (lua_Integer)int64_val); + return 1; + } + break; + case OPT_TYPE_STR: + val_len = STR_MAX; + ${err} = zmq_getsockopt(${this}, ${opt}, str_val, &val_len); + if(0 == ${err}) { + lua_pushlstring(L, str_val, val_len); + return 1; + } +#undef STR_MAX + break; + default: + printf("Invalid socket option type, this shouldn't happen.\n"); + abort(); + break; + } + lua_pushnil(L); +]] + }, + method "send" { + var_in{ "const char *", "data" }, + var_in{ "int", "flags", is_optional = true }, + var_out{ "ZMQ_Error", "err" }, + c_source[[ + zmq_msg_t msg; + /* initialize message */ + ${err} = zmq_msg_init_size(&msg, ${data}_len); + if(0 == ${err}) { + /* fill message */ + memcpy(zmq_msg_data(&msg), ${data}, ${data}_len); + /* send message */ + ${err} = zmq_send(${this}, &msg, ${flags}); + /* close message */ + zmq_msg_close(&msg); + } +]] + }, + method "recv" { + var_in{ "int", "flags", is_optional = true }, + var_out{ "const char *", "data", has_length = true }, + var_out{ "ZMQ_Error", "err" }, + c_source[[ + zmq_msg_t msg; + /* initialize message */ + ${err} = zmq_msg_init(&msg); + if(0 == ${err}) { + /* receive message */ + ${err} = zmq_recv(${this}, &msg, ${flags}); + if(0 == ${err}) { + ${data} = zmq_msg_data(&msg); + ${data}_len = zmq_msg_size(&msg); + } + } +]], + c_source "post" [[ + /* close message */ + zmq_msg_close(&msg); +]] + }, +} + diff --git a/zmq.c b/zmq.c deleted file mode 100644 index ea09c61..0000000 --- a/zmq.c +++ /dev/null @@ -1,552 +0,0 @@ -/* - * Copyright (c) 2010 Aleksey Yeschenko - * - * 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. - */ - -#define LUA_LIB - -#include "lua.h" -#include "lauxlib.h" - -#include -#include -#include -#include - -/* detect zmq version >= 2.1.0 */ -#define VERSION_2_1 0 -#if defined(ZMQ_VERSION) -#if (ZMQ_VERSION >= ZMQ_MAKE_VERSION(2,1,0)) -#undef VERSION_2_1 -#define VERSION_2_1 1 -#endif -#endif - -#define MT_ZMQ_CONTEXT "MT_ZMQ_CONTEXT" -#define MT_ZMQ_SOCKET "MT_ZMQ_SOCKET" - -typedef struct { - void *ptr; - int should_free; -} zmq_ptr; - -static int Lzmq_version(lua_State *L) -{ - int major, minor, patch; - - zmq_version(&major, &minor, &patch); - - lua_createtable(L, 3, 0); - - lua_pushinteger(L, 1); - lua_pushinteger(L, major); - lua_settable(L, -3); - - lua_pushinteger(L, 2); - lua_pushinteger(L, minor); - lua_settable(L, -3); - - lua_pushinteger(L, 3); - lua_pushinteger(L, patch); - lua_settable(L, -3); - - return 1; -} - -static int Lzmq_push_error(lua_State *L) -{ - const char *error; - lua_pushnil(L); - switch(zmq_errno()) { - case EAGAIN: - lua_pushliteral(L, "timeout"); - break; - case ETERM: - lua_pushliteral(L, "closed"); - break; - default: - error = zmq_strerror(zmq_errno()); - lua_pushlstring(L, error, strlen(error)); - break; - } - return 2; -} - -static int Lzmq_init(lua_State *L) -{ - zmq_ptr *ctx = lua_newuserdata(L, sizeof(zmq_ptr)); - luaL_getmetatable(L, MT_ZMQ_CONTEXT); - lua_setmetatable(L, -2); - - if (lua_islightuserdata(L, 1)) { - // Treat a light userdata as a raw ZMQ context object, which - // we'll silently wrap. (And we won't automatically call term - // on it.) - - ctx->ptr = lua_touserdata(L, 1); - ctx->should_free = 0; - return 1; - } - - int io_threads = luaL_checkint(L, 1); - - ctx->ptr = zmq_init(io_threads); - - if (!ctx->ptr) { - return Lzmq_push_error(L); - } - - // toboolean defaults to false, but we want a missing param #2 - // to mean true - if (lua_isnil(L, 2)) { - ctx->should_free = 1; - } else { - ctx->should_free = lua_toboolean(L, 2); - } - - return 1; -} - -static int Lzmq_term(lua_State *L) -{ - zmq_ptr *ctx = luaL_checkudata(L, 1, MT_ZMQ_CONTEXT); - - if(ctx->ptr != NULL) { - if(zmq_term(ctx->ptr) == 0) { - ctx->ptr = NULL; - } else { - return Lzmq_push_error(L); - } - } - - lua_pushboolean(L, 1); - - return 1; -} - -static int Lzmq_ctx_gc(lua_State *L) -{ - zmq_ptr *ctx = luaL_checkudata(L, 1, MT_ZMQ_CONTEXT); - if (ctx->should_free) { - return Lzmq_term(L); - } else { - return 0; - } -} - -static int Lzmq_ctx_lightuserdata(lua_State *L) -{ - zmq_ptr *ctx = luaL_checkudata(L, 1, MT_ZMQ_CONTEXT); - lua_pushlightuserdata(L, ctx->ptr); - return 1; -} - -static int Lzmq_socket(lua_State *L) -{ - zmq_ptr *ctx = luaL_checkudata(L, 1, MT_ZMQ_CONTEXT); - int type = luaL_checkint(L, 2); - - zmq_ptr *s = lua_newuserdata(L, sizeof(zmq_ptr)); - - s->ptr = zmq_socket(ctx->ptr, type); - - if (!s->ptr) { - return Lzmq_push_error(L); - } - - luaL_getmetatable(L, MT_ZMQ_SOCKET); - lua_setmetatable(L, -2); - - return 1; -} - -static int Lzmq_close(lua_State *L) -{ - zmq_ptr *s = luaL_checkudata(L, 1, MT_ZMQ_SOCKET); - - if(s->ptr != NULL) { - if(zmq_close(s->ptr) == 0) { - s->ptr = NULL; - } else { - return Lzmq_push_error(L); - } - } - - lua_pushboolean(L, 1); - - return 1; -} - -#if VERSION_2_1 -#ifdef _WIN32 -#include -typedef SOCKET socket_t; -#else -typedef int socket_t; -#endif -#endif - -static int Lzmq_setsockopt(lua_State *L) -{ - zmq_ptr *s = luaL_checkudata(L, 1, MT_ZMQ_SOCKET); - int option = luaL_checkint(L, 2); - - int rc = 0; - - switch (option) { -#if VERSION_2_1 - case ZMQ_FD: - { - socket_t optval = (socket_t) luaL_checklong(L, 3); - rc = zmq_setsockopt(s->ptr, option, (void *) &optval, sizeof(socket_t)); - } - break; - case ZMQ_EVENTS: - { - int32_t optval = (int32_t) luaL_checklong(L, 3); - rc = zmq_setsockopt(s->ptr, option, (void *) &optval, sizeof(int32_t)); - } - break; - case ZMQ_TYPE: - case ZMQ_LINGER: - case ZMQ_RECONNECT_IVL: - case ZMQ_BACKLOG: - { - int optval = (int) luaL_checklong(L, 3); - rc = zmq_setsockopt(s->ptr, option, (void *) &optval, sizeof(int)); - } - break; -#endif - case ZMQ_SWAP: - case ZMQ_RATE: - case ZMQ_RECOVERY_IVL: - case ZMQ_MCAST_LOOP: - { - int64_t optval = (int64_t) luaL_checklong(L, 3); - rc = zmq_setsockopt(s->ptr, option, (void *) &optval, sizeof(int64_t)); - } - break; - case ZMQ_IDENTITY: - case ZMQ_SUBSCRIBE: - case ZMQ_UNSUBSCRIBE: - { - size_t optvallen; - const char *optval = luaL_checklstring(L, 3, &optvallen); - rc = zmq_setsockopt(s->ptr, option, (void *) optval, optvallen); - } - break; - case ZMQ_HWM: - case ZMQ_AFFINITY: - case ZMQ_SNDBUF: - case ZMQ_RCVBUF: - { - uint64_t optval = (uint64_t) luaL_checklong(L, 3); - rc = zmq_setsockopt(s->ptr, option, (void *) &optval, sizeof(uint64_t)); - } - break; - default: - rc = -1; - errno = EINVAL; - } - - if (rc != 0) { - return Lzmq_push_error(L); - } - - lua_pushboolean(L, 1); - - return 1; -} - -static int Lzmq_getsockopt(lua_State *L) -{ - zmq_ptr *s = luaL_checkudata(L, 1, MT_ZMQ_SOCKET); - int option = luaL_checkint(L, 2); - - size_t optvallen; - - int rc = 0; - - switch (option) { -#if VERSION_2_1 - case ZMQ_FD: - { - socket_t optval; - optvallen = sizeof(socket_t); - rc = zmq_getsockopt(s->ptr, option, (void *) &optval, &optvallen); - if (rc == 0) { - lua_pushinteger(L, (lua_Integer) optval); - return 1; - } - } - break; - case ZMQ_EVENTS: - { - int32_t optval; - optvallen = sizeof(int32_t); - rc = zmq_getsockopt(s->ptr, option, (void *) &optval, &optvallen); - if (rc == 0) { - lua_pushinteger(L, (lua_Integer) optval); - return 1; - } - } - break; - case ZMQ_TYPE: - case ZMQ_LINGER: - case ZMQ_RECONNECT_IVL: - case ZMQ_BACKLOG: - { - int optval; - optvallen = sizeof(int); - rc = zmq_getsockopt(s->ptr, option, (void *) &optval, &optvallen); - if (rc == 0) { - lua_pushinteger(L, (lua_Integer) optval); - return 1; - } - } - break; -#endif - case ZMQ_SWAP: - case ZMQ_RATE: - case ZMQ_RECOVERY_IVL: - case ZMQ_MCAST_LOOP: - case ZMQ_RCVMORE: - { - int64_t optval; - optvallen = sizeof(int64_t); - rc = zmq_getsockopt(s->ptr, option, (void *) &optval, &optvallen); - if (rc == 0) { - lua_pushinteger(L, (lua_Integer) optval); - return 1; - } - } - break; - case ZMQ_IDENTITY: - { - char id[256]; - memset((void *)id, '\0', 256); - optvallen = 256; - rc = zmq_getsockopt(s->ptr, option, (void *)id, &optvallen); - id[255] = '\0'; - if (rc == 0) { - lua_pushstring(L, id); - return 1; - } - } - break; - case ZMQ_HWM: - case ZMQ_AFFINITY: - case ZMQ_SNDBUF: - case ZMQ_RCVBUF: - { - uint64_t optval; - optvallen = sizeof(uint64_t); - rc = zmq_getsockopt(s->ptr, option, (void *) &optval, &optvallen); - if (rc == 0) { - lua_pushinteger(L, (lua_Integer) optval); - return 1; - } - } - break; - default: - rc = -1; - errno = EINVAL; - } - - if (rc != 0) { - return Lzmq_push_error(L); - } - - lua_pushboolean(L, 1); - - return 1; -} - -static int Lzmq_bind(lua_State *L) -{ - zmq_ptr *s = luaL_checkudata(L, 1, MT_ZMQ_SOCKET); - const char *addr = luaL_checkstring(L, 2); - - if (zmq_bind(s->ptr, addr) != 0) { - return Lzmq_push_error(L); - } - - lua_pushboolean(L, 1); - - return 1; -} - -static int Lzmq_connect(lua_State *L) -{ - zmq_ptr *s = luaL_checkudata(L, 1, MT_ZMQ_SOCKET); - const char *addr = luaL_checkstring(L, 2); - - if (zmq_connect(s->ptr, addr) != 0) { - return Lzmq_push_error(L); - } - - lua_pushboolean(L, 1); - - return 1; -} - -static int Lzmq_send(lua_State *L) -{ - zmq_ptr *s = luaL_checkudata(L, 1, MT_ZMQ_SOCKET); - size_t msg_size; - const char *data = luaL_checklstring(L, 2, &msg_size); - int flags = luaL_optint(L, 3, 0); - - zmq_msg_t msg; - if(zmq_msg_init_size(&msg, msg_size) != 0) { - return Lzmq_push_error(L); - } - memcpy(zmq_msg_data(&msg), data, msg_size); - - int rc = zmq_send(s->ptr, &msg, flags); - - if(zmq_msg_close(&msg) != 0) { - return Lzmq_push_error(L); - } - - if (rc != 0) { - return Lzmq_push_error(L); - } - - lua_pushboolean(L, 1); - - return 1; -} - -static int Lzmq_recv(lua_State *L) -{ - zmq_ptr *s = luaL_checkudata(L, 1, MT_ZMQ_SOCKET); - int flags = luaL_optint(L, 2, 0); - - zmq_msg_t msg; - if(zmq_msg_init(&msg) != 0) { - return Lzmq_push_error(L); - } - - if(zmq_recv(s->ptr, &msg, flags) != 0) { - // Best we can do in this case is try to close and hope for the best. - zmq_msg_close(&msg); - return Lzmq_push_error(L); - } - - lua_pushlstring(L, zmq_msg_data(&msg), zmq_msg_size(&msg)); - - if(zmq_msg_close(&msg) != 0) { - // Above string will be poped from the stack by the normalising code - // upon sucessful return. - return Lzmq_push_error(L); - } - - return 1; -} - -static const luaL_reg zmqlib[] = { - {"version", Lzmq_version}, - {"init", Lzmq_init}, - {NULL, NULL} -}; - -static const luaL_reg ctxmethods[] = { - {"__gc", Lzmq_ctx_gc}, - {"lightuserdata", Lzmq_ctx_lightuserdata}, - {"term", Lzmq_term}, - {"socket", Lzmq_socket}, - {NULL, NULL} -}; - -static const luaL_reg sockmethods[] = { - {"__gc", Lzmq_close}, - {"close", Lzmq_close}, - {"setopt", Lzmq_setsockopt}, - {"getopt", Lzmq_getsockopt}, - {"bind", Lzmq_bind}, - {"connect", Lzmq_connect}, - {"send", Lzmq_send}, - {"recv", Lzmq_recv}, - {NULL, NULL} -}; - -#define set_zmq_const(s) lua_pushinteger(L,ZMQ_##s); lua_setfield(L, -2, #s); - -LUALIB_API int luaopen_zmq(lua_State *L) -{ - /* context metatable. */ - luaL_newmetatable(L, MT_ZMQ_CONTEXT); - lua_createtable(L, 0, sizeof(ctxmethods) / sizeof(luaL_reg) - 1); - luaL_register(L, NULL, ctxmethods); - lua_setfield(L, -2, "__index"); - - /* socket metatable. */ - luaL_newmetatable(L, MT_ZMQ_SOCKET); - lua_createtable(L, 0, sizeof(sockmethods) / sizeof(luaL_reg) - 1); - luaL_register(L, NULL, sockmethods); - lua_setfield(L, -2, "__index"); - - luaL_register(L, "zmq", zmqlib); - - /* Socket types. */ - set_zmq_const(PAIR); - set_zmq_const(PUB); - set_zmq_const(SUB); - set_zmq_const(REQ); - set_zmq_const(REP); - set_zmq_const(XREQ); - set_zmq_const(XREP); - set_zmq_const(PULL); - set_zmq_const(PUSH); - - /* Socket options. */ - set_zmq_const(HWM); - set_zmq_const(SWAP); - set_zmq_const(AFFINITY); - set_zmq_const(IDENTITY); - set_zmq_const(SUBSCRIBE); - set_zmq_const(UNSUBSCRIBE); - set_zmq_const(RATE); - set_zmq_const(RECOVERY_IVL); - set_zmq_const(MCAST_LOOP); - set_zmq_const(SNDBUF); - set_zmq_const(RCVBUF); - set_zmq_const(RCVMORE); -#if VERSION_2_1 - set_zmq_const(FD); - set_zmq_const(EVENTS); - set_zmq_const(TYPE); - set_zmq_const(LINGER); - set_zmq_const(RECONNECT_IVL); - set_zmq_const(BACKLOG); - - /* POLL events */ - set_zmq_const(POLLIN); - set_zmq_const(POLLOUT); - set_zmq_const(POLLERR); -#endif - - /* Send/recv options. */ - set_zmq_const(NOBLOCK); - set_zmq_const(SNDMORE); - - return 1; -} diff --git a/zmq.nobj.lua b/zmq.nobj.lua new file mode 100644 index 0000000..bf9fbcd --- /dev/null +++ b/zmq.nobj.lua @@ -0,0 +1,94 @@ + +c_module "zmq" { +-- module settings. +use_globals = false, +hide_meta_info = true, + +include "zmq.h", + +-- +-- Module constants +-- +const "MAX_VSM_SIZE" { 30 }, + +-- message types +const "DELIMITER" { 31 }, +const "VSM" { 32 }, + +-- message flags +const "MSG_MORE" { 1 }, +const "MSG_SHARED" { 128 }, + +-- socket types +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 +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 +const "NOBLOCK" { 1 }, +const "SNDMORE" { 2 }, + +-- poll events +const "POLLIN" { 1 }, +const "POLLOUT" { 2 }, +const "POLLERR" { 4 }, + +-- devices +const "STREAMER" { 1 }, +const "FORWARDER" { 2 }, +const "QUEUE" { 3 }, + +-- +-- Module static functions +-- +c_function "version" { + var_out{ "int", "major" }, + var_out{ "int", "minor" }, + var_out{ "int", "patch" }, + c_source[[ + zmq_version(&(${major}), &(${minor}), &(${patch})); +]] +}, +c_function "init" { + var_in{ "int", "io_threads" }, + var_out{ "ZMQ_Ctx", "ctx", own = true }, + var_out{ "ZMQ_Error", "err"}, + c_source[[ + ${ctx} = zmq_init(${io_threads}); + if(${ctx} == NULL) ${err} = -1; +]] +}, + +subfiles { +"error.nobj.lua", +"ctx.nobj.lua", +"socket.nobj.lua", +}, +} +