diff --git a/docs/make.jl b/docs/make.jl index 2454665..534d38e 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -20,6 +20,7 @@ makedocs( "man/examples.md", ], "Reference" => "reference.md", + "Bindings" => "bindings.md", "Changelog" => "changelog.md" ], format = Documenter.HTML(prettyurls = get(ENV, "CI", nothing) == "true") diff --git a/docs/src/_changelog.md b/docs/src/_changelog.md index 2bc9f9d..3099c27 100644 --- a/docs/src/_changelog.md +++ b/docs/src/_changelog.md @@ -12,6 +12,7 @@ Changelog](https://keepachangelog.com). ### Added - Support for creating [`Message`](@ref)'s from the new `Memory` type in Julia 1.11 ([#244]). +- Full [Bindings](@ref) to libzmq ([#232]). ### Fixed - Fixed [`isfreed()`](@ref), which would previously return the wrong values diff --git a/docs/src/bindings.md b/docs/src/bindings.md new file mode 100644 index 0000000..adccbcc --- /dev/null +++ b/docs/src/bindings.md @@ -0,0 +1,15 @@ +# Bindings + +This page documents the low-level bindings to libzmq that were automatically +generated. Where possible, the docstrings link to the [upstream +documentation](https://libzmq.readthedocs.io). Bindings have not been generated +for deprecated functions. + +!!! danger + These bindings are unsafe, do not use them unless you know what you're doing. + +--- + +```@autodocs +Modules = [ZMQ.lib] +``` diff --git a/docs/src/index.md b/docs/src/index.md index 8cfa19f..e9b0d9c 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -10,6 +10,6 @@ The [Guide](@ref) provides a tutorial explaining how to get started using ZMQ.jl. -Some examples of packages using Documenter can be found on the [Examples](@ref) page. +Some examples are linked on the [Examples](@ref) page. -See the [Reference](@ref) for the complete list of documented functions and types. +See the [Reference](@ref) for the complete list of wrapped functions and types. diff --git a/gen/Project.toml b/gen/Project.toml new file mode 100644 index 0000000..0f09a8d --- /dev/null +++ b/gen/Project.toml @@ -0,0 +1,4 @@ +[deps] +Clang = "40e3b903-d033-50b4-a0cc-940c62c95e31" +MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" +ZeroMQ_jll = "8f1865be-045e-5c20-9c9f-bfbfb0764568" diff --git a/gen/gen.jl b/gen/gen.jl new file mode 100644 index 0000000..f86d388 --- /dev/null +++ b/gen/gen.jl @@ -0,0 +1,106 @@ +import Clang +import Clang.Generators: FunctionProto +import ZeroMQ_jll +import MacroTools: @capture, postwalk, prettify + + +# Helper function to look through all the generated bindings and create new +# zmq_msg_* methods for the Message type. We need to create these overloads +# because the Message type relies on _Message (i.e. lib.zmq_msg_t) under the +# hood, and _Message is an immutable type so it doesn't have a stable address, +# and so cannot safely be passed to a ccall. +# +# We get around this for _Message by always using a Ref{_Message}, but Message +# is a mutable struct with a _Message as its first field. It's safe to pass a +# pointer to a Message to libzmq because the address of the Message is the same +# as its first field, the _Message. But to do that we need to create methods to +# ccall libzmq with the Message type instead of lib.zmq_msg_t (_Message). +function get_msg_methods(ctx, module_name) + methods = Expr[] + + for node in ctx.dag.nodes + for i in eachindex(node.exprs) + expr = node.exprs[i] + + # Check if this is a function + if @capture(expr, function name_(arg1_, args__) body_ end) + # Check if it's a zmq_msg_* function + if startswith(string(name), "zmq_msg_") + # Replace occurrences of `arg::Ptr{zmq_msg_t}` with + # `arg::Ref{Message}`. + new_body = postwalk(body) do x + if @capture(x, Ptr{T_}) && T == :(zmq_msg_t) + :(Ref{Message}) + else + x + end + end + + # Create the new method + new_method = quote + function $module_name.$name($arg1::Message, $(args...)) + $new_body + end + end + + push!(methods, prettify(new_method)) + end + end + end + end + + return methods +end + +# See: +# https://github.com/zeromq/libzmq/blob/c2fae81460d9d39a896da7b3f72484d23a172fa7/include/zmq.h#L582-L611 +const undocumented_functions = [:zmq_stopwatch_start, + :zmq_stopwatch_intermediate, + :zmq_stopwatch_stop, + :zmq_sleep, + :zmq_threadstart, + :zmq_threadclose] +function get_docs(node, doc) + # Only add docstrings for functions + if !(node.type isa FunctionProto) + return doc + end + + url_prefix = "https://libzmq.readthedocs.io/en/latest" + + # The timer functions are all documented on a single page + if startswith(string(node.id), "zmq_timers") + return ["[Upstream documentation]($(url_prefix)/zmq_timers.html)."] + elseif node.id in undocumented_functions + return ["This is an undocumented function, not part of the formal ZMQ API."] + else + # For all the others, generate the URL from the function name + return ["[Upstream documentation]($(url_prefix)/$(node.id).html)."] + end +end + +cd(@__DIR__) do + # Set the options + options = Clang.load_options(joinpath(@__DIR__, "generator.toml")) + options["general"]["callback_documentation"] = get_docs + header = joinpath(ZeroMQ_jll.artifact_dir, "include", "zmq.h") + args = Clang.get_default_args() + + # Generate the generic bindings + ctx = Clang.create_context([header], args, options) + Clang.build!(ctx) + + # Generate the Message methods we need + module_name = Symbol(options["general"]["module_name"]) + msg_methods = get_msg_methods(ctx, module_name) + output_file = joinpath(@__DIR__, "../src/msg_bindings.jl") + open(output_file; write=true) do io + # Import symbols required by the bindings + write(io, "import ZeroMQ_jll: libzmq\n") + write(io, "import .lib: zmq_free_fn\n\n") + + for expr in msg_methods + write(io, string(expr), "\n\n") + end + end +end diff --git a/gen/generator.toml b/gen/generator.toml new file mode 100644 index 0000000..8785275 --- /dev/null +++ b/gen/generator.toml @@ -0,0 +1,15 @@ +[general] +library_name = "libzmq" +module_name = "lib" +output_file_path = "../src/bindings.jl" +print_using_CEnum = false +output_ignorelist = ["ZMQ_VERSION", # This macro cannot be parsed by Clang.jl + # These functions/types are deprecated + "zmq_init", "zmq_term", "zmq_ctx_destroy", + "zmq_device", "zmq_sendmsg", "zmq_recvmsg", + "iovec", "zmq_sendiov", "zmq_recviov"] +prologue_file_path = "./prologue.jl" + +auto_mutability = true +auto_mutability_with_new = false +auto_mutability_includelist = ["zmq_pollitem_t"] diff --git a/gen/prologue.jl b/gen/prologue.jl new file mode 100644 index 0000000..e073113 --- /dev/null +++ b/gen/prologue.jl @@ -0,0 +1 @@ +import ZeroMQ_jll: libzmq diff --git a/src/ZMQ.jl b/src/ZMQ.jl index 9a74306..39e9e0d 100644 --- a/src/ZMQ.jl +++ b/src/ZMQ.jl @@ -1,7 +1,6 @@ # Support for ZeroMQ, a network and interprocess communication library module ZMQ -import ZeroMQ_jll: libzmq using Base.Libc: EAGAIN using FileWatching: UV_READABLE, uv_pollcb, FDWatcher @@ -19,7 +18,7 @@ export #Sockets connect, bind, send, recv - +include("bindings.jl") include("constants.jl") include("optutil.jl") include("error.jl") @@ -27,6 +26,7 @@ include("context.jl") include("socket.jl") include("sockopts.jl") include("message.jl") +include("msg_bindings.jl") include("comm.jl") """ @@ -38,7 +38,7 @@ function lib_version() major = Ref{Cint}() minor = Ref{Cint}() patch = Ref{Cint}() - ccall((:zmq_version, libzmq), Cvoid, (Ptr{Cint}, Ptr{Cint}, Ptr{Cint}), major, minor, patch) + lib.zmq_version(major, minor, patch) return VersionNumber(major[], minor[], patch[]) end diff --git a/src/_message.jl b/src/_message.jl index 1f2b240..0bbf1c4 100644 --- a/src/_message.jl +++ b/src/_message.jl @@ -3,34 +3,33 @@ # Low-level message type, matching the declaration of # zmq_msg_t in the header: char _[64]; -primitive type _Message 64 * 8 end +const _Message = lib.zmq_msg_t -const _MessageOrRef = Union{_Message,Base.RefValue{_Message}} +const _MessageRef = Base.RefValue{_Message} function msg_init() zmsg = Ref{_Message}() - rc = ccall((:zmq_msg_init, libzmq), Cint, (Ref{_Message},), zmsg) + rc = lib.zmq_msg_init(zmsg) rc != 0 && throw(StateError(jl_zmq_error_str())) return zmsg end function msg_init(nbytes::Int) zmsg = Ref{_Message}() - rc = ccall((:zmq_msg_init_size, libzmq), Cint, (Ref{_Message}, Csize_t), zmsg, nbytes % Csize_t) + rc = lib.zmq_msg_init_size(zmsg, nbytes % Csize_t) rc != 0 && throw(StateError(jl_zmq_error_str())) return zmsg end # note: no finalizer for _Message, so we need to call close manually! -function Base.close(zmsg::_MessageOrRef) - rc = ccall((:zmq_msg_close, libzmq), Cint, (Ref{_Message},), zmsg) +function Base.close(zmsg::_MessageRef) + rc = lib.zmq_msg_close(zmsg) rc != 0 && throw(StateError(jl_zmq_error_str())) return nothing end -Base.length(zmsg::_MessageOrRef) = ccall((:zmq_msg_size, libzmq), Csize_t, (Ref{_Message},), zmsg) % Int -Base.unsafe_convert(::Type{Ptr{UInt8}}, zmsg::_MessageOrRef) = - ccall((:zmq_msg_data, libzmq), Ptr{UInt8}, (Ref{_Message},), zmsg) +Base.length(zmsg::Base.RefValue{_Message}) = lib.zmq_msg_size(zmsg) % Int +Base.unsafe_convert(::Type{Ptr{UInt8}}, zmsg::_MessageRef) = Ptr{UInt8}(lib.zmq_msg_data(zmsg)) # isbits data, vectors thereof, and strings can be converted to/from _Message @@ -57,7 +56,7 @@ function _MessageRef(x::String) return zmsg end -function unsafe_copy(::Type{Vector{T}}, zmsg::_MessageOrRef) where {T} +function unsafe_copy(::Type{Vector{T}}, zmsg::_MessageRef) where {T} isbitstype(T) || throw(MethodError(unsafe_copy, (T, zmsg,))) n = length(zmsg) len, remainder = divrem(n, sizeof(T)) @@ -67,16 +66,16 @@ function unsafe_copy(::Type{Vector{T}}, zmsg::_MessageOrRef) where {T} return a end -function unsafe_copy(::Type{T}, zmsg::_MessageOrRef) where {T} +function unsafe_copy(::Type{T}, zmsg::_MessageRef) where {T} isbitstype(T) || throw(MethodError(unsafe_copy, (T, zmsg,))) n = length(zmsg) n == sizeof(T) || error("message length $n ≠ sizeof($T)") return @preserve zmsg unsafe_load(Ptr{T}(Base.unsafe_convert(Ptr{UInt8}, zmsg))) end -function unsafe_copy(::Type{String}, zmsg::_MessageOrRef) +function unsafe_copy(::Type{String}, zmsg::_MessageRef) n = length(zmsg) return @preserve zmsg unsafe_string(Base.unsafe_convert(Ptr{UInt8}, zmsg), n) end -unsafe_copy(::Type{IOBuffer}, zmsg::_MessageOrRef) = IOBuffer(unsafe_copy(Vector{UInt8}, zmsg)) +unsafe_copy(::Type{IOBuffer}, zmsg::_MessageRef) = IOBuffer(unsafe_copy(Vector{UInt8}, zmsg)) diff --git a/src/bindings.jl b/src/bindings.jl new file mode 100644 index 0000000..89f7ed3 --- /dev/null +++ b/src/bindings.jl @@ -0,0 +1,970 @@ +module lib + +import ZeroMQ_jll: libzmq + + +""" + zmq_errno() + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_errno.html). +""" +function zmq_errno() + ccall((:zmq_errno, libzmq), Cint, ()) +end + +""" + zmq_strerror(errnum_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_strerror.html). +""" +function zmq_strerror(errnum_) + ccall((:zmq_strerror, libzmq), Ptr{Cchar}, (Cint,), errnum_) +end + +""" + zmq_version(major_, minor_, patch_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_version.html). +""" +function zmq_version(major_, minor_, patch_) + ccall((:zmq_version, libzmq), Cvoid, (Ptr{Cint}, Ptr{Cint}, Ptr{Cint}), major_, minor_, patch_) +end + +""" + zmq_ctx_new() + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_ctx_new.html). +""" +function zmq_ctx_new() + ccall((:zmq_ctx_new, libzmq), Ptr{Cvoid}, ()) +end + +""" + zmq_ctx_term(context_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_ctx_term.html). +""" +function zmq_ctx_term(context_) + ccall((:zmq_ctx_term, libzmq), Cint, (Ptr{Cvoid},), context_) +end + +""" + zmq_ctx_shutdown(context_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_ctx_shutdown.html). +""" +function zmq_ctx_shutdown(context_) + ccall((:zmq_ctx_shutdown, libzmq), Cint, (Ptr{Cvoid},), context_) +end + +""" + zmq_ctx_set(context_, option_, optval_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_ctx_set.html). +""" +function zmq_ctx_set(context_, option_, optval_) + ccall((:zmq_ctx_set, libzmq), Cint, (Ptr{Cvoid}, Cint, Cint), context_, option_, optval_) +end + +""" + zmq_ctx_get(context_, option_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_ctx_get.html). +""" +function zmq_ctx_get(context_, option_) + ccall((:zmq_ctx_get, libzmq), Cint, (Ptr{Cvoid}, Cint), context_, option_) +end + +struct zmq_msg_t + data::NTuple{64, UInt8} +end + +function Base.getproperty(x::Ptr{zmq_msg_t}, f::Symbol) + f === :_ && return Ptr{NTuple{64, Cuchar}}(x + 0) + return getfield(x, f) +end + +function Base.getproperty(x::zmq_msg_t, f::Symbol) + r = Ref{zmq_msg_t}(x) + ptr = Base.unsafe_convert(Ptr{zmq_msg_t}, r) + fptr = getproperty(ptr, f) + GC.@preserve r unsafe_load(fptr) +end + +function Base.setproperty!(x::Ptr{zmq_msg_t}, f::Symbol, v) + unsafe_store!(getproperty(x, f), v) +end + +# typedef void ( zmq_free_fn ) ( void * data_ , void * hint_ ) +const zmq_free_fn = Cvoid + +""" + zmq_msg_init(msg_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_msg_init.html). +""" +function zmq_msg_init(msg_) + ccall((:zmq_msg_init, libzmq), Cint, (Ptr{zmq_msg_t},), msg_) +end + +""" + zmq_msg_init_size(msg_, size_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_msg_init_size.html). +""" +function zmq_msg_init_size(msg_, size_) + ccall((:zmq_msg_init_size, libzmq), Cint, (Ptr{zmq_msg_t}, Csize_t), msg_, size_) +end + +""" + zmq_msg_init_data(msg_, data_, size_, ffn_, hint_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_msg_init_data.html). +""" +function zmq_msg_init_data(msg_, data_, size_, ffn_, hint_) + ccall((:zmq_msg_init_data, libzmq), Cint, (Ptr{zmq_msg_t}, Ptr{Cvoid}, Csize_t, Ptr{zmq_free_fn}, Ptr{Cvoid}), msg_, data_, size_, ffn_, hint_) +end + +""" + zmq_msg_send(msg_, s_, flags_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_msg_send.html). +""" +function zmq_msg_send(msg_, s_, flags_) + ccall((:zmq_msg_send, libzmq), Cint, (Ptr{zmq_msg_t}, Ptr{Cvoid}, Cint), msg_, s_, flags_) +end + +""" + zmq_msg_recv(msg_, s_, flags_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_msg_recv.html). +""" +function zmq_msg_recv(msg_, s_, flags_) + ccall((:zmq_msg_recv, libzmq), Cint, (Ptr{zmq_msg_t}, Ptr{Cvoid}, Cint), msg_, s_, flags_) +end + +""" + zmq_msg_close(msg_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_msg_close.html). +""" +function zmq_msg_close(msg_) + ccall((:zmq_msg_close, libzmq), Cint, (Ptr{zmq_msg_t},), msg_) +end + +""" + zmq_msg_move(dest_, src_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_msg_move.html). +""" +function zmq_msg_move(dest_, src_) + ccall((:zmq_msg_move, libzmq), Cint, (Ptr{zmq_msg_t}, Ptr{zmq_msg_t}), dest_, src_) +end + +""" + zmq_msg_copy(dest_, src_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_msg_copy.html). +""" +function zmq_msg_copy(dest_, src_) + ccall((:zmq_msg_copy, libzmq), Cint, (Ptr{zmq_msg_t}, Ptr{zmq_msg_t}), dest_, src_) +end + +""" + zmq_msg_data(msg_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_msg_data.html). +""" +function zmq_msg_data(msg_) + ccall((:zmq_msg_data, libzmq), Ptr{Cvoid}, (Ptr{zmq_msg_t},), msg_) +end + +""" + zmq_msg_size(msg_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_msg_size.html). +""" +function zmq_msg_size(msg_) + ccall((:zmq_msg_size, libzmq), Csize_t, (Ptr{zmq_msg_t},), msg_) +end + +""" + zmq_msg_more(msg_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_msg_more.html). +""" +function zmq_msg_more(msg_) + ccall((:zmq_msg_more, libzmq), Cint, (Ptr{zmq_msg_t},), msg_) +end + +""" + zmq_msg_get(msg_, property_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_msg_get.html). +""" +function zmq_msg_get(msg_, property_) + ccall((:zmq_msg_get, libzmq), Cint, (Ptr{zmq_msg_t}, Cint), msg_, property_) +end + +""" + zmq_msg_set(msg_, property_, optval_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_msg_set.html). +""" +function zmq_msg_set(msg_, property_, optval_) + ccall((:zmq_msg_set, libzmq), Cint, (Ptr{zmq_msg_t}, Cint, Cint), msg_, property_, optval_) +end + +""" + zmq_msg_gets(msg_, property_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_msg_gets.html). +""" +function zmq_msg_gets(msg_, property_) + ccall((:zmq_msg_gets, libzmq), Ptr{Cchar}, (Ptr{zmq_msg_t}, Ptr{Cchar}), msg_, property_) +end + +""" + zmq_socket(arg1, type_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_socket.html). +""" +function zmq_socket(arg1, type_) + ccall((:zmq_socket, libzmq), Ptr{Cvoid}, (Ptr{Cvoid}, Cint), arg1, type_) +end + +""" + zmq_close(s_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_close.html). +""" +function zmq_close(s_) + ccall((:zmq_close, libzmq), Cint, (Ptr{Cvoid},), s_) +end + +""" + zmq_setsockopt(s_, option_, optval_, optvallen_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_setsockopt.html). +""" +function zmq_setsockopt(s_, option_, optval_, optvallen_) + ccall((:zmq_setsockopt, libzmq), Cint, (Ptr{Cvoid}, Cint, Ptr{Cvoid}, Csize_t), s_, option_, optval_, optvallen_) +end + +""" + zmq_getsockopt(s_, option_, optval_, optvallen_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_getsockopt.html). +""" +function zmq_getsockopt(s_, option_, optval_, optvallen_) + ccall((:zmq_getsockopt, libzmq), Cint, (Ptr{Cvoid}, Cint, Ptr{Cvoid}, Ptr{Csize_t}), s_, option_, optval_, optvallen_) +end + +""" + zmq_bind(s_, addr_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_bind.html). +""" +function zmq_bind(s_, addr_) + ccall((:zmq_bind, libzmq), Cint, (Ptr{Cvoid}, Ptr{Cchar}), s_, addr_) +end + +""" + zmq_connect(s_, addr_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_connect.html). +""" +function zmq_connect(s_, addr_) + ccall((:zmq_connect, libzmq), Cint, (Ptr{Cvoid}, Ptr{Cchar}), s_, addr_) +end + +""" + zmq_unbind(s_, addr_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_unbind.html). +""" +function zmq_unbind(s_, addr_) + ccall((:zmq_unbind, libzmq), Cint, (Ptr{Cvoid}, Ptr{Cchar}), s_, addr_) +end + +""" + zmq_disconnect(s_, addr_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_disconnect.html). +""" +function zmq_disconnect(s_, addr_) + ccall((:zmq_disconnect, libzmq), Cint, (Ptr{Cvoid}, Ptr{Cchar}), s_, addr_) +end + +""" + zmq_send(s_, buf_, len_, flags_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_send.html). +""" +function zmq_send(s_, buf_, len_, flags_) + ccall((:zmq_send, libzmq), Cint, (Ptr{Cvoid}, Ptr{Cvoid}, Csize_t, Cint), s_, buf_, len_, flags_) +end + +""" + zmq_send_const(s_, buf_, len_, flags_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_send_const.html). +""" +function zmq_send_const(s_, buf_, len_, flags_) + ccall((:zmq_send_const, libzmq), Cint, (Ptr{Cvoid}, Ptr{Cvoid}, Csize_t, Cint), s_, buf_, len_, flags_) +end + +""" + zmq_recv(s_, buf_, len_, flags_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_recv.html). +""" +function zmq_recv(s_, buf_, len_, flags_) + ccall((:zmq_recv, libzmq), Cint, (Ptr{Cvoid}, Ptr{Cvoid}, Csize_t, Cint), s_, buf_, len_, flags_) +end + +""" + zmq_socket_monitor(s_, addr_, events_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_socket_monitor.html). +""" +function zmq_socket_monitor(s_, addr_, events_) + ccall((:zmq_socket_monitor, libzmq), Cint, (Ptr{Cvoid}, Ptr{Cchar}, Cint), s_, addr_, events_) +end + +const zmq_fd_t = Cint + +mutable struct zmq_pollitem_t + socket::Ptr{Cvoid} + fd::zmq_fd_t + events::Cshort + revents::Cshort +end + +""" + zmq_poll(items_, nitems_, timeout_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_poll.html). +""" +function zmq_poll(items_, nitems_, timeout_) + ccall((:zmq_poll, libzmq), Cint, (Ptr{zmq_pollitem_t}, Cint, Clong), items_, nitems_, timeout_) +end + +""" + zmq_proxy(frontend_, backend_, capture_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_proxy.html). +""" +function zmq_proxy(frontend_, backend_, capture_) + ccall((:zmq_proxy, libzmq), Cint, (Ptr{Cvoid}, Ptr{Cvoid}, Ptr{Cvoid}), frontend_, backend_, capture_) +end + +""" + zmq_proxy_steerable(frontend_, backend_, capture_, control_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_proxy_steerable.html). +""" +function zmq_proxy_steerable(frontend_, backend_, capture_, control_) + ccall((:zmq_proxy_steerable, libzmq), Cint, (Ptr{Cvoid}, Ptr{Cvoid}, Ptr{Cvoid}, Ptr{Cvoid}), frontend_, backend_, capture_, control_) +end + +""" + zmq_has(capability_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_has.html). +""" +function zmq_has(capability_) + ccall((:zmq_has, libzmq), Cint, (Ptr{Cchar},), capability_) +end + +""" + zmq_z85_encode(dest_, data_, size_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_z85_encode.html). +""" +function zmq_z85_encode(dest_, data_, size_) + ccall((:zmq_z85_encode, libzmq), Ptr{Cchar}, (Ptr{Cchar}, Ptr{UInt8}, Csize_t), dest_, data_, size_) +end + +""" + zmq_z85_decode(dest_, string_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_z85_decode.html). +""" +function zmq_z85_decode(dest_, string_) + ccall((:zmq_z85_decode, libzmq), Ptr{UInt8}, (Ptr{UInt8}, Ptr{Cchar}), dest_, string_) +end + +""" + zmq_curve_keypair(z85_public_key_, z85_secret_key_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_curve_keypair.html). +""" +function zmq_curve_keypair(z85_public_key_, z85_secret_key_) + ccall((:zmq_curve_keypair, libzmq), Cint, (Ptr{Cchar}, Ptr{Cchar}), z85_public_key_, z85_secret_key_) +end + +""" + zmq_curve_public(z85_public_key_, z85_secret_key_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_curve_public.html). +""" +function zmq_curve_public(z85_public_key_, z85_secret_key_) + ccall((:zmq_curve_public, libzmq), Cint, (Ptr{Cchar}, Ptr{Cchar}), z85_public_key_, z85_secret_key_) +end + +""" + zmq_atomic_counter_new() + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_atomic_counter_new.html). +""" +function zmq_atomic_counter_new() + ccall((:zmq_atomic_counter_new, libzmq), Ptr{Cvoid}, ()) +end + +""" + zmq_atomic_counter_set(counter_, value_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_atomic_counter_set.html). +""" +function zmq_atomic_counter_set(counter_, value_) + ccall((:zmq_atomic_counter_set, libzmq), Cvoid, (Ptr{Cvoid}, Cint), counter_, value_) +end + +""" + zmq_atomic_counter_inc(counter_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_atomic_counter_inc.html). +""" +function zmq_atomic_counter_inc(counter_) + ccall((:zmq_atomic_counter_inc, libzmq), Cint, (Ptr{Cvoid},), counter_) +end + +""" + zmq_atomic_counter_dec(counter_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_atomic_counter_dec.html). +""" +function zmq_atomic_counter_dec(counter_) + ccall((:zmq_atomic_counter_dec, libzmq), Cint, (Ptr{Cvoid},), counter_) +end + +""" + zmq_atomic_counter_value(counter_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_atomic_counter_value.html). +""" +function zmq_atomic_counter_value(counter_) + ccall((:zmq_atomic_counter_value, libzmq), Cint, (Ptr{Cvoid},), counter_) +end + +""" + zmq_atomic_counter_destroy(counter_p_) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_atomic_counter_destroy.html). +""" +function zmq_atomic_counter_destroy(counter_p_) + ccall((:zmq_atomic_counter_destroy, libzmq), Cvoid, (Ptr{Ptr{Cvoid}},), counter_p_) +end + +# typedef void ( zmq_timer_fn ) ( int timer_id , void * arg ) +const zmq_timer_fn = Cvoid + +""" + zmq_timers_new() + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_timers.html). +""" +function zmq_timers_new() + ccall((:zmq_timers_new, libzmq), Ptr{Cvoid}, ()) +end + +""" + zmq_timers_destroy(timers_p) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_timers.html). +""" +function zmq_timers_destroy(timers_p) + ccall((:zmq_timers_destroy, libzmq), Cint, (Ptr{Ptr{Cvoid}},), timers_p) +end + +""" + zmq_timers_add(timers, interval, handler, arg) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_timers.html). +""" +function zmq_timers_add(timers, interval, handler, arg) + ccall((:zmq_timers_add, libzmq), Cint, (Ptr{Cvoid}, Csize_t, zmq_timer_fn, Ptr{Cvoid}), timers, interval, handler, arg) +end + +""" + zmq_timers_cancel(timers, timer_id) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_timers.html). +""" +function zmq_timers_cancel(timers, timer_id) + ccall((:zmq_timers_cancel, libzmq), Cint, (Ptr{Cvoid}, Cint), timers, timer_id) +end + +""" + zmq_timers_set_interval(timers, timer_id, interval) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_timers.html). +""" +function zmq_timers_set_interval(timers, timer_id, interval) + ccall((:zmq_timers_set_interval, libzmq), Cint, (Ptr{Cvoid}, Cint, Csize_t), timers, timer_id, interval) +end + +""" + zmq_timers_reset(timers, timer_id) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_timers.html). +""" +function zmq_timers_reset(timers, timer_id) + ccall((:zmq_timers_reset, libzmq), Cint, (Ptr{Cvoid}, Cint), timers, timer_id) +end + +""" + zmq_timers_timeout(timers) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_timers.html). +""" +function zmq_timers_timeout(timers) + ccall((:zmq_timers_timeout, libzmq), Clong, (Ptr{Cvoid},), timers) +end + +""" + zmq_timers_execute(timers) + +[Upstream documentation](https://libzmq.readthedocs.io/en/latest/zmq_timers.html). +""" +function zmq_timers_execute(timers) + ccall((:zmq_timers_execute, libzmq), Cint, (Ptr{Cvoid},), timers) +end + +""" + zmq_stopwatch_start() + +This is an undocumented function, not part of the formal ZMQ API. +""" +function zmq_stopwatch_start() + ccall((:zmq_stopwatch_start, libzmq), Ptr{Cvoid}, ()) +end + +""" + zmq_stopwatch_intermediate(watch_) + +This is an undocumented function, not part of the formal ZMQ API. +""" +function zmq_stopwatch_intermediate(watch_) + ccall((:zmq_stopwatch_intermediate, libzmq), Culong, (Ptr{Cvoid},), watch_) +end + +""" + zmq_stopwatch_stop(watch_) + +This is an undocumented function, not part of the formal ZMQ API. +""" +function zmq_stopwatch_stop(watch_) + ccall((:zmq_stopwatch_stop, libzmq), Culong, (Ptr{Cvoid},), watch_) +end + +""" + zmq_sleep(seconds_) + +This is an undocumented function, not part of the formal ZMQ API. +""" +function zmq_sleep(seconds_) + ccall((:zmq_sleep, libzmq), Cvoid, (Cint,), seconds_) +end + +# typedef void ( zmq_thread_fn ) ( void * ) +const zmq_thread_fn = Cvoid + +""" + zmq_threadstart(func_, arg_) + +This is an undocumented function, not part of the formal ZMQ API. +""" +function zmq_threadstart(func_, arg_) + ccall((:zmq_threadstart, libzmq), Ptr{Cvoid}, (Ptr{zmq_thread_fn}, Ptr{Cvoid}), func_, arg_) +end + +""" + zmq_threadclose(thread_) + +This is an undocumented function, not part of the formal ZMQ API. +""" +function zmq_threadclose(thread_) + ccall((:zmq_threadclose, libzmq), Cvoid, (Ptr{Cvoid},), thread_) +end + +const ZMQ_VERSION_MAJOR = 4 + +const ZMQ_VERSION_MINOR = 3 + +const ZMQ_VERSION_PATCH = 5 + +# Skipping MacroDefinition: ZMQ_EXPORT __attribute__ ( ( visibility ( "default" ) ) ) + +const ZMQ_DEFINED_STDINT = 1 + +const ZMQ_HAUSNUMERO = 156384712 + +const EFSM = ZMQ_HAUSNUMERO + 51 + +const ENOCOMPATPROTO = ZMQ_HAUSNUMERO + 52 + +const ETERM = ZMQ_HAUSNUMERO + 53 + +const EMTHREAD = ZMQ_HAUSNUMERO + 54 + +const ZMQ_IO_THREADS = 1 + +const ZMQ_MAX_SOCKETS = 2 + +const ZMQ_SOCKET_LIMIT = 3 + +const ZMQ_THREAD_PRIORITY = 3 + +const ZMQ_THREAD_SCHED_POLICY = 4 + +const ZMQ_MAX_MSGSZ = 5 + +const ZMQ_MSG_T_SIZE = 6 + +const ZMQ_THREAD_AFFINITY_CPU_ADD = 7 + +const ZMQ_THREAD_AFFINITY_CPU_REMOVE = 8 + +const ZMQ_THREAD_NAME_PREFIX = 9 + +const ZMQ_IO_THREADS_DFLT = 1 + +const ZMQ_MAX_SOCKETS_DFLT = 1023 + +const ZMQ_THREAD_PRIORITY_DFLT = -1 + +const ZMQ_THREAD_SCHED_POLICY_DFLT = -1 + +const ZMQ_PAIR = 0 + +const ZMQ_PUB = 1 + +const ZMQ_SUB = 2 + +const ZMQ_REQ = 3 + +const ZMQ_REP = 4 + +const ZMQ_DEALER = 5 + +const ZMQ_ROUTER = 6 + +const ZMQ_PULL = 7 + +const ZMQ_PUSH = 8 + +const ZMQ_XPUB = 9 + +const ZMQ_XSUB = 10 + +const ZMQ_STREAM = 11 + +const ZMQ_XREQ = ZMQ_DEALER + +const ZMQ_XREP = ZMQ_ROUTER + +const ZMQ_AFFINITY = 4 + +const ZMQ_ROUTING_ID = 5 + +const ZMQ_SUBSCRIBE = 6 + +const ZMQ_UNSUBSCRIBE = 7 + +const ZMQ_RATE = 8 + +const ZMQ_RECOVERY_IVL = 9 + +const ZMQ_SNDBUF = 11 + +const ZMQ_RCVBUF = 12 + +const ZMQ_RCVMORE = 13 + +const ZMQ_FD = 14 + +const ZMQ_EVENTS = 15 + +const ZMQ_TYPE = 16 + +const ZMQ_LINGER = 17 + +const ZMQ_RECONNECT_IVL = 18 + +const ZMQ_BACKLOG = 19 + +const ZMQ_RECONNECT_IVL_MAX = 21 + +const ZMQ_MAXMSGSIZE = 22 + +const ZMQ_SNDHWM = 23 + +const ZMQ_RCVHWM = 24 + +const ZMQ_MULTICAST_HOPS = 25 + +const ZMQ_RCVTIMEO = 27 + +const ZMQ_SNDTIMEO = 28 + +const ZMQ_LAST_ENDPOINT = 32 + +const ZMQ_ROUTER_MANDATORY = 33 + +const ZMQ_TCP_KEEPALIVE = 34 + +const ZMQ_TCP_KEEPALIVE_CNT = 35 + +const ZMQ_TCP_KEEPALIVE_IDLE = 36 + +const ZMQ_TCP_KEEPALIVE_INTVL = 37 + +const ZMQ_IMMEDIATE = 39 + +const ZMQ_XPUB_VERBOSE = 40 + +const ZMQ_ROUTER_RAW = 41 + +const ZMQ_IPV6 = 42 + +const ZMQ_MECHANISM = 43 + +const ZMQ_PLAIN_SERVER = 44 + +const ZMQ_PLAIN_USERNAME = 45 + +const ZMQ_PLAIN_PASSWORD = 46 + +const ZMQ_CURVE_SERVER = 47 + +const ZMQ_CURVE_PUBLICKEY = 48 + +const ZMQ_CURVE_SECRETKEY = 49 + +const ZMQ_CURVE_SERVERKEY = 50 + +const ZMQ_PROBE_ROUTER = 51 + +const ZMQ_REQ_CORRELATE = 52 + +const ZMQ_REQ_RELAXED = 53 + +const ZMQ_CONFLATE = 54 + +const ZMQ_ZAP_DOMAIN = 55 + +const ZMQ_ROUTER_HANDOVER = 56 + +const ZMQ_TOS = 57 + +const ZMQ_CONNECT_ROUTING_ID = 61 + +const ZMQ_GSSAPI_SERVER = 62 + +const ZMQ_GSSAPI_PRINCIPAL = 63 + +const ZMQ_GSSAPI_SERVICE_PRINCIPAL = 64 + +const ZMQ_GSSAPI_PLAINTEXT = 65 + +const ZMQ_HANDSHAKE_IVL = 66 + +const ZMQ_SOCKS_PROXY = 68 + +const ZMQ_XPUB_NODROP = 69 + +const ZMQ_BLOCKY = 70 + +const ZMQ_XPUB_MANUAL = 71 + +const ZMQ_XPUB_WELCOME_MSG = 72 + +const ZMQ_STREAM_NOTIFY = 73 + +const ZMQ_INVERT_MATCHING = 74 + +const ZMQ_HEARTBEAT_IVL = 75 + +const ZMQ_HEARTBEAT_TTL = 76 + +const ZMQ_HEARTBEAT_TIMEOUT = 77 + +const ZMQ_XPUB_VERBOSER = 78 + +const ZMQ_CONNECT_TIMEOUT = 79 + +const ZMQ_TCP_MAXRT = 80 + +const ZMQ_THREAD_SAFE = 81 + +const ZMQ_MULTICAST_MAXTPDU = 84 + +const ZMQ_VMCI_BUFFER_SIZE = 85 + +const ZMQ_VMCI_BUFFER_MIN_SIZE = 86 + +const ZMQ_VMCI_BUFFER_MAX_SIZE = 87 + +const ZMQ_VMCI_CONNECT_TIMEOUT = 88 + +const ZMQ_USE_FD = 89 + +const ZMQ_GSSAPI_PRINCIPAL_NAMETYPE = 90 + +const ZMQ_GSSAPI_SERVICE_PRINCIPAL_NAMETYPE = 91 + +const ZMQ_BINDTODEVICE = 92 + +const ZMQ_MORE = 1 + +const ZMQ_SHARED = 3 + +const ZMQ_DONTWAIT = 1 + +const ZMQ_SNDMORE = 2 + +const ZMQ_NULL = 0 + +const ZMQ_PLAIN = 1 + +const ZMQ_CURVE = 2 + +const ZMQ_GSSAPI = 3 + +const ZMQ_GROUP_MAX_LENGTH = 255 + +const ZMQ_IDENTITY = ZMQ_ROUTING_ID + +const ZMQ_CONNECT_RID = ZMQ_CONNECT_ROUTING_ID + +const ZMQ_TCP_ACCEPT_FILTER = 38 + +const ZMQ_IPC_FILTER_PID = 58 + +const ZMQ_IPC_FILTER_UID = 59 + +const ZMQ_IPC_FILTER_GID = 60 + +const ZMQ_IPV4ONLY = 31 + +const ZMQ_DELAY_ATTACH_ON_CONNECT = ZMQ_IMMEDIATE + +const ZMQ_NOBLOCK = ZMQ_DONTWAIT + +const ZMQ_FAIL_UNROUTABLE = ZMQ_ROUTER_MANDATORY + +const ZMQ_ROUTER_BEHAVIOR = ZMQ_ROUTER_MANDATORY + +const ZMQ_SRCFD = 2 + +const ZMQ_GSSAPI_NT_HOSTBASED = 0 + +const ZMQ_GSSAPI_NT_USER_NAME = 1 + +const ZMQ_GSSAPI_NT_KRB5_PRINCIPAL = 2 + +const ZMQ_EVENT_CONNECTED = 0x0001 + +const ZMQ_EVENT_CONNECT_DELAYED = 0x0002 + +const ZMQ_EVENT_CONNECT_RETRIED = 0x0004 + +const ZMQ_EVENT_LISTENING = 0x0008 + +const ZMQ_EVENT_BIND_FAILED = 0x0010 + +const ZMQ_EVENT_ACCEPTED = 0x0020 + +const ZMQ_EVENT_ACCEPT_FAILED = 0x0040 + +const ZMQ_EVENT_CLOSED = 0x0080 + +const ZMQ_EVENT_CLOSE_FAILED = 0x0100 + +const ZMQ_EVENT_DISCONNECTED = 0x0200 + +const ZMQ_EVENT_MONITOR_STOPPED = 0x0400 + +const ZMQ_EVENT_ALL = 0xffff + +const ZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL = 0x0800 + +const ZMQ_EVENT_HANDSHAKE_SUCCEEDED = 0x1000 + +const ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL = 0x2000 + +const ZMQ_EVENT_HANDSHAKE_FAILED_AUTH = 0x4000 + +const ZMQ_PROTOCOL_ERROR_ZMTP_UNSPECIFIED = 0x10000000 + +const ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND = 0x10000001 + +const ZMQ_PROTOCOL_ERROR_ZMTP_INVALID_SEQUENCE = 0x10000002 + +const ZMQ_PROTOCOL_ERROR_ZMTP_KEY_EXCHANGE = 0x10000003 + +const ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_UNSPECIFIED = 0x10000011 + +const ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_MESSAGE = 0x10000012 + +const ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO = 0x10000013 + +const ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_INITIATE = 0x10000014 + +const ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_ERROR = 0x10000015 + +const ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_READY = 0x10000016 + +const ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_WELCOME = 0x10000017 + +const ZMQ_PROTOCOL_ERROR_ZMTP_INVALID_METADATA = 0x10000018 + +const ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC = 0x11000001 + +const ZMQ_PROTOCOL_ERROR_ZMTP_MECHANISM_MISMATCH = 0x11000002 + +const ZMQ_PROTOCOL_ERROR_ZAP_UNSPECIFIED = 0x20000000 + +const ZMQ_PROTOCOL_ERROR_ZAP_MALFORMED_REPLY = 0x20000001 + +const ZMQ_PROTOCOL_ERROR_ZAP_BAD_REQUEST_ID = 0x20000002 + +const ZMQ_PROTOCOL_ERROR_ZAP_BAD_VERSION = 0x20000003 + +const ZMQ_PROTOCOL_ERROR_ZAP_INVALID_STATUS_CODE = 0x20000004 + +const ZMQ_PROTOCOL_ERROR_ZAP_INVALID_METADATA = 0x20000005 + +const ZMQ_PROTOCOL_ERROR_WS_UNSPECIFIED = 0x30000000 + +const ZMQ_POLLIN = 1 + +const ZMQ_POLLOUT = 2 + +const ZMQ_POLLERR = 4 + +const ZMQ_POLLPRI = 8 + +const ZMQ_POLLITEMS_DFLT = 16 + +const ZMQ_HAS_CAPABILITIES = 1 + +const ZMQ_STREAMER = 1 + +const ZMQ_FORWARDER = 2 + +const ZMQ_QUEUE = 3 + +end # module diff --git a/src/comm.jl b/src/comm.jl index 00529e5..f5676df 100644 --- a/src/comm.jl +++ b/src/comm.jl @@ -3,15 +3,10 @@ ############################################################################ -msg_send(socket::Socket, zmsg::_MessageOrRef, flags::Integer) = - ccall((:zmq_msg_send, libzmq), Cint, (Ref{_Message}, Ptr{Cvoid}, Cint), zmsg, socket, flags) -msg_send(socket::Socket, zmsg::Message, flags::Integer) = - ccall((:zmq_msg_send, libzmq), Cint, (Ref{Message}, Ptr{Cvoid}, Cint), zmsg, socket, flags) - function _send(socket::Socket, zmsg, more::Bool=false) while true - if -1 == msg_send(socket, zmsg, (ZMQ_SNDMORE*more) | ZMQ_DONTWAIT) - zmq_errno() == EAGAIN || throw(StateError(jl_zmq_error_str())) + if -1 == lib.zmq_msg_send(zmsg, socket, (ZMQ_SNDMORE*more) | ZMQ_DONTWAIT) + lib.zmq_errno() == EAGAIN || throw(StateError(jl_zmq_error_str())) while (socket.events & POLLOUT) == 0 wait(socket) end @@ -67,15 +62,10 @@ end ############################################################################ -msg_recv(socket::Socket, zmsg::_MessageOrRef, flags::Integer) = - ccall((:zmq_msg_recv, libzmq), Cint, (Ref{_Message}, Ptr{Cvoid}, Cint), zmsg, socket, flags) -msg_recv(socket::Socket, zmsg::Message, flags::Integer) = - ccall((:zmq_msg_recv, libzmq), Cint, (Ref{Message}, Ptr{Cvoid}, Cint), zmsg, socket, flags) - function _recv!(socket::Socket, zmsg) while true - if -1 == msg_recv(socket, zmsg, ZMQ_DONTWAIT) - zmq_errno() == EAGAIN || throw(StateError(jl_zmq_error_str())) + if -1 == lib.zmq_msg_recv(zmsg, socket, ZMQ_DONTWAIT) + lib.zmq_errno() == EAGAIN || throw(StateError(jl_zmq_error_str())) while socket.events & POLLIN== 0 wait(socket) end diff --git a/src/constants.jl b/src/constants.jl index 324b004..fe429f4 100644 --- a/src/constants.jl +++ b/src/constants.jl @@ -2,32 +2,32 @@ ## Constants # Context options -const IO_THREADS = 1 -const MAX_SOCKETS = 2 -const IPV6 = 42 +const IO_THREADS = lib.ZMQ_IO_THREADS +const MAX_SOCKETS = lib.ZMQ_MAX_SOCKETS +const IPV6 = lib.ZMQ_IPV6 "[PAIR](https://zeromq.org/socket-api/#pair-socket) socket." -const PAIR = 0 +const PAIR = lib.ZMQ_PAIR "[PUB](https://zeromq.org/socket-api/#pub-socket) socket." -const PUB = 1 +const PUB = lib.ZMQ_PUB "[SUB](https://zeromq.org/socket-api/#sub-socket) socket." -const SUB = 2 +const SUB = lib.ZMQ_SUB "[REQ](https://zeromq.org/socket-api/#req-socket) socket." -const REQ = 3 +const REQ = lib.ZMQ_REQ "[REP](https://zeromq.org/socket-api/#rep-socket) socket." -const REP = 4 +const REP = lib.ZMQ_REP "[DEALER](https://zeromq.org/socket-api/#dealer-socket) socket." -const DEALER = 5 +const DEALER = lib.ZMQ_DEALER "[ROUTER](https://zeromq.org/socket-api/#router-socket) socket." -const ROUTER = 6 +const ROUTER = lib.ZMQ_ROUTER "[PULL](https://zeromq.org/socket-api/#pull-socket) socket." -const PULL = 7 +const PULL = lib.ZMQ_PULL "[PUSH](https://zeromq.org/socket-api/#push-socket) socket." -const PUSH = 8 +const PUSH = lib.ZMQ_PUSH "[XPUB](https://zeromq.org/socket-api/#xpub-socket) socket." -const XPUB = 9 +const XPUB = lib.ZMQ_XPUB "[XSUB](https://zeromq.org/socket-api/#xsub-socket) socket." -const XSUB = 10 +const XSUB = lib.ZMQ_XSUB """ [XREQ](https://zeromq.org/socket-api/#dealer-socket) socket. @@ -61,20 +61,20 @@ const UPSTREAM = PULL const DOWNSTREAM = PUSH #Message options -const MORE = 1 +const MORE = lib.ZMQ_MORE const SNDMORE = true #IO Multiplexing -const POLLIN = 1 -const POLLOUT = 2 -const POLLERR = 4 +const POLLIN = lib.ZMQ_POLLIN +const POLLOUT = lib.ZMQ_POLLOUT +const POLLERR = lib.ZMQ_POLLERR #Built in devices -const STREAMER = 1 -const FORWARDER = 2 -const QUEUE = 3 +const STREAMER = lib.ZMQ_STREAMER +const FORWARDER = lib.ZMQ_FORWARDER +const QUEUE = lib.ZMQ_QUEUE #Send/Recv Options -const ZMQ_DONTWAIT = 1 -const ZMQ_SNDMORE = 2 +const ZMQ_DONTWAIT = lib.ZMQ_DONTWAIT +const ZMQ_SNDMORE = lib.ZMQ_SNDMORE diff --git a/src/context.jl b/src/context.jl index 9ba4aae..c4c306e 100644 --- a/src/context.jl +++ b/src/context.jl @@ -3,7 +3,7 @@ # the low-level context constructor function _ctx_new() - p = ccall((:zmq_ctx_new, libzmq), Ptr{Cvoid}, ()) + p = lib.zmq_ctx_new() if p == C_NULL throw(StateError(jl_zmq_error_str())) end @@ -14,7 +14,7 @@ mutable struct Context data::Ptr{Cvoid} # need to keep a list of weakrefs to sockets for this Context in order to - # close them before finalizing (otherwise zmq_term will hang) + # close them before finalizing (otherwise zmq_ctx_term will hang) sockets::Vector{WeakRef} function Context() @@ -73,7 +73,7 @@ function Base.close(ctx::Context) end end empty!(getfield(ctx, :sockets)) - rc = ccall((:zmq_ctx_destroy, libzmq), Cint, (Ptr{Cvoid},), ctx) + rc = lib.zmq_ctx_term(ctx) setfield!(ctx, :data, C_NULL) if rc != 0 throw(StateError(jl_zmq_error_str())) @@ -83,14 +83,14 @@ end @deprecate term(ctx::Context) close(ctx) function _get(ctx::Context, option::Integer) - val = ccall((:zmq_ctx_get, libzmq), Cint, (Ptr{Cvoid}, Cint), ctx, option) + val = lib.zmq_ctx_get(ctx, option) if val < 0 throw(StateError(jl_zmq_error_str())) end return val end function _set(ctx::Context, option::Integer, value::Integer) - rc = ccall((:zmq_ctx_set, libzmq), Cint, (Ptr{Cvoid}, Cint, Cint), ctx, option, value) + rc = lib.zmq_ctx_set(ctx, option, value) if rc != 0 throw(StateError(jl_zmq_error_str())) end diff --git a/src/error.jl b/src/error.jl index a9fda9d..2d0ef6d 100644 --- a/src/error.jl +++ b/src/error.jl @@ -8,14 +8,15 @@ end show(io, thiserr::StateError) = print(io, "ZMQ: ", thiserr.msg) # Basic functions -zmq_errno() = ccall((:zmq_errno, libzmq), Cint, ()) + function jl_zmq_error_str() - errno = zmq_errno() - c_strerror = ccall((:zmq_strerror, libzmq), Ptr{UInt8}, (Cint,), errno) + errno = lib.zmq_errno() + c_strerror = lib.zmq_strerror(errno) + if c_strerror != C_NULL strerror = unsafe_string(c_strerror) return strerror else return "Unknown error" end -end \ No newline at end of file +end diff --git a/src/message.jl b/src/message.jl index 4d8d05a..17c5fb7 100644 --- a/src/message.jl +++ b/src/message.jl @@ -38,7 +38,7 @@ mutable struct Message <: AbstractArray{UInt8,1} function Message() zmsg = new() setfield!(zmsg, :handle, C_NULL) - rc = ccall((:zmq_msg_init, libzmq), Cint, (Ref{Message},), zmsg) + rc = lib.zmq_msg_init(zmsg) if rc != 0 throw(StateError(jl_zmq_error_str())) end @@ -54,7 +54,7 @@ mutable struct Message <: AbstractArray{UInt8,1} function Message(len::Integer) zmsg = new() setfield!(zmsg, :handle, C_NULL) - rc = ccall((:zmq_msg_init_size, libzmq), Cint, (Ref{Message}, Csize_t), zmsg, len) + rc = lib.zmq_msg_init_size(zmsg, len) if rc != 0 throw(StateError(jl_zmq_error_str())) end @@ -74,8 +74,7 @@ mutable struct Message <: AbstractArray{UInt8,1} zmsg = new() setfield!(zmsg, :handle, gc_protect_handle(origin)) gc_free_fn_c = @cfunction(gc_free_fn, Cint, (Ptr{Cvoid}, Ptr{Cvoid})) - rc = ccall((:zmq_msg_init_data, libzmq), Cint, (Ref{Message}, Ptr{T}, Csize_t, Ptr{Cvoid}, Ptr{Cvoid}), - zmsg, m, len, gc_free_fn_c, getfield(zmsg, :handle)) + rc = lib.zmq_msg_init_data(zmsg, m, len, gc_free_fn_c, getfield(zmsg, :handle)) if rc != 0 gc_free_fn(C_NULL, getfield(zmsg, :handle)) # don't leak memory on error throw(StateError(jl_zmq_error_str())) @@ -139,9 +138,9 @@ isfreed(m::Message) = !haskey(gc_protect, getfield(m, :handle)) # AbstractArray behaviors: Base.similar(a::Message, ::Type{T}, dims::Dims) where {T} = Array{T}(undef, dims) # ? -Base.length(zmsg::Message) = Int(ccall((:zmq_msg_size, libzmq), Csize_t, (Ref{Message},), zmsg)) +Base.length(zmsg::Message) = Int(lib.zmq_msg_size(zmsg)) Base.size(zmsg::Message) = (length(zmsg),) -Base.unsafe_convert(::Type{Ptr{UInt8}}, zmsg::Message) = ccall((:zmq_msg_data, libzmq), Ptr{UInt8}, (Ref{Message},), zmsg) +Base.unsafe_convert(::Type{Ptr{UInt8}}, zmsg::Message) = Ptr{UInt8}(lib.zmq_msg_data(zmsg)) function Base.getindex(a::Message, i::Integer) @boundscheck if i < 1 || i > length(a) throw(BoundsError()) @@ -173,7 +172,7 @@ end # Close a message. You should not need to call this manually (let the # finalizer do it). function Base.close(zmsg::Message) - rc = ccall((:zmq_msg_close, libzmq), Cint, (Ref{Message},), zmsg) + rc = lib.zmq_msg_close(zmsg) if rc != 0 throw(StateError(jl_zmq_error_str())) end @@ -181,14 +180,14 @@ function Base.close(zmsg::Message) end function _get(zmsg::Message, property::Integer) - val = ccall((:zmq_msg_get, libzmq), Cint, (Ref{Message}, Cint), zmsg, property) + val = lib.zmq_msg_get(zmsg, property) if val < 0 throw(StateError(jl_zmq_error_str())) end val end function _set(zmsg::Message, property::Integer, value::Integer) - rc = ccall((:zmq_msg_set, libzmq), Cint, (Ref{Message}, Cint, Cint), zmsg, property, value) + rc = lib.zmq_msg_set(zmsg, property, value) if rc < 0 throw(StateError(jl_zmq_error_str())) end diff --git a/src/msg_bindings.jl b/src/msg_bindings.jl new file mode 100644 index 0000000..bb36f3b --- /dev/null +++ b/src/msg_bindings.jl @@ -0,0 +1,59 @@ +import ZeroMQ_jll: libzmq +import .lib: zmq_free_fn + +function lib.zmq_msg_init(msg_::Message) + ccall((:zmq_msg_init, libzmq), Cint, (Ref{Message},), msg_) +end + +function lib.zmq_msg_init_size(msg_::Message, size_) + ccall((:zmq_msg_init_size, libzmq), Cint, (Ref{Message}, Csize_t), msg_, size_) +end + +function lib.zmq_msg_init_data(msg_::Message, data_, size_, ffn_, hint_) + ccall((:zmq_msg_init_data, libzmq), Cint, (Ref{Message}, Ptr{Cvoid}, Csize_t, Ptr{zmq_free_fn}, Ptr{Cvoid}), msg_, data_, size_, ffn_, hint_) +end + +function lib.zmq_msg_send(msg_::Message, s_, flags_) + ccall((:zmq_msg_send, libzmq), Cint, (Ref{Message}, Ptr{Cvoid}, Cint), msg_, s_, flags_) +end + +function lib.zmq_msg_recv(msg_::Message, s_, flags_) + ccall((:zmq_msg_recv, libzmq), Cint, (Ref{Message}, Ptr{Cvoid}, Cint), msg_, s_, flags_) +end + +function lib.zmq_msg_close(msg_::Message) + ccall((:zmq_msg_close, libzmq), Cint, (Ref{Message},), msg_) +end + +function lib.zmq_msg_move(dest_::Message, src_) + ccall((:zmq_msg_move, libzmq), Cint, (Ref{Message}, Ref{Message}), dest_, src_) +end + +function lib.zmq_msg_copy(dest_::Message, src_) + ccall((:zmq_msg_copy, libzmq), Cint, (Ref{Message}, Ref{Message}), dest_, src_) +end + +function lib.zmq_msg_data(msg_::Message) + ccall((:zmq_msg_data, libzmq), Ptr{Cvoid}, (Ref{Message},), msg_) +end + +function lib.zmq_msg_size(msg_::Message) + ccall((:zmq_msg_size, libzmq), Csize_t, (Ref{Message},), msg_) +end + +function lib.zmq_msg_more(msg_::Message) + ccall((:zmq_msg_more, libzmq), Cint, (Ref{Message},), msg_) +end + +function lib.zmq_msg_get(msg_::Message, property_) + ccall((:zmq_msg_get, libzmq), Cint, (Ref{Message}, Cint), msg_, property_) +end + +function lib.zmq_msg_set(msg_::Message, property_, optval_) + ccall((:zmq_msg_set, libzmq), Cint, (Ref{Message}, Cint, Cint), msg_, property_, optval_) +end + +function lib.zmq_msg_gets(msg_::Message, property_) + ccall((:zmq_msg_gets, libzmq), Ptr{Cchar}, (Ref{Message}, Ptr{Cchar}), msg_, property_) +end + diff --git a/src/socket.jl b/src/socket.jl index 58a9db5..926d5a1 100644 --- a/src/socket.jl +++ b/src/socket.jl @@ -12,7 +12,7 @@ mutable struct Socket Create a socket in a given context. """ function Socket(ctx::Context, typ::Integer) - p = ccall((:zmq_socket, libzmq), Ptr{Cvoid}, (Ptr{Cvoid}, Cint), ctx, typ) + p = lib.zmq_socket(ctx, typ) if p == C_NULL throw(StateError(jl_zmq_error_str())) end @@ -58,7 +58,7 @@ Base.isopen(socket::Socket) = getfield(socket, :data) != C_NULL function Base.close(socket::Socket) if isopen(socket) close(getfield(socket, :pollfd)) - rc = ccall((:zmq_close, libzmq), Cint, (Ptr{Cvoid},), socket) + rc = lib.zmq_close(socket) setfield!(socket, :data, C_NULL) if rc != 0 throw(StateError(jl_zmq_error_str())) @@ -86,7 +86,7 @@ described [here](http://api.zeromq.org/4-3:zmq-bind). e.g. `tcp://127.0.0.1:42000`. """ function Sockets.bind(socket::Socket, endpoint::AbstractString) - rc = ccall((:zmq_bind, libzmq), Cint, (Ptr{Cvoid}, Ptr{UInt8}), socket, endpoint) + rc = lib.zmq_bind(socket, endpoint) if rc != 0 throw(StateError(jl_zmq_error_str())) end @@ -98,7 +98,7 @@ end Connect the socket to an endpoint. """ function Sockets.connect(socket::Socket, endpoint::AbstractString) - rc=ccall((:zmq_connect, libzmq), Cint, (Ptr{Cvoid}, Ptr{UInt8}), socket, endpoint) + rc = lib.zmq_connect(socket, endpoint) if rc != 0 throw(StateError(jl_zmq_error_str())) end diff --git a/src/sockopts.jl b/src/sockopts.jl index 67e1b0f..cc49a17 100644 --- a/src/sockopts.jl +++ b/src/sockopts.jl @@ -30,9 +30,7 @@ for (fset, fget, k, T) in [ ] if fset != nothing @eval function $(Symbol("_",fset))(socket::Socket, option_val::Integer) - rc = ccall((:zmq_setsockopt, libzmq), Cint, - (Ptr{Cvoid}, Cint, Ref{$T}, Csize_t), - socket, $k, option_val, sizeof($T)) + rc = lib.zmq_setsockopt(socket, $k, Ref{$T}(option_val), sizeof($T)) if rc != 0 throw(StateError(jl_zmq_error_str())) end @@ -43,9 +41,7 @@ for (fset, fget, k, T) in [ if fget != nothing @eval function $(Symbol("_",fget))(socket::Socket) val = Ref{$T}() - rc = ccall((:zmq_getsockopt, libzmq), Cint, - (Ptr{Cvoid}, Cint, Ref{$T}, Ref{Csize_t}), - socket, $k, val, sizeof($T)) + rc = lib.zmq_getsockopt(socket, $k, val, Ref(Csize_t(sizeof($T)))) if rc != 0 throw(StateError(jl_zmq_error_str())) end @@ -67,9 +63,7 @@ for (f,k) in ((:subscribe,6), (:unsubscribe,7)) f_ = Symbol(f, "_") @eval begin function $f_(socket::Socket, filter::Ptr{T}, len::Integer) where {T} - rc = ccall((:zmq_setsockopt, libzmq), Cint, - (Ptr{Cvoid}, Cint, Ptr{T}, Csize_t), - socket, $k, filter, len) + rc = lib.zmq_setsockopt(socket, $k, filter, len) if rc != 0 throw(StateError(jl_zmq_error_str())) end @@ -92,9 +86,11 @@ for (fset, fget, k) in [ if sizeof(option_val) > 255 throw(StateError("option value too large")) end - rc = ccall((:zmq_setsockopt, libzmq), Cint, - (Ptr{Cvoid}, Cint, Ptr{UInt8}, Csize_t), - socket, $k, option_val, sizeof(option_val)) + + GC.@preserve option_val begin + string_ptr = Base.unsafe_convert(Ptr{UInt8}, option_val) + rc = lib.zmq_setsockopt(socket, $k, string_ptr, sizeof(option_val)) + end if rc != 0 throw(StateError(jl_zmq_error_str())) end @@ -105,9 +101,7 @@ for (fset, fget, k) in [ @eval function ($fget)(socket::Socket) buf = Base.StringVector(255) len = Ref{Csize_t}(sizeof(buf)) - rc = ccall((:zmq_getsockopt, libzmq), Cint, - (Ptr{Cvoid}, Cint, Ptr{UInt8}, Ref{Csize_t}), - socket, $k, buf, len) + rc = lib.zmq_getsockopt(socket, $k, buf, len) if rc != 0 throw(StateError(jl_zmq_error_str())) end