diff --git a/CHANGELOG.md b/CHANGELOG.md index 563c710..a53f54e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +## 1.0.0-dev.6 + +### Free pointers before throwing a ZeroMQException +- Free pointers before throwing a ZeroMQException +- Add return code to `zmq_setsockopt` function +- Add return code check to `ZSocket.setOption` function +- Add `zmq_has` function for checking supported capabilities +- Add helper functions for `zmq_has` + + ## 1.0.0-dev.5 ### Fix destroying poller and loading shared library diff --git a/lib/src/bindings.dart b/lib/src/bindings.dart index e9682c0..091343e 100644 --- a/lib/src/bindings.dart +++ b/lib/src/bindings.dart @@ -32,6 +32,9 @@ class ZMQPollItem extends Struct { external int revents; } +typedef ZmqHasNative = Int32 Function(Pointer capability); +typedef ZmqHasDart = int Function(Pointer capability); + typedef ZmqBindNative = Int32 Function( ZMQSocket socket, Pointer endpoint); typedef ZmqBindDart = int Function(ZMQSocket socket, Pointer endpoint); @@ -107,14 +110,16 @@ typedef ZmqSendNative = Int32 Function( typedef ZmqSendDart = int Function( ZMQSocket socket, Pointer buffer, int size, int flags); -typedef ZmqsetsockoptNative = Void Function( +typedef ZmqsetsockoptNative = Int32 Function( ZMQSocket socket, Int32 option, Pointer optval, IntPtr optvallen); -typedef ZmqSetsockoptDart = void Function( +typedef ZmqSetsockoptDart = int Function( ZMQSocket socket, int option, Pointer optval, int optvallen); class ZMQBindings { final DynamicLibrary library; + late final ZmqHasDart zmq_has; + late final ZmqErrnoDart zmq_errno; late final ZmqBindDart zmq_bind; @@ -143,6 +148,7 @@ class ZMQBindings { late final ZmqSetsockoptDart zmq_setsockopt; ZMQBindings(this.library) { + zmq_has = library.lookupFunction('zmq_has'); zmq_errno = library.lookupFunction('zmq_errno'); zmq_bind = library.lookupFunction('zmq_bind'); diff --git a/lib/src/zeromq.dart b/lib/src/zeromq.dart index 512e254..4231188 100644 --- a/lib/src/zeromq.dart +++ b/lib/src/zeromq.dart @@ -70,7 +70,9 @@ class ZContext { } void _initBindings() { - final loaded = _loadBinding('zmq') || _loadBinding('libzmq-v142-mt-4_3_5'); + final loaded = _loadBinding('zmq') || + _loadBinding('libzmq') || + _loadBinding('libzmq-v142-mt-4_3_5'); if (!loaded) { throw Exception('Could not load any zeromq library'); } @@ -169,6 +171,79 @@ class ZContext { _stopCompleter?.complete(null); } + /// Check whether a specified [capability] is available in the library. + /// This allows bindings and applications to probe a library directly, + /// for transport and security options. + /// + /// Capabilities shall be lowercase strings. The following capabilities are defined: + /// * `ipc` - the library supports the ipc:// protocol + /// * `pgm` - the library supports the pgm:// protocol + /// * `tipc` - the library supports the tipc:// protocol + /// * `norm` - the library supports the norm:// protocol + /// * `curve` - the library supports the CURVE security mechanism + /// * `gssapi` - the library supports the GSSAPI security mechanism + /// * `draft` - the library is built with the draft api + /// + /// You can also use one of the direct functions [hasIPC], [hasPGM], + /// [hasTIPC], [hasNORM], [hasCURVE], [hasGSSAPI] and [hasDRAFT] instead. + /// + /// Returns true if supported, false if not + bool hasCapability(final String capability) { + final ptr = capability.toNativeUtf8(); + final result = _bindings.zmq_has(ptr); + malloc.free(ptr); + return result == 1; + } + + /// Check if the library supports the ipc:// protocol + /// + /// Returns true if supported, false if not + bool hasIPC() { + return hasCapability('ipc'); + } + + /// Check if the library supports the pgm:// protocol + /// + /// Returns true if supported, false if not + bool hasPGM() { + return hasCapability('pgm'); + } + + /// Check if the library supports the tipc:// protocol + /// + /// Returns true if supported, false if not + bool hasTIPC() { + return hasCapability('tipc'); + } + + /// Check if the library supports the norm:// protocol + /// + /// Returns true if supported, false if not + bool hasNORM() { + return hasCapability('norm'); + } + + /// Check if the library supports the CURVE security mechanism + /// + /// Returns true if supported, false if not + bool hasCURVE() { + return hasCapability('curve'); + } + + /// Check if the library supports the GSSAPI security mechanism + /// + /// Returns true if supported, false if not + bool hasGSSAPI() { + return hasCapability('gssapi'); + } + + /// Check if the library is built with the draft api + /// + /// Returns true if supported, false if not + bool hasDRAFT() { + return hasCapability('draft'); + } + /// Create a new socket of the given [mode] ZSocket createSocket(SocketType mode) { final socket = _bindings.zmq_socket(_context, mode.index); @@ -476,8 +551,8 @@ class ZSocket { final sendParams = more ? ZMQ_SNDMORE : 0; final result = _context._bindings .zmq_send(_socket, ptr.cast(), data.length, sendParams); - _context._checkReturnCode(result); malloc.free(ptr); + _context._checkReturnCode(result); } /// Sends the given [frame] over this socket @@ -508,8 +583,8 @@ class ZSocket { _checkNotClosed(); final endpointPointer = address.toNativeUtf8(); final result = _context._bindings.zmq_bind(_socket, endpointPointer); - _context._checkReturnCode(result); malloc.free(endpointPointer); + _context._checkReturnCode(result); } /// Connects the socket to an endpoint and then accepts incoming connections on that endpoint. @@ -521,8 +596,8 @@ class ZSocket { _checkNotClosed(); final endpointPointer = address.toNativeUtf8(); final result = _context._bindings.zmq_connect(_socket, endpointPointer); - _context._checkReturnCode(result); malloc.free(endpointPointer); + _context._checkReturnCode(result); } /// Closes the socket and releases underlying resources. @@ -539,9 +614,10 @@ class ZSocket { /// Set a socket [option] to a specific [value] void setOption(final int option, final String value) { final ptr = value.toNativeUtf8(); - _context._bindings + final result = _context._bindings .zmq_setsockopt(_socket, option, ptr.cast(), ptr.length); malloc.free(ptr); + _context._checkReturnCode(result); } /// Sets the socket's long term secret key. @@ -614,13 +690,13 @@ class ZeroMQException implements Exception { /// Maps error codes to messages static const Map _errorMessages = { // errno - EINTR: 'The operation was interrupted', - EBADF: 'Bad file descriptor', - // EAGAIN: '', // denpendant on what function has been called before - EACCES: 'Permission denied', - // EFAULT: '', // denpendant on what function has been called before - // EINVAL: '', // denpendant on what function has been called before - // EMFILE: '', // denpendant on what function has been called before + EINTR: 'EINTR: The operation was interrupted', + EBADF: 'EBADF: Bad file descriptor', + EAGAIN: 'EAGAIN', // denpendant on what function has been called before + EACCES: 'EACCES: Permission denied', + EFAULT: 'EFAULT', // denpendant on what function has been called before + EINVAL: 'EINVAL', // denpendant on what function has been called before + EMFILE: 'EMFILE', // denpendant on what function has been called before // 0MQ errors ENOTSUP: 'Not supported', diff --git a/pubspec.yaml b/pubspec.yaml index 7aa7fec..4424fb6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: dartzmq description: A simple dart zeromq implementation/wrapper around the libzmq C++ library -version: 1.0.0-dev.5 +version: 1.0.0-dev.6 homepage: https://github.com/enwi/dartzmq environment: