zmq-0.9.2/.appveyor.yml010064400017500001750000000003321347400165600132240ustar0000000000000000os: - Visual Studio 2015 clone_depth: 1 configuration: - Debug - Release platform: #- Win32 - x64 environment: matrix: - TOOLCHAIN_VERSION: 14.0 RUST: nightly build_script: .appveyor/appveyor.bat zmq-0.9.2/.appveyor/appveyor.bat010064400017500001750000000070551347400165600150470ustar0000000000000000echo on SetLocal EnableDelayedExpansion REM This is the recommended way to choose the toolchain version, according to REM Appveyor's documentation. SET PATH=C:\Program Files (x86)\MSBuild\%TOOLCHAIN_VERSION%\Bin;%PATH% set VCVARSALL="C:\Program Files (x86)\Microsoft Visual Studio %TOOLCHAIN_VERSION%\VC\vcvarsall.bat" set MSVCYEAR=vs2015 set MSVCVERSION=v140 if [%Platform%] NEQ [x64] goto win32 set TARGET_ARCH=x86_64 set TARGET_PROGRAM_FILES=%ProgramFiles% set SODIUM_PLATFORM=X64 set CMAKE_GENERATOR="Visual Studio 14 2015 Win64" call %VCVARSALL% amd64 if %ERRORLEVEL% NEQ 0 exit 1 goto download :win32 echo on if [%Platform%] NEQ [Win32] exit 1 set TARGET_ARCH=i686 set TARGET_PROGRAM_FILES=%ProgramFiles(x86)% set SODIUM_PLATFORM=x86 set CMAKE_GENERATOR="Visual Studio 14 2015" call %VCVARSALL% amd64_x86 if %ERRORLEVEL% NEQ 0 exit 1 goto download :download REM vcvarsall turns echo off echo on echo Installing libsodium set LIBSODIUM_DIR=C:\projects\libsodium git clone --branch stable --depth 1 --quiet "https://github.com/jedisct1/libsodium.git" %LIBSODIUM_DIR% if %ERRORLEVEL% NEQ 0 ( echo cloning libsodium failed exit 1 ) msbuild /v:minimal /maxcpucount:%NUMBER_OF_PROCESSORS% /p:Configuration=%Configuration%DLL %LIBSODIUM_DIR%\builds\msvc\%MSVCYEAR%\libsodium\libsodium.vcxproj if %ERRORLEVEL% NEQ 0 ( echo building libsodium failed exit 1 ) set SODIUM_LIBRARY_DIR="%LIBSODIUM_DIR%\bin\%SODIUM_PLATFORM%\%Configuration%\%MSVCVERSION%\dynamic" set SODIUM_INCLUDE_DIR="%LIBSODIUM_DIR%\src\libsodium\include" move "%SODIUM_LIBRARY_DIR%\libsodium.lib" "%SODIUM_LIBRARY_DIR%\sodium.lib" if %ERRORLEVEL% NEQ 0 exit 1 set PATH=%SODIUM_LIBRARY_DIR%;%PATH% echo Installing libzmq set LIBZMQ_SOURCEDIR=C:\projects\libzmq git clone --branch v4.2.0 --depth 1 --quiet https://github.com/zeromq/libzmq.git "%LIBZMQ_SOURCEDIR%" if %ERRORLEVEL% NEQ 0 ( echo cloning libzmq failed exit 1 ) set LIBZMQ_BUILDDIR=C:\projects\build_libzmq md "%LIBZMQ_BUILDDIR%" set ORIGINAL_PATH=%CD% cd "%LIBZMQ_BUILDDIR%" cmake -D CMAKE_INCLUDE_PATH="%SODIUM_INCLUDE_DIR%" -D CMAKE_LIBRARY_PATH="%SODIUM_LIBRARY_DIR%" -D CMAKE_CXX_FLAGS_RELEASE="/MT" -D CMAKE_CXX_FLAGS_DEBUG="/MTd" -G %CMAKE_GENERATOR% %LIBZMQ_SOURCEDIR% if %ERRORLEVEL% NEQ 0 ( echo ...configuring libzmq failed exit 1 ) msbuild /v:minimal /maxcpucount:%NUMBER_OF_PROCESSORS% /p:Configuration=%Configuration% libzmq.vcxproj if %ERRORLEVEL% NEQ 0 ( echo ...building libzmq failed exit 1 ) set LIBZMQ_INCLUDE_DIR=%LIBZMQ_SOURCEDIR%\include set LIBZMQ_LIB_DIR=%LIBZMQ_BUILDDIR%\lib\%Configuration% move "%LIBZMQ_LIB_DIR%\libzmq-*lib" "%LIBZMQ_LIB_DIR%\zmq.lib" set PATH=%LIBZMQ_BUILDDIR%\bin\%Configuration%;%PATH% if %ERRORLEVEL% NEQ 0 exit 1 cd %ORIGINAL_PATH% set RUST_URL=https://static.rust-lang.org/dist/rust-%RUST%-%TARGET_ARCH%-pc-windows-msvc.msi echo Downloading %RUST_URL%... mkdir build powershell -Command "(New-Object Net.WebClient).DownloadFile('%RUST_URL%', 'build\rust-%RUST%-%TARGET_ARCH%-pc-windows-msvc.msi')" if %ERRORLEVEL% NEQ 0 ( echo ...downloading Rust failed. exit 1 ) start /wait msiexec /i build\rust-%RUST%-%TARGET_ARCH%-pc-windows-msvc.msi INSTALLDIR="%TARGET_PROGRAM_FILES%\Rust %RUST%" /quiet /qn /norestart if %ERRORLEVEL% NEQ 0 exit 1 set PATH="%TARGET_PROGRAM_FILES%\Rust %RUST%\bin";%PATH% if [%Configuration%] == [Release] set CARGO_MODE=--release link /? cl /? rustc --version cargo --version set RUST_BACKTRACE=1 cargo test -vv %CARGO_MODE% if %ERRORLEVEL% NEQ 0 exit 1 cargo clean %CARGO_MODE% if %ERRORLEVEL% NEQ 0 exit 1 cargo test -vv --all-features %CARGO_MODE% if %ERRORLEVEL% NEQ 0 exit 1 zmq-0.9.2/.gitignore010064400017500001750000000000721277132650200125460ustar0000000000000000*.swp *~ \#*\# *.dylib *.dSYM *.o *.a /target/ Cargo.lock zmq-0.9.2/.travis.yml010064400017500001750000000035711354137150100126710ustar0000000000000000language: rust rust: - 1.32.0 # uniform paths - stable - beta - nightly os: linux # always test things that aren't pushes (like PRs) # never test tags or pushes to non-master or release branches (wait for PR) # https://github.com/travis-ci/travis-ci/issues/2200#issuecomment-441395545) if: type != push OR (tag IS blank AND branch =~ /^(master|release\/-.*)$/) addons: apt: packages: - libcurl4-openssl-dev - libelf-dev - libdw-dev - libc6-dev before_install: - wget https://github.com/jedisct1/libsodium/releases/download/1.0.16/libsodium-1.0.16.tar.gz - tar xvfz libsodium-1.0.16.tar.gz - cd libsodium-1.0.16 && ./configure --prefix=$HOME && make && make install && cd .. - wget https://github.com/zeromq/libzmq/releases/download/v4.2.5/zeromq-4.2.5.tar.gz - tar xvfz zeromq-4.2.5.tar.gz - cd zeromq-4.2.5 && ./configure --prefix=$HOME --with-libsodium && make && make install && cd .. matrix: allow_failures: - rust: nightly fast_finish: true include: - stage: check # do a pre-screen to make sure this is even worth testing script: cargo check --all-targets rust: stable - stage: test script: - cargo test --all # Now test with the vendored crate. Clean to prevent duplicate zmq link. - cargo clean - cargo test --all --all-features - cargo test --all --release --all-features - stage: lint name: "Rust: rustfmt" rust: stable install: - rustup component add rustfmt script: - cargo fmt -v -- --check - name: "Rust: clippy" rust: stable install: - rustup component add clippy script: - cargo clippy --all-features --all-targets -- -D warnings stages: - check - test - lint env: global: - PATH=$HOME/.local/bin:$PATH - LD_LIBRARY_PATH=$HOME/lib - PKG_CONFIG_PATH=$HOME/lib/pkgconfig zmq-0.9.2/CONTRIBUTING.md010064400017500001750000000053441347400165600130170ustar0000000000000000# Contributing to rust-zmq Thank you for your interest in contributing to rust-zmq! ## Bug reports Please describe what you did, what you expected, and what happened instead. Please use https://gist.github.com/ if your examples run long. ## Feature requests If you find a missing feature, such as functionality provided by the underlying `libzmq` library, but not available via the Rust API provided by the `zmq` crate, or a suggestion to improve the existing API to make it more ergonomic, please file an issue before starting to work on a pull request, especially when the feature requires API changes or adds to the existing API in non-trivial ways. This gives the maintainers a chance to provide guidance on how the feature might be best implemented, or point out additional constraints that need to be considered when tackling the feature. ## Pull requests rust-zmq uses the "fork and pull" model [described here](https://help.github.com/en/articles/about-collaborative-development-models). It is highly recommended that you create a dedicated branch in your repository for each pull request you submit, instead of submitting using your `master` branch. This will make it easier on you when you end up having multiple pull requests outstanding, and will let you avoid rewriting history on your fork's `master` branch (see below). ### Version history The rust-zmq project aims to keep the version history useful and reasonably simple. Thus, when preparing and updating your pull request, you should make liberal use of git's history rewriting capabilities, such as amending and squashing commits. Try to observe the following guidelines: - Unless you are working on a complex feature that can be implemented in multiple, independent changes, the pull request should contain a single commit. Do not submit "fixup" commits, instead amend your commit (`git commit --amend`) or use interactive rebase (`git rebase -i`) to prepare commits that can be considered on their own, instead of requiring a reviewer to take later fixup commits into account. - Each commit message should give a rough description of what was changed, and why. See ["How to Write a Commit Message"] for details on what a good commit message looks like, and why it matters. - Do not merge the target branch into your pull request branch if you need to update your pull request with changes made in the target branch. Instead, use `git rebase`. ["How to Write a Commit Message"]: https://chris.beams.io/posts/git-commit/ ### Tests If you add a feature, or fix an issue, think about how it could be tested, and add to the testsuite, if possible. This will make it easier for reviewers to see that your code actually does what it is supposed to do, and will prevent future regressions. zmq-0.9.2/Cargo.toml.orig010064400017500001750000000067321354141107200134470ustar0000000000000000[package] name = "zmq" version = "0.9.2" authors = [ "a.rottmann@gmx.at", "erick.tryzelaar@gmail.com", ] license = "MIT/Apache-2.0" description = "High-level bindings to the zeromq library" keywords = ["bindings", "protocol"] categories = ["api-bindings", "network-programming"] repository = "https://github.com/erickt/rust-zmq" readme = "README.md" build = "build.rs" edition = "2018" [badges] maintenance = { status = "passively-maintained" } travis-ci = { repository = "erickt/rust-zmq" } appveyor = { repository = "erickt/rust-zmq" } [features] default = ["zmq_has"] # zmq_has was added in zeromq 4.1. As we now require 4.1 or newer, # this feature is a no-op and only present for backward-compatibility; # it will be removed in the next API-breaking release. zmq_has = [] vendored = ['zmq-sys/vendored'] [dependencies] libc = "0.2.15" log = "0.4.3" zmq-sys = { version = "0.11.0", path = "zmq-sys" } bitflags = "1.0" [dev-dependencies] env_logger = "0.6" quickcheck = "0.9" rand = "0.7" tempfile = "3" timebomb = "0.1.2" nix = "0.15" compiletest_rs = { version = "0.3.10", features = ["stable"] } [[example]] name = "helloworld_client" path = "examples/zguide/helloworld_client/main.rs" [[example]] name = "helloworld_server" path = "examples/zguide/helloworld_server/main.rs" [[example]] name = "msreader" path = "examples/zguide/msreader/main.rs" [[example]] name = "mspoller" path = "examples/zguide/mspoller/main.rs" [[example]] name = "pathopub" path = "examples/zguide/pathopub/main.rs" [[example]] name = "pathosub" path = "examples/zguide/pathosub/main.rs" [[example]] name = "lvcache" path = "examples/zguide/lvcache/main.rs" [[example]] name = "msgsend" path = "examples/msgsend/main.rs" [[example]] name = "stream-logserver" path = "examples/stream/logserver.rs" [[example]] name = "tasksink" path = "examples/zguide/tasksink/main.rs" [[example]] name = "taskvent" path = "examples/zguide/taskvent/main.rs" [[example]] name = "taskwork" path = "examples/zguide/taskwork/main.rs" [[example]] name = "version" path = "examples/zguide/version/main.rs" [[example]] name = "weather_client" path = "examples/zguide/weather_client/main.rs" [[example]] name = "weather_server" path = "examples/zguide/weather_server/main.rs" [[example]] name = "rtdealer" path = "examples/zguide/rtdealer/main.rs" [[example]] name = "fileio3" path = "examples/zguide/fileio3/main.rs" [[example]] name = "rrclient" path = "examples/zguide/rrclient/main.rs" [[example]] name = "rrworker" path = "examples/zguide/rrworker/main.rs" [[example]] name = "rrbroker" path = "examples/zguide/rrbroker/main.rs" [[example]] name = "msgqueue" path = "examples/zguide/msgqueue/main.rs" [[example]] name = "wuproxy" path = "examples/zguide/wuproxy/main.rs" [[example]] name = "tasksink2" path = "examples/zguide/tasksink2/main.rs" [[example]] name = "taskwork2" path = "examples/zguide/taskwork2/main.rs" [[example]] name = "mtserver" path = "examples/zguide/mtserver/main.rs" [[example]] name = "mtrelay" path = "examples/zguide/mtrelay/main.rs" [[example]] name = "syncpub" path = "examples/zguide/syncpub/main.rs" [[example]] name = "syncsub" path = "examples/zguide/syncsub/main.rs" [[example]] name = "psenvpub" path = "examples/zguide/psenvpub/main.rs" [[example]] name="psenvsub" path="examples/zguide/psenvsub/main.rs" [[example]] name="rtreq" path="examples/zguide/rtreq/main.rs" [[example]] name="lbbroker" path="examples/zguide/lbbroker/main.rs" [[example]] name="asyncsrv" path="examples/zguide/asyncsrv/main.rs" zmq-0.9.2/Cargo.toml0000644000000077730000000000000077260ustar00# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] edition = "2018" name = "zmq" version = "0.9.2" authors = ["a.rottmann@gmx.at", "erick.tryzelaar@gmail.com"] build = "build.rs" description = "High-level bindings to the zeromq library" readme = "README.md" keywords = ["bindings", "protocol"] categories = ["api-bindings", "network-programming"] license = "MIT/Apache-2.0" repository = "https://github.com/erickt/rust-zmq" [[example]] name = "helloworld_client" path = "examples/zguide/helloworld_client/main.rs" [[example]] name = "helloworld_server" path = "examples/zguide/helloworld_server/main.rs" [[example]] name = "msreader" path = "examples/zguide/msreader/main.rs" [[example]] name = "mspoller" path = "examples/zguide/mspoller/main.rs" [[example]] name = "pathopub" path = "examples/zguide/pathopub/main.rs" [[example]] name = "pathosub" path = "examples/zguide/pathosub/main.rs" [[example]] name = "lvcache" path = "examples/zguide/lvcache/main.rs" [[example]] name = "msgsend" path = "examples/msgsend/main.rs" [[example]] name = "stream-logserver" path = "examples/stream/logserver.rs" [[example]] name = "tasksink" path = "examples/zguide/tasksink/main.rs" [[example]] name = "taskvent" path = "examples/zguide/taskvent/main.rs" [[example]] name = "taskwork" path = "examples/zguide/taskwork/main.rs" [[example]] name = "version" path = "examples/zguide/version/main.rs" [[example]] name = "weather_client" path = "examples/zguide/weather_client/main.rs" [[example]] name = "weather_server" path = "examples/zguide/weather_server/main.rs" [[example]] name = "rtdealer" path = "examples/zguide/rtdealer/main.rs" [[example]] name = "fileio3" path = "examples/zguide/fileio3/main.rs" [[example]] name = "rrclient" path = "examples/zguide/rrclient/main.rs" [[example]] name = "rrworker" path = "examples/zguide/rrworker/main.rs" [[example]] name = "rrbroker" path = "examples/zguide/rrbroker/main.rs" [[example]] name = "msgqueue" path = "examples/zguide/msgqueue/main.rs" [[example]] name = "wuproxy" path = "examples/zguide/wuproxy/main.rs" [[example]] name = "tasksink2" path = "examples/zguide/tasksink2/main.rs" [[example]] name = "taskwork2" path = "examples/zguide/taskwork2/main.rs" [[example]] name = "mtserver" path = "examples/zguide/mtserver/main.rs" [[example]] name = "mtrelay" path = "examples/zguide/mtrelay/main.rs" [[example]] name = "syncpub" path = "examples/zguide/syncpub/main.rs" [[example]] name = "syncsub" path = "examples/zguide/syncsub/main.rs" [[example]] name = "psenvpub" path = "examples/zguide/psenvpub/main.rs" [[example]] name = "psenvsub" path = "examples/zguide/psenvsub/main.rs" [[example]] name = "rtreq" path = "examples/zguide/rtreq/main.rs" [[example]] name = "lbbroker" path = "examples/zguide/lbbroker/main.rs" [[example]] name = "asyncsrv" path = "examples/zguide/asyncsrv/main.rs" [dependencies.bitflags] version = "1.0" [dependencies.libc] version = "0.2.15" [dependencies.log] version = "0.4.3" [dependencies.zmq-sys] version = "0.11.0" [dev-dependencies.compiletest_rs] version = "0.3.10" features = ["stable"] [dev-dependencies.env_logger] version = "0.6" [dev-dependencies.nix] version = "0.15" [dev-dependencies.quickcheck] version = "0.9" [dev-dependencies.rand] version = "0.7" [dev-dependencies.tempfile] version = "3" [dev-dependencies.timebomb] version = "0.1.2" [features] default = ["zmq_has"] vendored = ["zmq-sys/vendored"] zmq_has = [] [badges.appveyor] repository = "erickt/rust-zmq" [badges.maintenance] status = "passively-maintained" [badges.travis-ci] repository = "erickt/rust-zmq" zmq-0.9.2/HACKING.md010064400017500001750000000016131354137150100121410ustar0000000000000000# Hacking on rust-zmq This file is intended to collect useful knowledge when hacking on the rust-zmq crate. If you intend to provide a contribution, please check the [contribution guidelines]. [contribution guidelines]: ./CONTRIBUTING.md ## Regenerating the C bindings The C low-level, unsafe C binding is provided by the `zmq-sys` crate, also hosted in this repository. The bindings are only partially auto-generated, to allow getting some platform-specific details right. The autogenerated part produced by the `bindgen` crate is stored in the [`ffi.rs`] file inside the `zmq-sys` crate, and is created using the `zmq.h` header file; using the following command: ```sh bindgen \ --with-derive-default \ --whitelist-function "^zmq_.*" \ --whitelist-type "^zmq_.*" \ --whitelist-var "^ZMQ_.*" ~/src/zeromq-4.1.6/include/zmq.h > zmq-sys/src/ffi.rs ``` [`ffi.rs`]: ./zmq-sys/src/ffi.rs zmq-0.9.2/LICENSE-APACHE010064400017500001750000000251371277132650200125130ustar0000000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. zmq-0.9.2/LICENSE-MIT010064400017500001750000000020501277132650200122100ustar0000000000000000Copyright (c) 2011-2014 Erick Tryzelaar 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-0.9.2/NEWS.md010064400017500001750000000157661354141107200116650ustar0000000000000000# 0.9.2 ## New and improved functionality - Support for the `ZMQ_REQ_RELAXED` and `ZMQ_REQ_CORRELATE` socket options, implemented in #285. ## Compatibility - `SocketType`, `Mechanism`, and `Error` can not longer be cast to an integer type and expected to get the corresponding `libzmq` C-level value. The ability to cast to integers and get the C enum values was never a documented part of the API, so this is not considered a breaking change. Unfortunately, the `SocketEvent` can not be future-proofed in this way; the monitoring API needs breaking changes to gain a reasonable level of type-safety. ## Fixes - A potential panic in `Message::gets` involving messages with non-UTF8 property values has been fixed; see #288. # 0.9.1 ## New and improved functionality - Added `vendored` feature which build `libzmq` from source via [`zeromq-src`], see the [`README`] for details; discussed in #257 and implemented in #267. - The installed `libzmq` C library is no longer feature-probed at build time, and all the wrapped API is exposed. Using features unsupported by the installed `libzmq` library will lead to run-time errors, like they would in C. This should enable cross-compiling without jumping through additional hoops. Implemented in #276. - The `Message` data type now implements `From`. - The `Message` data type has gained a new constructor `with_size`, which replaces the now-deprecated, confusingly-named `with_capacity` constructor. Reported in #215 and fixed in #272. - New functions `proxy_steerable` and `proxy_steerable_with_capture`, which wrap the `zmq_proxy_steerable` C function. Implemented in #242. [`README`]: ./README.md [`zeromq-src`]: https://github.com/jean-airoldie/zeromq-src-rs ## Deprecations - The `Message` constructors `with_capacity_unallocated`, `with_capacity` and `from_slice` methods are deprecated, the first one without a planned alternative (#272). ## Platform requirements - The codebase has been switched to the Rust 2018 edition and requires `rustc` 1.32.0 or newer. Compatibility back to 1.32.0 is now ensured via CI. # 0.9.0 ## Incompatible API changes - Requires ZeroMQ 4.1+. - The deprecated `Constants` enum has been removed from the API. - Message allocation, e.g. `Message::new()` directly returns `Message` instead of `Result` and will panic on allocation failure, as is customary in Rust. Reported in #118 and fixed by #130. ## New and improved functionality - `Message` now implements `From` for various types that have an obvious byte-level representation. This is possible due to the message allocation API change (see above). - `Message::send()` now works on `Into` types, obsoleting `send_msg()` and `send_str()`. - Added support for connection timeouts, heartbeats, and xpub welcome messages. ## Deprecations - `Message::send_msg()` and `send_str()` are deprecated in favor of `Message::send()`. # 0.8.3 ## New and improved functionality - Support for the `zmq_socket_monitor` API. - Added `PollItem::set_events`, which allows for constructing a `PollItem` from arbitrary file descriptors. ## Bug fixes - Fix feature detection for `zmq_has` (issue #207). # 0.8.2 ## New and improved functionality - Support for the `ZMQ_PROBE_ROUTER` and `ZMQ_ROUTER_MANDATORY` socket options. - `zmq_disconnect` is now exposed as `Socket::disconnect`. ## Bug fixes - Fix build on OpenBSD (issue #170). - Account for OpenBSD not defining `EPROTO`. - Fix build for 32-bit Windows. - Handle `EINTR` in `Error::from_raw` (issue #174). - Alignment of `zmq_msg_t` FFI type fixed. - Fix `build.rs` to portably construct paths, instead of hard-coding slash as path separator. # 0.8.1 This release fixes the remaining Windows-specific issues exposed by our test suite, as well as improving API convenience a bit. ## New and improved functionality - Should now work on Windows. - `Message` now provides the `Eq` trait. - `From` is now provided for `std::io::Error` (issue #136). - There is now a type alias `PollEvents` mapping to `i16`. Use that instead of `i16` to refer to a set of poll events; in 0.9, `PollEvents` will become a separate type. - `PollItem` now has methods `is_readable`, `is_writable` and `is_error`; use those in preference to using bit masking operations when applicable. - New example zguide example `mspoller`. - Some documentation improvements. - There is now a Unix-specific test integrating `zmq` with Unix `poll(2)`. ## Incompatible API changes There has been a minor API change that was deemed necessary for cross-platform support and to fix broken parts of the API: - There is now an internal `RawFd` type alias that maps to `RawFd` on Unixoids and `RawSocket` on Windows. `Socket::get_fd()` and `PollItem::from_fd()` now use that instead of `i64` and `c_int`, respectively. # 0.8.0 This is a feature and bugfix release. The API has changed, partially in slightly incompatible ways. Typical code, for some suitable value of "typical", should still compile when it did with 0.7, but expect a lot of warnings due to reduced mutability requirements for `Socket` and `Context`. Note that this release adds initial support for the Windows platform (PR #124). While the code now compiles, the test suite is still broken under Windows (issue #125). Since these release notes have been assembled post-hoc, they are highly likely to be incomplete. ## Incompatible API changes The following methods of `Socket` changed: - The deprecated `close()` method has been removed. - `to_raw()` is now known as `into_raw()`. - `borrow_raw()` is known as `as_mut_ptr()`, and takes a `&mut self` now. ## New and improved functionality Note that the added `CURVE` and `GSSAPI` parts of the API are conditional, depending on the compile-time detected capabilities of libzmq. - Most methods of `Socket` no longer require `&mut self`. - `Context` now can be shared across threads - rust-zmq should now work across a wider range of libzmq versions. - More functions now have minimal documentation, but there is still lots of improvements to make in this area. - Initial API coverage for encryption via the `Mechanism` and `CurveKeyPair` data types. - Wrappers for the Z85 codec (`z85_encode` and `z85_decode`). - New socket option accessors for: - `ZMQ_LAST_ENDPOINT` - `ZMQ_IMMEDIATE` - `ZMQ_PROBE_ROUTER`, `ZMQ_ROUTER_MANDATORY` - `ZMQ_RCVTIMEO`, `ZMQ_SNDTIMEO` - Various Kerberos (aka `GSSAPI`) and encryption-related (aka `CURVE`) options. - New zguide examples `fileio3`, `msreader`, `rtdealer`, `lvcache`, `pathopub` and `pathosub`. - There now is a test suite. ## Deprecations `Constants` will be removed from public API in the next release; it should not be needed in client code, since corresponding functionality is provided in a higher-level form. ## Bugfixes Yes, there have been bugs that were fixed; hopefully for the next releases, a reasonably accurate list of those will be provided. ## Internals Some redundancy in error handling and socket option handling has been abstracted over using macros. zmq-0.9.2/README.md010064400017500001750000000122351354137150100120340ustar0000000000000000Rust ZeroMQ bindings. [![Travis Build Status](https://travis-ci.org/erickt/rust-zmq.png?branch=master)](https://travis-ci.org/erickt/rust-zmq) [![Appveyor Build status](https://ci.appveyor.com/api/projects/status/xhytsx4jwyb9qk7m?svg=true)](https://ci.appveyor.com/project/erickt/rust-zmq) [![Coverage Status](https://coveralls.io/repos/erickt/erickt-zmq/badge.svg?branch=master)](https://coveralls.io/r/erickt/erickt-zmq?branch=master) [![Apache 2.0 licensed](https://img.shields.io/badge/license-Apache2.0-blue.svg)](./LICENSE-APACHE) [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE-MIT) [![crates.io](http://meritbadge.herokuapp.com/zmq)](https://crates.io/crates/zmq) [![docs](https://docs.rs/zmq/badge.svg)](https://docs.rs/zmq) [Documentation](https://docs.rs/crate/zmq/) [Release Notes](https://github.com/erickt/rust-zmq/tree/master/NEWS.md) # About The `zmq` crate provides bindings for the `libzmq` library from the [ZeroMQ](https://zeromq.org/) project. The API exposed by `zmq` should be safe (in the usual Rust sense), but it follows the C API closely, so it is not very idiomatic. Also, support for `libzmq` API in "draft" state is considered out-of-scope for this crate; this includes currently, as of libzmq 4.3.3: - Newer, thread-safe socket types, such as `ZMQ_CLIENT` and `ZMQ_SERVER`. - The "poller" API. For a more modern, idiomatic approach to `libzmq` bindings, including draft API features, have a look at [`libzmq-rs`](https://github.com/jean-airoldie/libzmq-rs). # Compatibility The current 0.9 release series requires `libzmq` 4.1 or newer. New release series of `zmq` may require newer `libzmq` versions. # Installation rust-zmq is available from [crates.io](https://crates.io). Users should add this to their `Cargo.toml` file: ```toml [dependencies] zmq = "0.9" ``` As rust-zmq is a wrapper around `libzmq`, you need a build of `libzmq` version 4.1 or newer, before attempting to build the `zmq` crate. There are several options available: ## Dynamic linking using `pkg-config` This is probably the preferred method when you are running a recent Unix-like OS that has support for `pkg-config`. For example, on recent Debian-based distributions, you can use the following command to get the prerequiste headers and library installed: ```sh apt install libzmq3-dev ``` If your OS of choice does not provide packages of a new-enough libzmq, you can install it from source; see , although in this case, you may prefer a `vendored` build, which automates that, see below. The build normally uses `pkg-config` to find out about libzmq's location. If that is not available, the environment variable `LIBZMQ_PREFIX` (or alternatively, `LIBZMQ_LIB_DIR` and `LIBZMQ_INCLUDE_DIR`) can be defined to avoid the invocation of `pkg-config`. ## Windows build When building on Windows, using the MSCV toolchain, consider the following when trying to link dynamically against `libzmq`: - When building `libzmq` from sources, the library must be renamed to `zmq.lib` from the auto named `libzmq-v***-mt-gd-*_*_*.lib`, `libzmq.lib`, `libzmq-mt-*_*_*.lib`, etc. - The folder containing the `*.dll` (dynamic link library) referred to by `zmq.lib` must be accessible via the path for the session that invokes the Rust compiler. - The name of the `*.dll` in question depends on the build system used for `libzmq` and can usually be seen when opening `zmq.lib` in a text editor. ## Vendored build Starting with the upcoming release `0.9.1` (or when building from current `master`), you can enable the `vendored` feature flag to have `libzmq` be built for you and statically linked into your binary crate. In your `Cargo.toml`, you can give users the option to do so using a dedicated feature flag: ```toml [features] vendored-zmq = ['zmq/vendored'] ``` ## Cross-compilation When you have a cross-compiled version of `libzmq` installed, you should be able to cross-compile rust-zmq, assuming a platform supporting `pkg-config`. For example, assuming you have `libzmq` compiled for the `i686-pc-windows-gnu` target installed in `~/.local-w32`, the following should work: ```sh PKG_CONFIG_PATH=$HOME/.local-w32/lib/pkgconfig \ PKG_CONFIG_ALLOW_CROSS=1 \ cargo build --target=i686-pc-windows-gnu --verbose ``` Cross compilation without `pkg-config` should work as well, but you need set `LIBZMQ_PREFIX` as described above. # Usage `rust-zmq` is a pretty straight forward port of the C API into Rust: ```rust fn main() { let ctx = zmq::Context::new(); let mut socket = ctx.socket(zmq::REQ).unwrap(); socket.connect("tcp://127.0.0.1:1234").unwrap(); socket.send("hello world!", 0).unwrap(); } ``` You can find more usage examples in https://github.com/erickt/rust-zmq/tree/master/examples. # Contributing Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed under the terms of both the Apache License, Version 2.0 and the MIT license without any additional terms or conditions. See the [contribution guidelines] for what to watch out for when submitting a pull request. [contribution guidelines]: ./CONTRIBUTING.md zmq-0.9.2/build.rs010064400017500001750000000001711347400165600122240ustar0000000000000000fn main() { println!( "cargo:rustc-env=BUILD_PROFILE={}", std::env::var("PROFILE").unwrap() ); } zmq-0.9.2/examples/msgsend/main.rs010064400017500001750000000077471347400165600153470ustar0000000000000000// A port of the simplistic benchmark from // // http://github.com/PaulKeeble/ScalaVErlangAgents // // I *think* it's the same, more or less. #![crate_name = "msgsend"] use std::env; use std::f64; use std::sync::mpsc::{channel, Receiver, Sender}; use std::thread; use std::time::{Duration, Instant}; fn server(pull_socket: &zmq::Socket, push_socket: &zmq::Socket, mut workers: u64) { let mut count = 0; let mut msg = zmq::Message::new(); while workers != 0 { pull_socket.recv(&mut msg, 0).unwrap(); let s = msg.as_str().unwrap(); if s.is_empty() { workers -= 1; } else { count += s.parse::().unwrap(); } } push_socket.send(&count.to_string(), 0).unwrap(); } fn spawn_server(ctx: &mut zmq::Context, workers: u64) -> Sender<()> { let pull_socket = ctx.socket(zmq::PULL).unwrap(); let push_socket = ctx.socket(zmq::PUSH).unwrap(); pull_socket.bind("inproc://server-pull").unwrap(); push_socket.bind("inproc://server-push").unwrap(); // Spawn the server. let (ready_tx, ready_rx) = channel(); let (start_tx, start_rx) = channel(); thread::spawn(move || { // Let the main thread know we're ready. ready_tx.send(()).unwrap(); // Wait until we need to start. start_rx.recv().unwrap(); server(&pull_socket, &push_socket, workers); }); // Wait for the server to start. ready_rx.recv().unwrap(); start_tx } fn worker(push_socket: &zmq::Socket, count: u64) { for _ in 0..count { push_socket.send(&100.to_string(), 0).unwrap(); } // Let the server know we're done. push_socket.send("", 0).unwrap(); } fn spawn_worker(ctx: &mut zmq::Context, count: u64) -> Receiver<()> { let push_socket = ctx.socket(zmq::PUSH).unwrap(); push_socket.connect("inproc://server-pull").unwrap(); //push_socket.connect("tcp://127.0.0.1:3456").unwrap(); // Spawn the worker. let (tx, rx) = channel(); thread::spawn(move || { // Let the main thread we're ready. tx.send(()).unwrap(); worker(&push_socket, count); tx.send(()).unwrap(); }); // Wait for the worker to start. rx.recv().unwrap(); rx } fn seconds(d: &Duration) -> f64 { d.as_secs() as f64 + (f64::from(d.subsec_nanos()) / 1e9) } fn run(ctx: &mut zmq::Context, size: u64, workers: u64) { let start_ch = spawn_server(ctx, workers); // Create some command/control sockets. let push_socket = ctx.socket(zmq::PUSH).unwrap(); let pull_socket = ctx.socket(zmq::PULL).unwrap(); push_socket.connect("inproc://server-pull").unwrap(); pull_socket.connect("inproc://server-push").unwrap(); //push_socket.connect("tcp://127.0.0.1:3456").unwrap(); //pull_socket.connect("tcp://127.0.0.1:3457").unwrap(); // Spawn all the workers. let mut worker_results = Vec::new(); for _ in 0..workers { worker_results.push(spawn_worker(ctx, size / workers)); } let start = Instant::now(); start_ch.send(()).unwrap(); // Block until all the workers finish. for po in worker_results { po.recv().unwrap(); } // Receive the final count. let msg = pull_socket.recv_msg(0).unwrap(); let result = msg.as_str().unwrap().parse::().unwrap(); let elapsed = seconds(&start.elapsed()); println!("Count is {}", result); println!("Test took {} seconds", elapsed); let thruput = ((size / workers * workers) as f64) / elapsed; println!("Throughput={} per sec", thruput); } fn main() { let args: Vec = env::args().collect(); let args = if env::var("RUST_BENCH").is_ok() { vec!["".to_string(), "1000000".to_string(), "10000".to_string()] } else if args.len() <= 1 { vec!["".to_string(), "10000".to_string(), "4".to_string()] } else { args }; let size = args[1].parse().unwrap(); let workers = args[2].parse().unwrap(); let mut ctx = zmq::Context::new(); run(&mut ctx, size, workers); } zmq-0.9.2/examples/stream/logserver.rs010064400017500001750000000012101347400165600162410ustar0000000000000000// Very basic example to listen tcp socket from zmq using STREAM sockets // You can use telnet to send messages and they will be output to console // ZMQ_STREAM socket will prepend socket identity on message, that's why we use recv_multipart here use std::str; fn main() { println!("Hello, world!"); let ctx = zmq::Context::new(); let socket = ctx.socket(zmq::STREAM).unwrap(); socket.bind("tcp://*:8888").unwrap(); loop { let data = socket.recv_multipart(0).unwrap(); println!( "Identity: {:?} Message : {}", data[0], str::from_utf8(&data[1]).unwrap() ); } } zmq-0.9.2/examples/zguide/README.md010064400017500001750000000014331302262162000151310ustar0000000000000000This is the C examples from the zeromq guide (http://zguide.zeromq.org/), written in Rust. The coding guidelines for porting examples is: - Faithfully implement the semantics from the guide, and also follow their code structure as far as reasonable. This allows for knowledge transfer between languages. - Use ideomatic Rust, and use the most fitting abstraction offered by the bindings. We want these to also highlight the differences in API usage and the higher-level abstractions provided, if applicable. Besides giving potential rust-zmq users an impression of the bindings, these examples are also intended as a "proving ground" for API additions and changes. Ideally, an API change should be reflected in changes to the examples that improve code quality (by whatever metric). zmq-0.9.2/examples/zguide/asyncsrv/main.rs010064400017500001750000000057041347400165600170350ustar0000000000000000// Asynchronous client-to-server (DEALER to ROUTER) // // While this example runs in a single process, that is to make // it easier to start and stop the example. Each task has its own // context and conceptually acts as a separate process. #![crate_name = "asyncsrv"] use rand::{thread_rng, Rng}; use std::time::Duration; use std::{str, thread}; fn client_task() { let context = zmq::Context::new(); let client = context.socket(zmq::DEALER).unwrap(); let mut rng = thread_rng(); let identity = format!("{:04X}-{:04X}", rng.gen::(), rng.gen::()); client .set_identity(identity.as_bytes()) .expect("failed setting client id"); client .connect("tcp://localhost:5570") .expect("failed connecting client"); let mut request_nbr = 0; loop { for _ in 0..100 { if client.poll(zmq::POLLIN, 10).expect("client failed polling") > 0 { let msg = client .recv_multipart(0) .expect("client failed receivng response"); println!("{}", str::from_utf8(&msg[msg.len() - 1]).unwrap()); } } request_nbr += 1; let request = format!("request #{}", request_nbr); client .send(&request, 0) .expect("client failed sending request"); } } fn server_task() { let context = zmq::Context::new(); let frontend = context.socket(zmq::ROUTER).unwrap(); frontend .bind("tcp://*:5570") .expect("server failed binding frontend"); let backend = context.socket(zmq::DEALER).unwrap(); backend .bind("inproc://backend") .expect("server failed binding backend"); for _ in 0..5 { let ctx = context.clone(); thread::spawn(move || server_worker(&ctx)); } zmq::proxy(&frontend, &backend).expect("server failed proxying"); } fn server_worker(context: &zmq::Context) { let worker = context.socket(zmq::DEALER).unwrap(); worker .connect("inproc://backend") .expect("worker failed to connect to backend"); let mut rng = thread_rng(); loop { let identity = worker .recv_string(0) .expect("worker failed receiving identity") .unwrap(); let message = worker .recv_string(0) .expect("worker failed receiving message") .unwrap(); let replies = rng.gen_range(0, 4); for _ in 0..replies { thread::sleep(Duration::from_millis(rng.gen_range(0, 1000) + 1)); worker .send(&identity, zmq::SNDMORE) .expect("worker failed sending identity"); worker .send(&message, 0) .expect("worker failed sending message"); } } } fn main() { thread::spawn(client_task); thread::spawn(client_task); thread::spawn(client_task); thread::spawn(server_task); thread::sleep(Duration::from_secs(5)); } zmq-0.9.2/examples/zguide/fileio3/main.rs010064400017500001750000000111431354137150100165030ustar0000000000000000#![crate_name = "fileio3"] //! File Transfer model #3 //! //! In which the client requests each chunk individually, using //! command pipelining to give us a credit-based flow control. use rand::distributions::Alphanumeric; use rand::Rng; use std::fs::File; use std::io::{Error, Read, Seek, SeekFrom, Write}; use std::thread; use tempfile::tempfile; use zmq::SNDMORE; static CHUNK_SIZE: usize = 250_000; static CHUNK_SIZE_STR: &str = "250000"; static PIPELINE: usize = 10; static PIPELINE_HWM: usize = 20; fn random_string(length: usize) -> String { rand::thread_rng() .sample_iter(&Alphanumeric) .take(length) .collect() } fn client_thread(expected_total: usize) { let context = zmq::Context::new(); let dealer = context.socket(zmq::DEALER).unwrap(); let identity: Vec = (0..10).map(|_| rand::random::()).collect(); dealer.set_identity(&identity).unwrap(); assert!(dealer.connect("tcp://localhost:6000").is_ok()); // Up to this many chunks in transit let mut credit = PIPELINE; let mut total = 0; // Total bytes received let mut chunks = 0; // Total chunks received let mut offset = 0; // Offset of next chunk request let mut clean_break = false; loop { while (credit > 0) && !clean_break { // Ask for next chunk dealer.send("fetch", SNDMORE).unwrap(); dealer.send(&offset.to_string(), SNDMORE).unwrap(); dealer.send(CHUNK_SIZE_STR, 0).unwrap(); offset += CHUNK_SIZE; credit -= 1; } let chunk = dealer.recv_string(0).unwrap().unwrap(); if chunk.is_empty() { clean_break = true; // Shutting down, quit } chunks += 1; credit += 1; let size = chunk.len(); total += size; if size < CHUNK_SIZE { clean_break = true; // Last chunk received; exit } if clean_break && (credit == PIPELINE) { break; // All requests have completed, we can cleanly break. } } println!("{:?} chunks received, {} bytes\n", chunks, total); assert!(expected_total == total); } // The rest of the code is exactly the same as in model 2, except // that we set the HWM on the server's ROUTER socket to PIPELINE // to act as a sanity check. // The server thread waits for a chunk request from a client, // reads that chunk and sends it back to the client: fn server_thread(file: &mut File) -> Result<(), Error> { let context = zmq::Context::new(); let router = context.socket(zmq::ROUTER).unwrap(); // We have two parts per message so HWM is PIPELINE * 2 router.set_sndhwm(PIPELINE_HWM as i32).unwrap(); assert!(router.bind("tcp://*:6000").is_ok()); loop { // First frame in each message is the sender identity let identity = router.recv_bytes(0).unwrap(); if identity.is_empty() { break; // Shutting down, quit } // Second frame is "fetch" command let command = router.recv_string(0).unwrap().unwrap(); assert!(command == "fetch"); // Third frame is chunk offset in file let offset = router.recv_string(0).unwrap().unwrap(); let offset = offset.parse::().unwrap(); // Fourth frame is maximum chunk size let chunk_size = router.recv_string(0).unwrap().unwrap(); let chunk_size = chunk_size.parse::().unwrap(); // Seek to offset file.seek(SeekFrom::Start(offset)).unwrap(); // Read chunk of data from file let mut data = vec![0; chunk_size]; let size = file.read(&mut data)?; data.truncate(size); // Send resulting chunk to client router.send(&identity, SNDMORE).unwrap(); router.send(&data, 0).unwrap(); } Ok(()) } // The main task starts the client and server threads; it's easier // to test this as a single process with threads, than as multiple // processes: fn main() { // Start child threads thread::spawn(|| { // Generate test data in a temp directory println!("Generating temporary data..."); let mut file = tempfile().unwrap(); // Prepare some random test data of appropriate size file.write_all(random_string(10 * CHUNK_SIZE).as_bytes()) .unwrap(); // Start server thread println!("Emitting file content of {:?} bytes", 10 * CHUNK_SIZE); server_thread(&mut file).unwrap(); }); let client_child = thread::spawn(|| { // Start client thread client_thread(10 * CHUNK_SIZE); }); // Loop until client tells us it's done client_child.join().unwrap(); } zmq-0.9.2/examples/zguide/helloworld_client/main.rs010064400017500001750000000011221347400165600206640ustar0000000000000000#![crate_name = "helloworld_client"] //! Hello World client fn main() { println!("Connecting to hello world server...\n"); let context = zmq::Context::new(); let requester = context.socket(zmq::REQ).unwrap(); assert!(requester.connect("tcp://localhost:5555").is_ok()); let mut msg = zmq::Message::new(); for request_nbr in 0..10 { println!("Sending Hello {}...", request_nbr); requester.send("Hello", 0).unwrap(); requester.recv(&mut msg, 0).unwrap(); println!("Received World {}: {}", msg.as_str().unwrap(), request_nbr); } } zmq-0.9.2/examples/zguide/helloworld_server/main.rs010064400017500001750000000011561347400165600207230ustar0000000000000000#![crate_name = "helloworld_server"] //! Hello World server in Rust //! Binds REP socket to tcp://*:5555 //! Expects "Hello" from client, replies with "World" use std::thread; use std::time::Duration; fn main() { let context = zmq::Context::new(); let responder = context.socket(zmq::REP).unwrap(); assert!(responder.bind("tcp://*:5555").is_ok()); let mut msg = zmq::Message::new(); loop { responder.recv(&mut msg, 0).unwrap(); println!("Received {}", msg.as_str().unwrap()); thread::sleep(Duration::from_millis(1000)); responder.send("World", 0).unwrap(); } } zmq-0.9.2/examples/zguide/lbbroker/main.rs010064400017500001750000000165351347400165600167730ustar0000000000000000#![crate_name = "lbbroker"] //! load balancing broker //! clients and workers here are shown in process use zmq::SNDMORE; //use std::time::; use std::thread; // Basic request-reply client using REQ socket // Because s_send and s_recv can't handle 0MQ binary identities, we // set a printable text identity to allow routing. fn client_task(client_nbr: i32) { //create context and client socket let context = zmq::Context::new(); let client = context.socket(zmq::REQ).unwrap(); //set random indentity string and connect let identity = format!("Client{}", client_nbr.to_string()); client.set_identity(identity.as_bytes()).unwrap(); client .connect("ipc://frontend.ipc") .expect("failed connecting client"); //send request, get reply client .send("HELLO", 0) .expect("client failed sending request"); let reply = client .recv_string(0) .expect("client failed receiving reply") .unwrap(); println!("Client: {}", reply); } fn worker_task(worker_nbr: i32) { let context = zmq::Context::new(); let worker = context.socket(zmq::REQ).unwrap(); let identity = format!("Worker{}", worker_nbr.to_string()); worker.set_identity(identity.as_bytes()).unwrap(); assert!(worker.connect("ipc://backend.ipc").is_ok()); // Tell the broker we're ready for work worker.send("READY", 0).unwrap(); loop { //Read and save all frames until we get an empty frame //In this example there is only 1 but there could be more let identity = worker .recv_string(0) .expect("worker failed receiving id") .unwrap(); let empty = worker .recv_string(0) .expect("worker failed receving empty") .unwrap(); assert!(empty.is_empty()); // Get workload from broker, until finished let request = worker.recv_string(0).unwrap().unwrap(); println!("Worker: {}", request); worker .send(&identity, SNDMORE) .expect("worker failed sending identity"); worker .send("", SNDMORE) .expect("worker failed sending empty frame"); worker.send("OK", 0).expect("worker failed sending OK"); } } fn main() { let worker_pool_size = 3; let client_pool_size = 10; let context = zmq::Context::new(); let frontend = context.socket(zmq::ROUTER).unwrap(); let backend = context.socket(zmq::ROUTER).unwrap(); frontend .bind("ipc://frontend.ipc") .expect("failed binding frontend"); backend .bind("ipc://backend.ipc") .expect("failed binding backend"); // While this example runs in a single process, that is just to make // it easier to start and stop the example. Each thread has its own // context and conceptually acts as a separate process. let mut client_thread_pool = Vec::new(); for client_nbr in 0..client_pool_size { let child = thread::spawn(move || { client_task(client_nbr); }); client_thread_pool.push(child); } let mut worker_thread_pool = Vec::new(); for worker_nbr in 0..worker_pool_size { let child = thread::spawn(move || { worker_task(worker_nbr); }); worker_thread_pool.push(child); } // Here is the main loop for the least-recently-used queue. It has two // sockets; a frontend for clients and a backend for workers. It polls // the backend in all cases, and polls the frontend only when there are // one or more workers ready. This is a neat way to use 0MQ's own queues // to hold messages we're not ready to process yet. When we get a client // reply, we pop the next available worker and send the request to it, // including the originating client identity. When a worker replies, // we requeue that worker and forward the reply to the original // client using the reply envelope. let mut client_nbr = client_pool_size; let mut worker_queue = Vec::new(); loop { let mut items = [ backend.as_poll_item(zmq::POLLIN), frontend.as_poll_item(zmq::POLLIN), ]; let rc = zmq::poll( &mut items[0..if worker_queue.is_empty() { 1 } else { 2 }], -1, ) .unwrap(); if rc == -1 { break; } if items[0].is_readable() { let worker_id = backend .recv_string(0) .expect("backend failed receiving worker id") .unwrap(); assert!( backend .recv_string(0) .expect("backend failed receiving empty") .unwrap() == "" ); assert!(worker_queue.len() < (worker_pool_size as usize)); worker_queue.push(worker_id); let client_id = backend .recv_string(0) .expect("backend failed receiving client id") .unwrap(); //if client reply send rest to front end if client_id != "READY" { assert!( backend .recv_string(0) .expect("backend failed receiving second empty") .unwrap() == "" ); let reply = backend .recv_string(0) .expect("backend failed receiving client reply") .unwrap(); frontend .send(&client_id, SNDMORE) .expect("frontend failed sending client id"); frontend .send("", SNDMORE) .expect("frontend failed sending empty"); frontend .send(&reply, 0) .expect("frontend failed sending reply"); client_nbr -= 1; if client_nbr == 0 { break; } } } if items[1].is_readable() { // Now get next client request, route to last-used worker // Client request is [identity][empty][request] let client_id = frontend .recv_string(0) .expect("frontend failed receiving client id") .unwrap(); assert!( frontend .recv_string(0) .expect("frontend failed receiving empty") .unwrap() == "" ); let request = frontend .recv_string(0) .expect("frontend failed receiving request") .unwrap(); let worker = worker_queue.pop().unwrap(); backend .send(&worker, SNDMORE) .expect("backend failed sending worker_id"); backend .send("", SNDMORE) .expect("backend failed sending empty"); backend .send(client_id.as_bytes(), SNDMORE) .expect("backend failed sending client_id"); backend .send("", SNDMORE) .expect("backend faield sending second empty"); backend .send(&request, 0) .expect("backend failed sending request"); } } } zmq-0.9.2/examples/zguide/lvcache/main.rs010064400017500001750000000032131347400165600165630ustar0000000000000000#![crate_name = "lvcache"] use std::collections::HashMap; use std::str::from_utf8; fn main() { let context = zmq::Context::new(); let frontend = context.socket(zmq::SUB).unwrap(); frontend .connect("tcp://localhost:5557") .expect("could not connect to frontend"); let backend = context.socket(zmq::XPUB).unwrap(); backend .bind("tcp://*:5558") .expect("could not bind backend socket"); // Subscribe to every single topic from publisher frontend.set_subscribe(b"").unwrap(); let mut cache = HashMap::new(); loop { let mut items = [ frontend.as_poll_item(zmq::POLLIN), backend.as_poll_item(zmq::POLLIN), ]; if zmq::poll(&mut items, 1000).is_err() { break; // Interrupted } if items[0].is_readable() { let topic = frontend.recv_msg(0).unwrap(); let current = frontend.recv_msg(0).unwrap(); cache.insert(topic.to_vec(), current.to_vec()); backend.send(topic, zmq::SNDMORE).unwrap(); backend.send(current, 0).unwrap(); } if items[1].is_readable() { // Event is one byte 0=unsub or 1=sub, followed by topic let event = backend.recv_msg(0).unwrap(); if event[0] == 1 { let topic = &event[1..]; println!("Sending cached topic {}", from_utf8(topic).unwrap()); if let Some(previous) = cache.get(topic) { backend.send(topic, zmq::SNDMORE).unwrap(); backend.send(previous, 0).unwrap(); } } } } } zmq-0.9.2/examples/zguide/msgqueue/main.rs010064400017500001750000000006601347400165600170140ustar0000000000000000#![crate_name = "msgqueue"] fn main() { let context = zmq::Context::new(); let frontend = context.socket(zmq::ROUTER).unwrap(); let backend = context.socket(zmq::DEALER).unwrap(); frontend .bind("tcp://*:5559") .expect("failed binding frontend"); backend .bind("tcp://*:5560") .expect("failed binding backend"); zmq::proxy(&frontend, &backend).expect("failed to proxy"); } zmq-0.9.2/examples/zguide/mspoller/main.rs010064400017500001750000000020031347400165600170070ustar0000000000000000// Reading from multiple sockets // This version uses zmq::poll() fn main() { let context = zmq::Context::new(); // Connect to task ventilator let receiver = context.socket(zmq::PULL).unwrap(); assert!(receiver.connect("tcp://localhost:5557").is_ok()); // Connect to weather server let subscriber = context.socket(zmq::SUB).unwrap(); assert!(subscriber.connect("tcp://localhost:5556").is_ok()); let filter = b"10001"; assert!(subscriber.set_subscribe(filter).is_ok()); // Process messages from both sockets let mut msg = zmq::Message::new(); loop { let mut items = [ receiver.as_poll_item(zmq::POLLIN), subscriber.as_poll_item(zmq::POLLIN), ]; zmq::poll(&mut items, -1).unwrap(); if items[0].is_readable() && receiver.recv(&mut msg, 0).is_ok() { // Process task } if items[1].is_readable() && subscriber.recv(&mut msg, 0).is_ok() { // Process weather update } } } zmq-0.9.2/examples/zguide/msreader/main.rs010064400017500001750000000022101347400165600167540ustar0000000000000000#![crate_name = "msreader"] //! Reading from multiple sockets //! This version uses a simple recv loop use std::thread; use std::time::Duration; fn main() { let context = zmq::Context::new(); // Connect to task ventilator let receiver = context.socket(zmq::PULL).unwrap(); assert!(receiver.connect("tcp://localhost:5557").is_ok()); // Connect to weather server let subscriber = context.socket(zmq::SUB).unwrap(); assert!(subscriber.connect("tcp://localhost:5556").is_ok()); let filter = b"10001"; assert!(subscriber.set_subscribe(filter).is_ok()); // Process messages from both sockets // We prioritize traffic from the task ventilator let mut msg = zmq::Message::new(); loop { loop { if receiver.recv(&mut msg, zmq::DONTWAIT).is_err() { break; } // Process task } loop { if subscriber.recv(&mut msg, zmq::DONTWAIT).is_err() { break; } // Process weather update } // No activity, so sleep for 1 msec thread::sleep(Duration::from_millis(1)) } } zmq-0.9.2/examples/zguide/mtrelay/main.rs010064400017500001750000000027201347400165600166350ustar0000000000000000#![crate_name = "mtrelay"] use std::thread; fn step1(context: &zmq::Context) { //connect to step 2 and tell it we're ready let xmitter = context.socket(zmq::PAIR).unwrap(); xmitter .connect("inproc://step2") .expect("step 1 failed connecting"); println!("Step 1 ready, signalling step 2"); xmitter.send("READY", 0).expect("step 1 failed sending"); } fn step2(context: &zmq::Context) { //bind inproc socket before starting step 1 let receiver = context.socket(zmq::PAIR).unwrap(); receiver .bind("inproc://step2") .expect("failed binding step 2"); let ctx = context.clone(); thread::spawn(move || step1(&ctx)); //wait for signal and pass it on receiver.recv_msg(0).unwrap(); //connect to step 3 and tell it we're ready let xmitter = context.socket(zmq::PAIR).unwrap(); xmitter .connect("inproc://step3") .expect("step 2 failed connecting"); println!("Step 2 ready, signalling step 3"); xmitter.send("READY", 0).expect("step 2 failed sending"); } fn main() { let context = zmq::Context::new(); //bind inproc socket before starting step 2 let receiver = context.socket(zmq::PAIR).unwrap(); receiver .bind("inproc://step3") .expect("failed binding step 3"); let ctx = context.clone(); thread::spawn(move || step2(&ctx)); //wait for signal and pass it on receiver.recv_msg(0).unwrap(); println!("Test successful!"); } zmq-0.9.2/examples/zguide/mtserver/main.rs010064400017500001750000000020011347400165600170170ustar0000000000000000#![crate_name = "mtserver"] use std::thread; use std::time::Duration; fn worker_routine(context: &zmq::Context) { let receiver = context.socket(zmq::REP).unwrap(); receiver .connect("inproc://workers") .expect("failed to connect worker"); loop { receiver .recv_string(0) .expect("worker failed receiving") .unwrap(); thread::sleep(Duration::from_millis(1000)); receiver.send("World", 0).unwrap(); } } fn main() { let context = zmq::Context::new(); let clients = context.socket(zmq::ROUTER).unwrap(); let workers = context.socket(zmq::DEALER).unwrap(); clients .bind("tcp://*:5555") .expect("failed to bind client router"); workers .bind("inproc://workers") .expect("failed to bind worker dealer"); for _ in 0..5 { let ctx = context.clone(); thread::spawn(move || worker_routine(&ctx)); } zmq::proxy(&clients, &workers).expect("failed proxying"); } zmq-0.9.2/examples/zguide/pathopub/main.rs010064400017500001750000000024231347400165600170020ustar0000000000000000// Pathological publisher // Sends out 1,000 topics and then one random update per second use std::env; use std::thread::sleep; use std::time::Duration; use rand::distributions::{Distribution, Uniform}; fn main() { let context = zmq::Context::new(); let publisher = context.socket(zmq::PUB).unwrap(); let args: Vec<_> = env::args().collect(); let address = if args.len() == 2 { args[1].as_str() } else { "tcp://*:5556" }; publisher .bind(&address) .expect("could not bind publisher socket"); // Ensure subscriber connection has time to complete sleep(Duration::from_millis(1000)); // Send out all 1,000 topic messages for topic_nbr in 0..1000 { publisher .send(&format!("{:03}", topic_nbr), zmq::SNDMORE) .unwrap(); publisher.send("Save Roger", 0).unwrap(); } // Send one random update per second let mut rng = rand::thread_rng(); let topic_range = Uniform::new(0, 1000); loop { sleep(Duration::from_millis(1000)); publisher .send( &format!("{:03}", topic_range.sample(&mut rng)), zmq::SNDMORE, ) .unwrap(); publisher.send("Off with his head!", 0).unwrap(); } } zmq-0.9.2/examples/zguide/pathosub/main.rs010064400017500001750000000017241347400165600170100ustar0000000000000000//! Pathological subscriber //! Subscribes to one random topic and prints received messages use std::env; use rand::distributions::{Distribution, Uniform}; fn main() { let context = zmq::Context::new(); let subscriber = context.socket(zmq::SUB).unwrap(); let args: Vec<_> = env::args().collect(); let address = if args.len() == 2 { args[1].as_str() } else { "tcp://localhost:5556" }; subscriber .connect(&address) .expect("could not connect to publisher"); let mut rng = rand::thread_rng(); let topic_range = Uniform::new(0, 1000); let subscription = format!("{:03}", topic_range.sample(&mut rng)).into_bytes(); subscriber.set_subscribe(&subscription).unwrap(); loop { let topic = subscriber.recv_msg(0).unwrap(); let data = subscriber.recv_msg(0).unwrap(); assert_eq!(&topic[..], &subscription[..]); println!("{}", std::str::from_utf8(&data).unwrap()); } } zmq-0.9.2/examples/zguide/psenvpub/main.rs010064400017500001750000000015021347400165600170170ustar0000000000000000#![crate_name = "psenvpub"] use std::thread; use std::time::Duration; fn main() { //prepare context and publisher let context = zmq::Context::new(); let publisher = context.socket(zmq::PUB).unwrap(); publisher .bind("tcp://*:5563") .expect("failed binding publisher"); loop { publisher .send("A", zmq::SNDMORE) .expect("failed sending first envelope"); publisher .send("We don't want to see this", 0) .expect("failed sending first message"); publisher .send("B", zmq::SNDMORE) .expect("failed sending second envelope"); publisher .send("We would like to see this", 0) .expect("failed sending second message"); thread::sleep(Duration::from_millis(1)); } } zmq-0.9.2/examples/zguide/psenvsub/main.rs010064400017500001750000000012001347400165600170150ustar0000000000000000#![crate_name = "psenvsub"] fn main() { let context = zmq::Context::new(); let subscriber = context.socket(zmq::SUB).unwrap(); subscriber .connect("tcp://localhost:5563") .expect("failed connecting subscriber"); subscriber.set_subscribe(b"B").expect("failed subscribing"); loop { let envelope = subscriber .recv_string(0) .expect("failed receiving envelope") .unwrap(); let message = subscriber .recv_string(0) .expect("failed receiving message") .unwrap(); println!("[{}] {}", envelope, message); } } zmq-0.9.2/examples/zguide/rrbroker/main.rs010064400017500001750000000024671347400165600170200ustar0000000000000000#![crate_name = "rrbroker"] fn main() { let context = zmq::Context::new(); let frontend = context.socket(zmq::ROUTER).unwrap(); let backend = context.socket(zmq::DEALER).unwrap(); frontend .bind("tcp://*:5559") .expect("failed binding frontend"); backend .bind("tcp://*:5560") .expect("failed binding backend"); loop { let mut items = [ frontend.as_poll_item(zmq::POLLIN), backend.as_poll_item(zmq::POLLIN), ]; zmq::poll(&mut items, -1).unwrap(); if items[0].is_readable() { loop { let message = frontend.recv_msg(0).unwrap(); let more = message.get_more(); backend .send(message, if more { zmq::SNDMORE } else { 0 }) .unwrap(); if !more { break; } } } if items[1].is_readable() { loop { let message = backend.recv_msg(0).unwrap(); let more = message.get_more(); frontend .send(message, if more { zmq::SNDMORE } else { 0 }) .unwrap(); if !more { break; } } } } } zmq-0.9.2/examples/zguide/rrclient/main.rs010064400017500001750000000007701347400165600170050ustar0000000000000000#![crate_name = "rrclient"] fn main() { let context = zmq::Context::new(); let requester = context.socket(zmq::REQ).unwrap(); requester .connect("tcp://localhost:5559") .expect("failed to connect requester"); for request_nbr in 0..10 { requester.send("Hello", 0).unwrap(); let message = requester.recv_msg(0).unwrap(); println!( "Received reply {} {}", request_nbr, message.as_str().unwrap() ); } } zmq-0.9.2/examples/zguide/rrworker/main.rs010064400017500001750000000010001347400165600170230ustar0000000000000000#![crate_name = "rrworker"] use std::thread; use std::time::Duration; fn main() { let context = zmq::Context::new(); let responder = context.socket(zmq::REP).unwrap(); responder .connect("tcp://localhost:5560") .expect("failed connecting responder"); loop { let string = responder.recv_string(0).unwrap().unwrap(); println!("Received request:{}", string); thread::sleep(Duration::from_millis(1000)); responder.send("World", 0).unwrap(); } } zmq-0.9.2/examples/zguide/rtdealer/main.rs010064400017500001750000000052731347400165600167700ustar0000000000000000#![crate_name = "rtdealer"] //! Router-to-dealer example use rand::Rng; use std::thread; use std::time::{Duration, Instant}; use zmq::SNDMORE; // Inefficient but terse base16 encoder fn hex(bytes: &[u8]) -> String { bytes .iter() .map(|x| format!("{:02x}", x)) .collect::>() .join("") } fn worker_task() { let context = zmq::Context::new(); let worker = context.socket(zmq::DEALER).unwrap(); let mut rng = rand::thread_rng(); let identity: Vec<_> = (0..10).map(|_| rand::random::()).collect(); worker.set_identity(&identity).unwrap(); assert!(worker.connect("tcp://localhost:5671").is_ok()); let mut total = 0; loop { // Tell the broker we're ready for work worker.send("", SNDMORE).unwrap(); worker.send("Hi boss!", 0).unwrap(); // Get workload from broker, until finished worker.recv_bytes(0).unwrap(); // envelope delimiter let workload = worker.recv_string(0).unwrap().unwrap(); if workload == "Fired!" { println!("Worker {} completed {} tasks", hex(&identity), total); break; } total += 1; // Do some random work thread::sleep(Duration::from_millis(rng.gen_range(1, 500))); } } fn main() { let worker_pool_size = 10; let allowed_duration = Duration::new(5, 0); let context = zmq::Context::new(); let broker = context.socket(zmq::ROUTER).unwrap(); assert!(broker.bind("tcp://*:5671").is_ok()); // While this example runs in a single process, that is just to make // it easier to start and stop the example. Each thread has its own // context and conceptually acts as a separate process. let mut thread_pool = Vec::new(); for _ in 0..worker_pool_size { let child = thread::spawn(move || { worker_task(); }); thread_pool.push(child); } // Run for five seconds and then tell workers to end let start_time = Instant::now(); let mut workers_fired = 0; loop { // Next message gives us least recently used worker let identity = broker.recv_bytes(0).unwrap(); broker.send(&identity, SNDMORE).unwrap(); broker.recv_bytes(0).unwrap(); // Envelope broker.recv_bytes(0).unwrap(); // Response from worker broker.send("", SNDMORE).unwrap(); // Encourage workers until it's time to fire them if start_time.elapsed() < allowed_duration { broker.send("Work harder", 0).unwrap(); } else { broker.send("Fired!", 0).unwrap(); workers_fired += 1; if workers_fired >= worker_pool_size { break; } } } } zmq-0.9.2/examples/zguide/rtreq/main.rs010064400017500001750000000051161347400165600163170ustar0000000000000000#![crate_name = "rtreq"] //! Router-to-request example use rand::Rng; use std::thread; use std::time::{Duration, Instant}; use zmq::SNDMORE; // Inefficient but terse base16 encoder fn hex(bytes: &[u8]) -> String { bytes .iter() .map(|x| format!("{:02x}", x)) .collect::>() .join("") } fn worker_task() { let context = zmq::Context::new(); let worker = context.socket(zmq::REQ).unwrap(); let mut rng = rand::thread_rng(); let identity: Vec<_> = (0..10).map(|_| rand::random::()).collect(); worker.set_identity(&identity).unwrap(); assert!(worker.connect("tcp://localhost:5671").is_ok()); let mut total = 0; loop { // Tell the broker we're ready for work worker.send("Hi boss!", 0).unwrap(); // Get workload from broker, until finished let workload = worker.recv_string(0).unwrap().unwrap(); if workload == "Fired!" { println!("Worker {} completed {} tasks", hex(&identity), total); break; } total += 1; // Do some random work thread::sleep(Duration::from_millis(rng.gen_range(1, 500))); } } fn main() { let worker_pool_size = 10; let allowed_duration = Duration::new(5, 0); let context = zmq::Context::new(); let broker = context.socket(zmq::ROUTER).unwrap(); assert!(broker.bind("tcp://*:5671").is_ok()); // While this example runs in a single process, that is just to make // it easier to start and stop the example. Each thread has its own // context and conceptually acts as a separate process. let mut thread_pool = Vec::new(); for _ in 0..worker_pool_size { let child = thread::spawn(move || { worker_task(); }); thread_pool.push(child); } // Run for five seconds and then tell workers to end let start_time = Instant::now(); let mut workers_fired = 0; loop { // Next message gives us least recently used worker let identity = broker.recv_bytes(0).unwrap(); broker.send(&identity, SNDMORE).unwrap(); broker.recv_bytes(0).unwrap(); // Envelope broker.recv_bytes(0).unwrap(); // Response from worker broker.send("", SNDMORE).unwrap(); // Encourage workers until it's time to fire them if start_time.elapsed() < allowed_duration { broker.send("Work harder", 0).unwrap(); } else { broker.send("Fired!", 0).unwrap(); workers_fired += 1; if workers_fired >= worker_pool_size { break; } } } } zmq-0.9.2/examples/zguide/syncpub/main.rs010064400017500001750000000017411347400165600166450ustar0000000000000000#![crate_name = "syncpub"] fn main() { let context = zmq::Context::new(); //socket to talk to clients let publisher = context.socket(zmq::PUB).unwrap(); publisher.set_sndhwm(1_100_000).expect("failed setting hwm"); publisher .bind("tcp://*:5561") .expect("failed binding publisher"); //socket to receive signals let syncservice = context.socket(zmq::REP).unwrap(); syncservice .bind("tcp://*:5562") .expect("failed binding syncservice"); //get syncronization from subscribers println!("Waiting for subscribers"); for _ in 0..10 { syncservice.recv_msg(0).expect("failed receiving sync"); syncservice.send("", 0).expect("failed sending sync"); } //now broadcast 1M updates followed by end println!("Broadcasting messages"); for _ in 0..1_000_000 { publisher.send("Rhubarb", 0).expect("failed broadcasting"); } publisher.send("END", 0).expect("failed sending end"); } zmq-0.9.2/examples/zguide/syncsub/main.rs010064400017500001750000000021721347400165600166470ustar0000000000000000#![crate_name = "syncsub"] use std::thread; use std::time::Duration; fn main() { let context = zmq::Context::new(); //first connect our subscriber let subscriber = context.socket(zmq::SUB).unwrap(); subscriber .connect("tcp://localhost:5561") .expect("failed connecting subscriber"); subscriber .set_subscribe(b"") .expect("failed setting subscription"); thread::sleep(Duration::from_millis(1)); //second sync with publisher let syncclient = context.socket(zmq::REQ).unwrap(); syncclient .connect("tcp://localhost:5562") .expect("failed connect syncclient"); syncclient.send("", 0).expect("failed sending sync request"); syncclient.recv_msg(0).expect("failed receiving sync reply"); //third get our updates and report how many we got let mut update_nbr = 0; loop { let message = subscriber .recv_string(0) .expect("failed receiving update") .unwrap(); if message == "END" { break; } update_nbr += 1; } println!("Received {} updates", update_nbr); } zmq-0.9.2/examples/zguide/tasksink/main.rs010064400017500001750000000014501347400165600170060ustar0000000000000000#![crate_name = "tasksink"] /// Task sink /// Binds PULL socket to tcp://localhost:5558 /// Collects results from workers via that socket use std::io::{self, Write}; use std::time::Instant; fn main() { // Prepare our context and socket let context = zmq::Context::new(); let receiver = context.socket(zmq::PULL).unwrap(); assert!(receiver.bind("tcp://*:5558").is_ok()); // Wait for start of batch receiver.recv_bytes(0).unwrap(); // Start our clock now let start = Instant::now(); for task_nbr in 0..100 { receiver.recv_bytes(0).unwrap(); if task_nbr % 10 == 0 { print!(":"); } else { print!("."); } let _ = io::stdout().flush(); } println!("\nTotal elapsed time: {:?}", start.elapsed()); } zmq-0.9.2/examples/zguide/tasksink2/main.rs010064400017500001750000000020531347400165600170700ustar0000000000000000#![crate_name = "tasksink2"] /// Task sink /// Binds PULL socket to tcp://localhost:5558 /// Collects results from workers via that socket use std::io::{self, Write}; use std::time::Instant; fn main() { // Prepare our context and socket let context = zmq::Context::new(); let receiver = context.socket(zmq::PULL).unwrap(); assert!(receiver.bind("tcp://*:5558").is_ok()); let controller = context.socket(zmq::PUB).unwrap(); controller .bind("tcp://*:5559") .expect("failed to bind controller"); // Wait for start of batch receiver.recv_bytes(0).unwrap(); // Start our clock now let start = Instant::now(); for task_nbr in 0..100 { receiver.recv_bytes(0).unwrap(); if task_nbr % 10 == 0 { print!(":"); } else { print!("."); } let _ = io::stdout().flush(); } println!("\nTotal elapsed time: {:?}", start.elapsed()); //send kill signal controller .send("KILL", 0) .expect("failed to send kill signal"); } zmq-0.9.2/examples/zguide/taskvent/main.rs010064400017500001750000000023021347400165600170130ustar0000000000000000#![crate_name = "taskvent"] //! Task ventilator //! Binds PUSH socket to tcp://localhost:5557 //! Sends batch of tasks to workers via that socket use rand::Rng; use std::io::{self, BufRead}; fn main() { let context = zmq::Context::new(); // Socket to send messages on let sender = context.socket(zmq::PUSH).unwrap(); assert!(sender.bind("tcp://*:5557").is_ok()); // Socket to send start of batch message on let sink = context.socket(zmq::PUSH).unwrap(); assert!(sink.connect("tcp://localhost:5558").is_ok()); println!("Press Enter when the workers are ready: "); let stdin = io::stdin(); stdin.lock().lines().next(); println!("Sending tasks to workers..."); // The first message is "0" and signals start of batch sink.send("0", 0).unwrap(); let mut rng = rand::thread_rng(); // Send 100 tasks let mut total_msec: u32 = 0; for _ in 0..100 { // Random workload from 1 to 100 msecs let workload: u32 = rng.gen_range(1, 101); total_msec += workload; let workload_str = format!("{}", workload); sender.send(&workload_str, 0).unwrap(); } println!("Total expected cost: {} msec", total_msec) } zmq-0.9.2/examples/zguide/taskwork/main.rs010064400017500001750000000020241347400165600170220ustar0000000000000000#![crate_name = "taskwork"] /// Task worker /// Connects PULL socket to tcp://localhost:5557 /// Collects workloads from ventilator via that socket /// Connects PUSH socket to tcp://localhost:5558 /// Sends results to sink via that socket use std::io::{self, Write}; use std::thread; use std::time::Duration; fn atoi(s: &str) -> u64 { s.parse().unwrap() } fn main() { let context = zmq::Context::new(); // socket to receive messages on let receiver = context.socket(zmq::PULL).unwrap(); assert!(receiver.connect("tcp://localhost:5557").is_ok()); // Socket to send messages to let sender = context.socket(zmq::PUSH).unwrap(); assert!(sender.connect("tcp://localhost:5558").is_ok()); loop { let string = receiver.recv_string(0).unwrap().unwrap(); // Show progress print!("."); let _ = io::stdout().flush(); // Do the work thread::sleep(Duration::from_millis(atoi(&string))); // Send results to sink sender.send("", 0).unwrap(); } } zmq-0.9.2/examples/zguide/taskwork2/main.rs010064400017500001750000000031111347400165600171020ustar0000000000000000#![crate_name = "taskwork2"] /// Task worker /// Connects PULL socket to tcp://localhost:5557 /// Collects workloads from ventilator via that socket /// Connects PUSH socket to tcp://localhost:5558 /// Sends results to sink via that socket use std::io::{self, Write}; use std::thread; use std::time::Duration; fn atoi(s: &str) -> u64 { s.parse().unwrap() } fn main() { let context = zmq::Context::new(); // socket to receive messages on let receiver = context.socket(zmq::PULL).unwrap(); assert!(receiver.connect("tcp://localhost:5557").is_ok()); // Socket to send messages to let sender = context.socket(zmq::PUSH).unwrap(); assert!(sender.connect("tcp://localhost:5558").is_ok()); let controller = context.socket(zmq::SUB).unwrap(); controller .connect("tcp://localhost:5559") .expect("failed connecting controller"); controller.set_subscribe(b"").expect("failed subscribing"); loop { let mut items = [ receiver.as_poll_item(zmq::POLLIN), controller.as_poll_item(zmq::POLLIN), ]; zmq::poll(&mut items, -1).expect("failed polling"); if items[0].is_readable() { let string = receiver.recv_string(0).unwrap().unwrap(); // Show progress print!("."); let _ = io::stdout().flush(); // Do the work thread::sleep(Duration::from_millis(atoi(&string))); // Send results to sink sender.send("", 0).unwrap(); } if items[1].is_readable() { break; } } } zmq-0.9.2/examples/zguide/version/main.rs010064400017500001750000000002401347400165600166400ustar0000000000000000#![crate_name = "version"] fn main() { let (major, minor, patch) = zmq::version(); println!("Current 0MQ version is {}.{}.{}", major, minor, patch); } zmq-0.9.2/examples/zguide/weather_client/main.rs010064400017500001750000000020771347400165600201620ustar0000000000000000#![crate_name = "weather_client"] /*! * Weather update client * Connects SUB socket to tcp://localhost:5556 * Collects weather updates and find avg temp in zipcode */ use std::env; fn atoi(s: &str) -> i64 { s.parse().unwrap() } fn main() { println!("Collecting updates from weather server..."); let context = zmq::Context::new(); let subscriber = context.socket(zmq::SUB).unwrap(); assert!(subscriber.connect("tcp://localhost:5556").is_ok()); let args: Vec = env::args().collect(); let filter = if args.len() > 1 { &args[1] } else { "10001" }; assert!(subscriber.set_subscribe(filter.as_bytes()).is_ok()); let mut total_temp = 0; for _ in 0..100 { let string = subscriber.recv_string(0).unwrap().unwrap(); let chks: Vec = string.split(' ').map(atoi).collect(); let (_zipcode, temperature, _relhumidity) = (chks[0], chks[1], chks[2]); total_temp += temperature; } println!( "Average temperature for zipcode '{}' was {}F", filter, (total_temp / 100) ); } zmq-0.9.2/examples/zguide/weather_server/main.rs010064400017500001750000000017011354141107200201730ustar0000000000000000#![crate_name = "weather_server"] //! Weather update server //! Binds PUB socket to tcp://*:5556 and ipc://weather.ipc //! Publishes random weather updates use rand::Rng; fn main() { let context = zmq::Context::new(); let publisher = context.socket(zmq::PUB).unwrap(); assert!(publisher.bind("tcp://*:5556").is_ok()); assert!(publisher.bind("ipc://weather.ipc").is_ok()); let mut rng = rand::thread_rng(); loop { let zipcode = rng.gen_range(0, 100_000); let temperature = rng.gen_range(-80, 135); let relhumidity = rng.gen_range(10, 60); // this is slower than C because the current format! implementation is // very, very slow. Several orders of magnitude slower than glibc's // sprintf let update = format!("{:05} {} {}", zipcode, temperature, relhumidity); publisher.send(&update, 0).unwrap(); } // note: destructors mean no explicit cleanup necessary } zmq-0.9.2/examples/zguide/wuproxy/main.rs010064400017500001750000000007041347400165600167150ustar0000000000000000#![crate_name = "wuproxy"] fn main() { let context = zmq::Context::new(); let frontend = context.socket(zmq::XSUB).unwrap(); let backend = context.socket(zmq::XPUB).unwrap(); frontend .connect("tcp://192.168.55.210:5556") .expect("failed connecting frontend"); backend .bind("tcp://10.1.1.0:8100") .expect("failed binding backend"); zmq::proxy(&frontend, &backend).expect("failed proxying"); } zmq-0.9.2/src/lib.rs010064400017500001750000001302771354137150100124670ustar0000000000000000//! Module: zmq #![allow(trivial_numeric_casts)] use bitflags::bitflags; use libc::{c_int, c_long, c_short}; use log::debug; use std::ffi; use std::fmt; use std::marker::PhantomData; use std::os::raw::c_void; use std::result; use std::string::FromUtf8Error; use std::sync::Arc; use std::{mem, ptr, str}; use zmq_sys::{errno, RawFd}; macro_rules! zmq_try { ($($tt:tt)*) => {{ let rc = $($tt)*; if rc == -1 { return Err(crate::errno_to_error()); } rc }} } mod message; mod sockopt; use crate::message::msg_ptr; pub use crate::message::Message; pub use crate::SocketType::*; /// `zmq`-specific Result type. pub type Result = result::Result; /// Socket types #[allow(non_camel_case_types)] #[derive(Clone, Copy, Debug, PartialEq)] pub enum SocketType { PAIR, PUB, SUB, REQ, REP, DEALER, ROUTER, PULL, PUSH, XPUB, XSUB, STREAM, } impl SocketType { fn to_raw(self) -> c_int { let raw = match self { PAIR => zmq_sys::ZMQ_PAIR, PUB => zmq_sys::ZMQ_PUB, SUB => zmq_sys::ZMQ_SUB, REQ => zmq_sys::ZMQ_REQ, REP => zmq_sys::ZMQ_REP, DEALER => zmq_sys::ZMQ_DEALER, ROUTER => zmq_sys::ZMQ_ROUTER, PULL => zmq_sys::ZMQ_PULL, PUSH => zmq_sys::ZMQ_PUSH, XPUB => zmq_sys::ZMQ_XPUB, XSUB => zmq_sys::ZMQ_XSUB, STREAM => zmq_sys::ZMQ_STREAM, }; raw as c_int } fn from_raw(raw: c_int) -> SocketType { match raw as u32 { zmq_sys::ZMQ_PAIR => PAIR, zmq_sys::ZMQ_PUB => PUB, zmq_sys::ZMQ_SUB => SUB, zmq_sys::ZMQ_REQ => REQ, zmq_sys::ZMQ_REP => REP, zmq_sys::ZMQ_DEALER => DEALER, zmq_sys::ZMQ_ROUTER => ROUTER, zmq_sys::ZMQ_PULL => PULL, zmq_sys::ZMQ_PUSH => PUSH, zmq_sys::ZMQ_XPUB => XPUB, zmq_sys::ZMQ_XSUB => XSUB, zmq_sys::ZMQ_STREAM => STREAM, _ => panic!("socket type is out of range!"), } } } /// Socket Events #[allow(non_camel_case_types)] #[derive(Clone, Copy, Debug, PartialEq)] pub enum SocketEvent { // TODO: This should become a proper enum, including the data. CONNECTED = zmq_sys::ZMQ_EVENT_CONNECTED as isize, CONNECT_DELAYED = zmq_sys::ZMQ_EVENT_CONNECT_DELAYED as isize, CONNECT_RETRIED = zmq_sys::ZMQ_EVENT_CONNECT_RETRIED as isize, LISTENING = zmq_sys::ZMQ_EVENT_LISTENING as isize, BIND_FAILED = zmq_sys::ZMQ_EVENT_BIND_FAILED as isize, ACCEPTED = zmq_sys::ZMQ_EVENT_ACCEPTED as isize, ACCEPT_FAILED = zmq_sys::ZMQ_EVENT_ACCEPT_FAILED as isize, CLOSED = zmq_sys::ZMQ_EVENT_CLOSED as isize, CLOSE_FAILED = zmq_sys::ZMQ_EVENT_CLOSE_FAILED as isize, DISCONNECTED = zmq_sys::ZMQ_EVENT_DISCONNECTED as isize, MONITOR_STOPPED = zmq_sys::ZMQ_EVENT_MONITOR_STOPPED as isize, HANDSHAKE_FAILED_NO_DETAIL = zmq_sys::ZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL as isize, HANDSHAKE_SUCCEEDED = zmq_sys::ZMQ_EVENT_HANDSHAKE_SUCCEEDED as isize, HANDSHAKE_FAILED_PROTOCOL = zmq_sys::ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL as isize, HANDSHAKE_FAILED_AUTH = zmq_sys::ZMQ_EVENT_HANDSHAKE_FAILED_AUTH as isize, ALL = zmq_sys::ZMQ_EVENT_ALL as isize, } impl SocketEvent { pub fn to_raw(self) -> u16 { self as u16 } // TODO: this should not need to be public pub fn from_raw(raw: u16) -> SocketEvent { use SocketEvent::*; match u32::from(raw) { zmq_sys::ZMQ_EVENT_CONNECTED => CONNECTED, zmq_sys::ZMQ_EVENT_CONNECT_DELAYED => CONNECT_DELAYED, zmq_sys::ZMQ_EVENT_CONNECT_RETRIED => CONNECT_RETRIED, zmq_sys::ZMQ_EVENT_LISTENING => LISTENING, zmq_sys::ZMQ_EVENT_BIND_FAILED => BIND_FAILED, zmq_sys::ZMQ_EVENT_ACCEPTED => ACCEPTED, zmq_sys::ZMQ_EVENT_ACCEPT_FAILED => ACCEPT_FAILED, zmq_sys::ZMQ_EVENT_CLOSED => CLOSED, zmq_sys::ZMQ_EVENT_CLOSE_FAILED => CLOSE_FAILED, zmq_sys::ZMQ_EVENT_DISCONNECTED => DISCONNECTED, zmq_sys::ZMQ_EVENT_MONITOR_STOPPED => MONITOR_STOPPED, zmq_sys::ZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL => HANDSHAKE_FAILED_NO_DETAIL, zmq_sys::ZMQ_EVENT_HANDSHAKE_SUCCEEDED => HANDSHAKE_SUCCEEDED, zmq_sys::ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL => HANDSHAKE_FAILED_PROTOCOL, zmq_sys::ZMQ_EVENT_HANDSHAKE_FAILED_AUTH => HANDSHAKE_FAILED_AUTH, zmq_sys::ZMQ_EVENT_ALL => ALL, x => panic!("unknown event type {}", x), } } } /// Flag for socket `send` methods that specifies non-blocking mode. pub static DONTWAIT: i32 = zmq_sys::ZMQ_DONTWAIT as i32; /// Flag for socket `send` methods that specifies that more frames of a /// multipart message will follow. pub static SNDMORE: i32 = zmq_sys::ZMQ_SNDMORE as i32; /// Security Mechanism #[allow(non_camel_case_types)] #[derive(Clone, Copy, Debug, PartialEq)] pub enum Mechanism { // TODO: Fix the naming ZMQ_NULL, ZMQ_PLAIN, ZMQ_CURVE, ZMQ_GSSAPI, } /// An error returned by a 0MQ API function. #[derive(Clone, Copy, Eq, PartialEq)] pub enum Error { EACCES, EADDRINUSE, EAGAIN, EBUSY, ECONNREFUSED, EFAULT, EINTR, EHOSTUNREACH, EINPROGRESS, EINVAL, EMFILE, EMSGSIZE, ENAMETOOLONG, ENODEV, ENOENT, ENOMEM, ENOTCONN, ENOTSOCK, EPROTO, EPROTONOSUPPORT, ENOTSUP, ENOBUFS, ENETDOWN, EADDRNOTAVAIL, // native zmq error codes EFSM, ENOCOMPATPROTO, ETERM, EMTHREAD, } impl Error { pub fn to_raw(self) -> i32 { match self { Error::EACCES => errno::EACCES, Error::EADDRINUSE => errno::EADDRINUSE, Error::EAGAIN => errno::EAGAIN, Error::EBUSY => errno::EBUSY, Error::ECONNREFUSED => errno::ECONNREFUSED, Error::EFAULT => errno::EFAULT, Error::EINTR => errno::EINTR, Error::EHOSTUNREACH => errno::EHOSTUNREACH, Error::EINPROGRESS => errno::EINPROGRESS, Error::EINVAL => errno::EINVAL, Error::EMFILE => errno::EMFILE, Error::EMSGSIZE => errno::EMSGSIZE, Error::ENAMETOOLONG => errno::ENAMETOOLONG, Error::ENODEV => errno::ENODEV, Error::ENOENT => errno::ENOENT, Error::ENOMEM => errno::ENOMEM, Error::ENOTCONN => errno::ENOTCONN, Error::ENOTSOCK => errno::ENOTSOCK, Error::EPROTO => errno::EPROTO, Error::EPROTONOSUPPORT => errno::EPROTONOSUPPORT, Error::ENOTSUP => errno::ENOTSUP, Error::ENOBUFS => errno::ENOBUFS, Error::ENETDOWN => errno::ENETDOWN, Error::EADDRNOTAVAIL => errno::EADDRNOTAVAIL, Error::EFSM => errno::EFSM, Error::ENOCOMPATPROTO => errno::ENOCOMPATPROTO, Error::ETERM => errno::ETERM, Error::EMTHREAD => errno::EMTHREAD, } } pub fn from_raw(raw: i32) -> Error { match raw { errno::EACCES => Error::EACCES, errno::EADDRINUSE => Error::EADDRINUSE, errno::EAGAIN => Error::EAGAIN, errno::EBUSY => Error::EBUSY, errno::ECONNREFUSED => Error::ECONNREFUSED, errno::EFAULT => Error::EFAULT, errno::EHOSTUNREACH => Error::EHOSTUNREACH, errno::EINPROGRESS => Error::EINPROGRESS, errno::EINVAL => Error::EINVAL, errno::EMFILE => Error::EMFILE, errno::EMSGSIZE => Error::EMSGSIZE, errno::ENAMETOOLONG => Error::ENAMETOOLONG, errno::ENODEV => Error::ENODEV, errno::ENOENT => Error::ENOENT, errno::ENOMEM => Error::ENOMEM, errno::ENOTCONN => Error::ENOTCONN, errno::ENOTSOCK => Error::ENOTSOCK, errno::EPROTO => Error::EPROTO, errno::EPROTONOSUPPORT => Error::EPROTONOSUPPORT, errno::ENOTSUP => Error::ENOTSUP, errno::ENOBUFS => Error::ENOBUFS, errno::ENETDOWN => Error::ENETDOWN, errno::EADDRNOTAVAIL => Error::EADDRNOTAVAIL, errno::EINTR => Error::EINTR, // These may turn up on platforms that don't support these // errno codes natively (Windows) errno::ENOTSUP_ALT => Error::ENOTSUP, errno::EPROTONOSUPPORT_ALT => Error::EPROTONOSUPPORT, errno::ENOBUFS_ALT => Error::ENOBUFS, errno::ENETDOWN_ALT => Error::ENETDOWN, errno::EADDRINUSE_ALT => Error::EADDRINUSE, errno::EADDRNOTAVAIL_ALT => Error::EADDRNOTAVAIL, errno::ECONNREFUSED_ALT => Error::ECONNREFUSED, errno::EINPROGRESS_ALT => Error::EINPROGRESS, errno::ENOTSOCK_ALT => Error::ENOTSOCK, errno::EMSGSIZE_ALT => Error::EMSGSIZE, // TODO: these are present in `zmq-sys`, but not handled, as that // would break backwards-compatibility for the `Error` enum. // errno::EAFNOSUPPORT_ALT => Error::EAFNOSUPPORT, // errno::ENETUNREACH_ALT => Error::ENETUNREACH, // errno::ECONNABORTED_ALT => Error::ECONNABORTED, // errno::ECONNRESET_ALT => Error::ECONNRESET, // errno::ENOTCONN_ALT => Error::ENOTCONN, // errno::ETIMEDOUT_ALT => Error::ETIMEDOUT, // errno::EHOSTUNREACH_ALT => Error::EHOSTUNREACH, // errno::ENETRESET_ALT => Error::ENETRESET, // 0MQ native error codes errno::EFSM => Error::EFSM, errno::ENOCOMPATPROTO => Error::ENOCOMPATPROTO, errno::ETERM => Error::ETERM, errno::EMTHREAD => Error::EMTHREAD, x => unsafe { let s = zmq_sys::zmq_strerror(x); panic!( "unknown error [{}]: {}", x, str::from_utf8(ffi::CStr::from_ptr(s).to_bytes()).unwrap() ) }, } } } impl std::error::Error for Error { fn description(&self) -> &str { unsafe { let s = zmq_sys::zmq_strerror(self.to_raw()); let v: &'static [u8] = mem::transmute(ffi::CStr::from_ptr(s).to_bytes()); str::from_utf8(v).unwrap() } } } impl std::fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { unsafe { let s = zmq_sys::zmq_strerror(self.to_raw()); let v: &'static [u8] = mem::transmute(ffi::CStr::from_ptr(s).to_bytes()); write!(f, "{}", str::from_utf8(v).unwrap()) } } } impl fmt::Debug for Error { /// Return the error string for an error. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { unsafe { let s = zmq_sys::zmq_strerror(self.to_raw()); write!( f, "{}", str::from_utf8(ffi::CStr::from_ptr(s).to_bytes()).unwrap() ) } } } impl From for std::io::Error { fn from(error: Error) -> Self { use std::io::ErrorKind; let kind = match error { Error::ENOENT => ErrorKind::NotFound, Error::EACCES => ErrorKind::PermissionDenied, Error::ECONNREFUSED => ErrorKind::ConnectionRefused, Error::ENOTCONN => ErrorKind::NotConnected, Error::EADDRINUSE => ErrorKind::AddrInUse, Error::EADDRNOTAVAIL => ErrorKind::AddrNotAvailable, Error::EAGAIN => ErrorKind::WouldBlock, Error::EINVAL => ErrorKind::InvalidInput, Error::EINTR => ErrorKind::Interrupted, _ => ErrorKind::Other, }; // TODO: With rust 1.14 and up there is an optimization // opportunity using `std::io::Error: From` when // `kind != Other`. We should do that once 1.14 has been // stable for a bit. std::io::Error::new(kind, error) } } fn errno_to_error() -> Error { Error::from_raw(unsafe { zmq_sys::zmq_errno() }) } /// Return the current zeromq version, as `(major, minor, patch)`. pub fn version() -> (i32, i32, i32) { let mut major = 0; let mut minor = 0; let mut patch = 0; unsafe { zmq_sys::zmq_version(&mut major, &mut minor, &mut patch); } (major as i32, minor as i32, patch as i32) } struct RawContext { ctx: *mut c_void, } impl RawContext { fn term(&self) -> Result<()> { zmq_try!(unsafe { zmq_sys::zmq_ctx_term(self.ctx) }); Ok(()) } } unsafe impl Send for RawContext {} unsafe impl Sync for RawContext {} impl Drop for RawContext { fn drop(&mut self) { debug!("context dropped"); let mut e = self.term(); while e == Err(Error::EINTR) { e = self.term(); } } } /// Handle for a 0MQ context, used to create sockets. /// /// It is thread safe, and can be safely cloned and shared. Each clone /// references the same underlying C context. Internally, an `Arc` is /// used to implement this in a threadsafe way. /// /// Also note that this binding deviates from the C API in that each /// socket created from a context initially owns a clone of that /// context. This reference is kept to avoid a potential deadlock /// situation that would otherwise occur: /// /// Destroying the underlying C context is an operation which /// blocks waiting for all sockets created from it to be closed /// first. If one of the sockets belongs to thread issuing the /// destroy operation, you have established a deadlock. /// /// You can still deadlock yourself (or intentionally close sockets in /// other threads, see `zmq_ctx_destroy`(3)) by explicitly calling /// `Context::destroy`. /// #[derive(Clone)] pub struct Context { raw: Arc, } impl Context { /// Create a new reference-counted context handle. pub fn new() -> Context { Context { raw: Arc::new(RawContext { ctx: unsafe { zmq_sys::zmq_ctx_new() }, }), } } /// Create a new socket. /// /// Note that the returned socket keeps a an `Arc` reference to /// the context it was created from, and will keep that context /// from being dropped while being live. pub fn socket(&self, socket_type: SocketType) -> Result { let sock = unsafe { zmq_sys::zmq_socket(self.raw.ctx, socket_type.to_raw()) }; if sock.is_null() { return Err(errno_to_error()); } Ok(Socket { sock, context: Some(self.clone()), owned: true, }) } /// Try to destroy the context. This is different than the destructor; the /// destructor will loop when zmq_ctx_term returns EINTR. pub fn destroy(&mut self) -> Result<()> { self.raw.term() } } impl Default for Context { fn default() -> Self { Context::new() } } /// A socket, the central object in 0MQ. pub struct Socket { sock: *mut c_void, // The `context` field is never accessed, but implicitly does // reference counting via the `Drop` trait. #[allow(dead_code)] context: Option, owned: bool, } unsafe impl Send for Socket {} impl Drop for Socket { fn drop(&mut self) { if self.owned { if unsafe { zmq_sys::zmq_close(self.sock) } == -1 { panic!(errno_to_error()); } else { debug!("socket dropped"); } } } } macro_rules! sockopt_getter { ( $(#[$meta:meta])* pub $getter:ident => $constant_name:ident as $ty:ty ) => { $(#[$meta])* pub fn $getter(&self) -> Result<$ty> { <$ty as sockopt::Getter>::get(self.sock, zmq_sys::$constant_name as c_int) } }; } macro_rules! sockopt_setter { ( $(#[$meta:meta])* pub $setter:ident => $constant_name:ident as $ty:ty ) => { $(#[$meta])* pub fn $setter(&self, value: $ty) -> Result<()> { <$ty as sockopt::Setter>::set(self.sock, zmq_sys::$constant_name as c_int, value) } }; } macro_rules! sockopt_seq { ( META { $($meta:meta)* }, ) => (); ( META { $($meta:meta)* }, $(#[$item_meta:meta])* (_, $setter:ident) => $constant_name:ident as $ty:ty, $($rest:tt)* ) => { sockopt_setter! { $(#[$meta])* $(#[$item_meta])* pub $setter => $constant_name as $ty } sockopt_seq!(META { $($meta)* }, $($rest)*); }; ( META { $($meta:meta)* }, $(#[$item_meta:meta])* ($getter:ident) => $constant_name:ident as $ty:ty, $($rest:tt)* ) => { sockopt_getter! { $(#[$meta])* $(#[$item_meta])* pub $getter => $constant_name as $ty } sockopt_seq!(META { $($meta)* }, $($rest)*); }; ( META { $($meta:meta)* }, $(#[$item_meta:meta])* ($getter:ident, $setter:ident) => $constant_name:ident as $ty:ty, $($rest:tt)* ) => { sockopt_getter! { $(#[$meta])* $(#[$item_meta])* pub $getter => $constant_name as $ty } sockopt_setter! { $(#[$meta])* $(#[$item_meta])* pub $setter => $constant_name as $ty } sockopt_seq!(META { $($meta)* }, $($rest)*); }; } macro_rules! sockopts { () => (); ( $($rest:tt)* ) => { sockopt_seq!(META {}, $($rest)*); }; } /// Sendable over a `Socket`. /// /// A type can implement this trait there is an especially efficient /// implementation for sending it as a message over a zmq socket. /// /// If the type needs to be directly passed to `Socket::send()`, but /// the overhead of allocating a `Message` instance is not an issue, /// `Into` should be implemented instead. /// pub trait Sendable { fn send(self, socket: &Socket, flags: i32) -> Result<()>; } impl Sendable for T where T: Into, { fn send(self, socket: &Socket, flags: i32) -> Result<()> { let mut msg = self.into(); zmq_try!(unsafe { zmq_sys::zmq_msg_send(msg_ptr(&mut msg), socket.sock, flags as c_int) }); Ok(()) } } impl Socket { /// Consume the Socket and return the raw socket pointer. /// /// Failure to close the raw socket manually or call `from_raw` /// will lead to a memory leak. Also note that is function /// relinquishes the reference on the context is was created from. pub fn into_raw(mut self) -> *mut c_void { self.owned = false; self.sock } /// Create a Socket from a raw socket pointer. /// /// The Socket assumes ownership of the pointer and will close the socket /// when it is dropped. The returned socket will not reference any context. pub unsafe fn from_raw(sock: *mut c_void) -> Socket { Socket { sock, context: None, owned: true, } } /// Return the inner pointer to this Socket. /// /// **WARNING**: /// It is your responsibility to make sure that the underlying /// memory is not freed too early. pub fn as_mut_ptr(&mut self) -> *mut c_void { self.sock } /// Accept connections on a socket. pub fn bind(&self, endpoint: &str) -> Result<()> { let c_str = ffi::CString::new(endpoint.as_bytes()).unwrap(); zmq_try!(unsafe { zmq_sys::zmq_bind(self.sock, c_str.as_ptr()) }); Ok(()) } /// Connect a socket. pub fn connect(&self, endpoint: &str) -> Result<()> { let c_str = ffi::CString::new(endpoint.as_bytes()).unwrap(); zmq_try!(unsafe { zmq_sys::zmq_connect(self.sock, c_str.as_ptr()) }); Ok(()) } /// Disconnect a previously connected socket pub fn disconnect(&self, endpoint: &str) -> Result<()> { let c_str = ffi::CString::new(endpoint.as_bytes()).unwrap(); zmq_try!(unsafe { zmq_sys::zmq_disconnect(self.sock, c_str.as_ptr()) }); Ok(()) } /// Configure the socket for monitoring pub fn monitor(&self, monitor_endpoint: &str, events: i32) -> Result<()> { let c_str = ffi::CString::new(monitor_endpoint.as_bytes()).unwrap(); zmq_try!(unsafe { zmq_sys::zmq_socket_monitor(self.sock, c_str.as_ptr(), events as c_int) }); Ok(()) } /// Send a message. /// /// Due to the provided `From` implementations, this works for /// `&[u8]`, `Vec` and `&str` `Message` itself. pub fn send(&self, data: T, flags: i32) -> Result<()> where T: Sendable, { data.send(self, flags) } /// Send a `Message` message. #[deprecated(since = "0.9.0", note = "Use `send` instead")] pub fn send_msg(&self, msg: Message, flags: i32) -> Result<()> { self.send(msg, flags) } #[deprecated(since = "0.9.0", note = "Use `send` instead")] pub fn send_str(&self, data: &str, flags: i32) -> Result<()> { self.send(data, flags) } pub fn send_multipart(&self, iter: I, flags: i32) -> Result<()> where I: IntoIterator, T: Into, { let mut last_part: Option = None; for part in iter { let maybe_last = last_part.take(); if let Some(last) = maybe_last { self.send(last.into(), flags | SNDMORE)?; } last_part = Some(part); } if let Some(last) = last_part { self.send(last.into(), flags) } else { Ok(()) } } /// Receive a message into a `Message`. The length passed to zmq_msg_recv /// is the length of the buffer. pub fn recv(&self, msg: &mut Message, flags: i32) -> Result<()> { zmq_try!(unsafe { zmq_sys::zmq_msg_recv(msg_ptr(msg), self.sock, flags as c_int) }); Ok(()) } /// Receive bytes into a slice. The length passed to `zmq_recv` is the length of the slice. The /// return value is the number of bytes in the message, which may be larger than the length of /// the slice, indicating truncation. pub fn recv_into(&self, bytes: &mut [u8], flags: i32) -> Result { let bytes_ptr = bytes.as_mut_ptr() as *mut c_void; let rc = zmq_try!(unsafe { zmq_sys::zmq_recv(self.sock, bytes_ptr, bytes.len(), flags as c_int) }); Ok(rc as usize) } /// Receive a message into a fresh `Message`. pub fn recv_msg(&self, flags: i32) -> Result { let mut msg = Message::new(); self.recv(&mut msg, flags).map(|_| msg) } /// Receive a message as a byte vector. pub fn recv_bytes(&self, flags: i32) -> Result> { self.recv_msg(flags).map(|msg| msg.to_vec()) } /// Receive a `String` from the socket. /// /// If the received message is not valid UTF-8, it is returned as the original /// Vec in the `Err` part of the inner result. pub fn recv_string(&self, flags: i32) -> Result>> { self.recv_bytes(flags) .map(|bytes| String::from_utf8(bytes).map_err(FromUtf8Error::into_bytes)) } /// Receive a multipart message from the socket. /// /// Note that this will allocate a new vector for each message part; for /// many applications it will be possible to process the different parts /// sequentially and reuse allocations that way. pub fn recv_multipart(&self, flags: i32) -> Result>> { let mut parts: Vec> = vec![]; loop { let part = self.recv_bytes(flags)?; parts.push(part); let more_parts = self.get_rcvmore()?; if !more_parts { break; } } Ok(parts) } sockopts! { /// Accessor for the `ZMQ_IPV6` option. (is_ipv6, set_ipv6) => ZMQ_IPV6 as bool, /// Accessor for the `ZMQ_IMMEDIATE` option. (is_immediate, set_immediate) => ZMQ_IMMEDIATE as bool, /// Accessor for the `ZMQ_PLAIN_SERVER` option. (is_plain_server, set_plain_server) => ZMQ_PLAIN_SERVER as bool, /// Accessor for the `ZMQ_CONFLATE` option. (is_conflate, set_conflate) => ZMQ_CONFLATE as bool, (is_probe_router, set_probe_router) => ZMQ_PROBE_ROUTER as bool, (is_router_mandatory, set_router_mandatory) => ZMQ_ROUTER_MANDATORY as bool, (is_router_handover, set_router_handover) => ZMQ_ROUTER_HANDOVER as bool, (is_curve_server, set_curve_server) => ZMQ_CURVE_SERVER as bool, (is_gssapi_server, set_gssapi_server) => ZMQ_GSSAPI_SERVER as bool, (is_gssapi_plaintext, set_gssapi_plaintext) => ZMQ_GSSAPI_PLAINTEXT as bool, (_, set_req_relaxed) => ZMQ_REQ_RELAXED as bool, (_, set_req_correlate) => ZMQ_REQ_CORRELATE as bool, } /// Return the type of this socket. pub fn get_socket_type(&self) -> Result { sockopt::get(self.sock, zmq_sys::ZMQ_TYPE as c_int).map(SocketType::from_raw) } /// Return true if there are more frames of a multipart message to receive. pub fn get_rcvmore(&self) -> Result { sockopt::get(self.sock, zmq_sys::ZMQ_RCVMORE as c_int).map(|o: i64| o == 1i64) } sockopts! { (get_maxmsgsize, set_maxmsgsize) => ZMQ_MAXMSGSIZE as i64, (get_sndhwm, set_sndhwm) => ZMQ_SNDHWM as i32, (get_rcvhwm, set_rcvhwm) => ZMQ_RCVHWM as i32, (get_affinity, set_affinity) => ZMQ_AFFINITY as u64, (get_rate, set_rate) => ZMQ_RATE as i32, (get_recovery_ivl, set_recovery_ivl) => ZMQ_RECOVERY_IVL as i32, (get_sndbuf, set_sndbuf) => ZMQ_SNDBUF as i32, (get_rcvbuf, set_rcvbuf) => ZMQ_RCVBUF as i32, (get_tos, set_tos) => ZMQ_TOS as i32, (get_linger, set_linger) => ZMQ_LINGER as i32, (get_reconnect_ivl, set_reconnect_ivl) => ZMQ_RECONNECT_IVL as i32, (get_reconnect_ivl_max, set_reconnect_ivl_max) => ZMQ_RECONNECT_IVL_MAX as i32, (get_backlog, set_backlog) => ZMQ_BACKLOG as i32, /// Get the event notification file descriptor. /// /// Getter for the `ZMQ_FD` option. Note that the returned /// type is platform-specific; it aliases either /// `std::os::unix::io::RawFd` and or /// `std::os::windows::io::RawSocket`. /// /// Note that the returned file desciptor has special /// semantics: it should only used with an operating system /// facility like Unix `poll()` to check its readability. (get_fd) => ZMQ_FD as RawFd, /// Get the currently pending events. /// /// Note that the result of this function can also change due /// to receiving or sending a message on the socket, without /// the signalling FD (see `Socket::get_fd()`). /// /// # Examples /// /// ``` /// use zmq; /// let ctx = zmq::Context::new(); /// let socket = ctx.socket(zmq::REQ).unwrap(); /// let events = socket.get_events().unwrap(); /// if events.contains(zmq::POLLIN) { /// println!("socket readable") /// } /// drop(socket); /// ``` /// /// # Compatibility /// /// This function currently returns the bitmask as an `i32` /// for backwards compatibility; in effect it should have been /// using the same type as `PollItem::get_revents()` all /// along. /// /// In the `0.9` series, this will be rectified. (get_events) => ZMQ_EVENTS as PollEvents, (get_multicast_hops, set_multicast_hops) => ZMQ_MULTICAST_HOPS as i32, (get_rcvtimeo, set_rcvtimeo) => ZMQ_RCVTIMEO as i32, (get_sndtimeo, set_sndtimeo) => ZMQ_SNDTIMEO as i32, (get_tcp_keepalive, set_tcp_keepalive) => ZMQ_TCP_KEEPALIVE as i32, (get_tcp_keepalive_cnt, set_tcp_keepalive_cnt) => ZMQ_TCP_KEEPALIVE_CNT as i32, (get_tcp_keepalive_idle, set_tcp_keepalive_idle) => ZMQ_TCP_KEEPALIVE_IDLE as i32, (get_tcp_keepalive_intvl, set_tcp_keepalive_intvl) => ZMQ_TCP_KEEPALIVE_INTVL as i32, (get_handshake_ivl, set_handshake_ivl) => ZMQ_HANDSHAKE_IVL as i32, // TODO: deprecate to align with ZMQ's preferred naming (_, set_identity) => ZMQ_ROUTING_ID as &[u8], (_, set_subscribe) => ZMQ_SUBSCRIBE as &[u8], (_, set_unsubscribe) => ZMQ_UNSUBSCRIBE as &[u8], (get_heartbeat_ivl, set_heartbeat_ivl) => ZMQ_HEARTBEAT_IVL as i32, (get_heartbeat_ttl, set_heartbeat_ttl) => ZMQ_HEARTBEAT_TTL as i32, (get_heartbeat_timeout, set_heartbeat_timeout) => ZMQ_HEARTBEAT_TIMEOUT as i32, (get_connect_timeout, set_connect_timeout) => ZMQ_CONNECT_TIMEOUT as i32, } // TODO: deprecate to align with ZMQ's preferred naming pub fn get_identity(&self) -> Result> { // 255 = identity max length sockopt::get_bytes(self.sock, zmq_sys::ZMQ_ROUTING_ID as c_int, 255) } pub fn get_socks_proxy(&self) -> Result>> { // 255 = longest allowable domain name is 253 so this should // be a reasonable size. sockopt::get_string(self.sock, zmq_sys::ZMQ_SOCKS_PROXY as c_int, 255, true) } pub fn get_mechanism(&self) -> Result { sockopt::get(self.sock, zmq_sys::ZMQ_MECHANISM as c_int).map(|mech| match mech { zmq_sys::ZMQ_NULL => Mechanism::ZMQ_NULL, zmq_sys::ZMQ_PLAIN => Mechanism::ZMQ_PLAIN, zmq_sys::ZMQ_CURVE => Mechanism::ZMQ_CURVE, zmq_sys::ZMQ_GSSAPI => Mechanism::ZMQ_GSSAPI, _ => panic!("Mechanism is out of range!"), }) } pub fn get_plain_username(&self) -> Result>> { // 255 = arbitrary size sockopt::get_string(self.sock, zmq_sys::ZMQ_PLAIN_USERNAME as c_int, 255, true) } pub fn get_plain_password(&self) -> Result>> { // 256 = arbitrary size based on std crypto key size sockopt::get_string(self.sock, zmq_sys::ZMQ_PLAIN_PASSWORD as c_int, 256, true) } pub fn get_zap_domain(&self) -> Result>> { // 255 = arbitrary size sockopt::get_string(self.sock, zmq_sys::ZMQ_ZAP_DOMAIN as c_int, 255, true) } /// Return the address of the last endpoint this socket was bound to. /// /// Note that the returned address is not guaranteed to be the /// same as the one used with `bind`, and might also not be /// directly usable with `connect`. In particular, when `bind` is /// used with the wildcard address (`"*"`), in the address /// returned, the wildcard will be expanded into the any address /// (i.e. `0.0.0.0` with IPv4). pub fn get_last_endpoint(&self) -> Result>> { // 256 + 9 + 1 = maximum inproc name size (= 256) + "inproc://".len() (= 9), plus null byte sockopt::get_string( self.sock, zmq_sys::ZMQ_LAST_ENDPOINT as c_int, 256 + 9 + 1, true, ) } /// Set the `ZMQ_CURVE_PUBLICKEY` option value. /// /// The key is returned as raw bytes. Use `z85_encode` on the /// resulting data to get the Z85-encoded string representation of /// the key. pub fn get_curve_publickey(&self) -> Result> { sockopt::get_bytes(self.sock, zmq_sys::ZMQ_CURVE_PUBLICKEY as c_int, 32) } /// Get the `ZMQ_CURVE_SECRETKEY` option value. /// /// The key is returned as raw bytes. Use `z85_encode` on the /// resulting data to get the Z85-encoded string representation of /// the key. pub fn get_curve_secretkey(&self) -> Result> { sockopt::get_bytes(self.sock, zmq_sys::ZMQ_CURVE_SECRETKEY as c_int, 32) } /// Get `ZMQ_CURVE_SERVERKEY` option value. /// /// Note that the key is returned as raw bytes, as a 32-byte /// vector. Use `z85_encode()` explicitly to obtain the /// Z85-encoded string variant. pub fn get_curve_serverkey(&self) -> Result> { // 41 = Z85 encoded keysize + 1 for null byte sockopt::get_bytes(self.sock, zmq_sys::ZMQ_CURVE_SERVERKEY as c_int, 32) } pub fn get_gssapi_principal(&self) -> Result>> { // 260 = best guess of max length based on docs. sockopt::get_string(self.sock, zmq_sys::ZMQ_GSSAPI_PRINCIPAL as c_int, 260, true) } pub fn get_gssapi_service_principal(&self) -> Result>> { // 260 = best guess of max length based on docs. sockopt::get_string( self.sock, zmq_sys::ZMQ_GSSAPI_SERVICE_PRINCIPAL as c_int, 260, true, ) } sockopts! { (_, set_socks_proxy) => ZMQ_SOCKS_PROXY as Option<&str>, (_, set_plain_username) => ZMQ_PLAIN_USERNAME as Option<&str>, (_, set_plain_password) => ZMQ_PLAIN_PASSWORD as Option<&str>, (_, set_zap_domain) => ZMQ_ZAP_DOMAIN as &str, (_, set_xpub_welcome_msg) => ZMQ_XPUB_WELCOME_MSG as Option<&str>, (_, set_xpub_verbose) => ZMQ_XPUB_VERBOSE as bool, (_, set_curve_publickey) => ZMQ_CURVE_PUBLICKEY as &[u8], (_, set_curve_secretkey) => ZMQ_CURVE_SECRETKEY as &[u8], (_, set_curve_serverkey) => ZMQ_CURVE_SERVERKEY as &[u8], (_, set_gssapi_principal) => ZMQ_GSSAPI_PRINCIPAL as &str, (_, set_gssapi_service_principal) => ZMQ_GSSAPI_SERVICE_PRINCIPAL as &str, } /// Create a `PollItem` from the socket. pub fn as_poll_item(&self, events: PollEvents) -> PollItem { PollItem { socket: self.sock, fd: 0, events: events.bits(), revents: 0, marker: PhantomData, } } /// Do a call to `zmq_poll` with only this socket. /// /// The return value on success will be either zero (no event) or one (some /// event was signaled). pub fn poll(&self, events: PollEvents, timeout_ms: i64) -> Result { poll(&mut [self.as_poll_item(events)], timeout_ms) } } // TODO: Duplicating the values inside the bitflags struct and on the top level // is unfortunate. bitflags! { /// Type representing pending socket events. pub struct PollEvents: i16 { /// For `poll()`, specifies to signal when a message/some data /// can be read from a socket. const POLLIN = zmq_sys::ZMQ_POLLIN as i16; /// For `poll()`, specifies to signal when a message/some data /// can be written to a socket. const POLLOUT = zmq_sys::ZMQ_POLLOUT as i16; /// For `poll()`, specifies to signal when an error condition /// is present on a socket. This only applies to non-0MQ /// sockets. const POLLERR = zmq_sys::ZMQ_POLLERR as i16; } } /// For `poll()`, specifies to signal when a message/some data can be /// read from a socket. pub const POLLIN: PollEvents = PollEvents::POLLIN; /// For `poll()`, specifies to signal when a message/some data can be /// written to a socket. pub const POLLOUT: PollEvents = PollEvents::POLLOUT; /// For `poll()`, specifies to signal when an error condition is /// present on a socket. This only applies to non-0MQ sockets. pub const POLLERR: PollEvents = PollEvents::POLLERR; /// Represents a handle that can be `poll()`ed. /// /// This is either a reference to a 0MQ socket, or a standard socket. /// Apart from that it contains the requested event mask, and is updated /// with the occurred events after `poll()` finishes. #[repr(C)] pub struct PollItem<'a> { socket: *mut c_void, fd: RawFd, events: c_short, revents: c_short, marker: PhantomData<&'a Socket>, } impl<'a> PollItem<'a> { /// Construct a PollItem from a non-0MQ socket, given by its file /// descriptor and the events that should be polled. pub fn from_fd(fd: RawFd, events: PollEvents) -> PollItem<'a> { PollItem { socket: ptr::null_mut(), fd, events: events.bits(), revents: 0, marker: PhantomData, } } /// Change the events to wait for. pub fn set_events(&mut self, events: PollEvents) { self.events = events.bits(); } /// Retrieve the events that occurred for this handle. pub fn get_revents(&self) -> PollEvents { PollEvents::from_bits_truncate(self.revents) } /// Returns true if the polled socket has messages ready to receive. pub fn is_readable(&self) -> bool { (self.revents & POLLIN.bits()) != 0 } /// Returns true if the polled socket can accept messages to be sent /// without blocking. pub fn is_writable(&self) -> bool { (self.revents & POLLOUT.bits()) != 0 } /// Returns true if the polled socket encountered an error condition. pub fn is_error(&self) -> bool { (self.revents & POLLERR.bits()) != 0 } } /// Poll for events on multiple sockets. /// /// For every poll item given, the events given in the `events` bitmask are /// monitored, and signaled in `revents` when they occur. Any number of poll /// items can have events signaled when the function returns. /// /// The given timeout is in milliseconds and can be zero. A timeout of `-1` /// indicates to block indefinitely until an event has occurred. /// /// The result, if not `Err`, indicates the number of poll items that have /// events signaled. pub fn poll(items: &mut [PollItem], timeout: i64) -> Result { let rc = zmq_try!(unsafe { zmq_sys::zmq_poll( items.as_mut_ptr() as *mut zmq_sys::zmq_pollitem_t, items.len() as c_int, timeout as c_long, ) }); Ok(rc as i32) } /// Start a 0MQ proxy in the current thread. /// /// A proxy connects a frontend socket with a backend socket, where the exact /// behavior depends on the type of both sockets. /// /// This function only returns (always with an `Err`) when the sockets' context /// has been closed. pub fn proxy(frontend: &Socket, backend: &Socket) -> Result<()> { zmq_try!(unsafe { zmq_sys::zmq_proxy(frontend.sock, backend.sock, ptr::null_mut()) }); Ok(()) } /// Start a 0MQ proxy in the current thread, with a capture socket. /// /// The capture socket is sent all messages received on the frontend and backend /// sockets. pub fn proxy_with_capture( frontend: &mut Socket, backend: &mut Socket, capture: &mut Socket, ) -> Result<()> { zmq_try!(unsafe { zmq_sys::zmq_proxy(frontend.sock, backend.sock, capture.sock) }); Ok(()) } /// Start a 0MQ proxy in the current thread, with a control socket. /// /// If PAUSE is received on the control socket, the proxy suspends its activities. If RESUME is received, /// it goes on. If TERMINATE is received, it terminates smoothly. At start, the proxy runs normally /// as if `proxy` was used. pub fn proxy_steerable( frontend: &mut Socket, backend: &mut Socket, control: &mut Socket, ) -> Result<()> { zmq_try!(unsafe { zmq_sys::zmq_proxy_steerable(frontend.sock, backend.sock, ptr::null_mut(), control.sock) }); Ok(()) } /// Start a 0MQ proxy in the current thread, with capture and control sockets. /// /// Provides a steerable proxy with a capture socket. See `proxy_with_capture` pub fn proxy_steerable_with_capture( frontend: &mut Socket, backend: &mut Socket, capture: &mut Socket, control: &mut Socket, ) -> Result<()> { zmq_try!(unsafe { zmq_sys::zmq_proxy_steerable(frontend.sock, backend.sock, capture.sock, control.sock) }); Ok(()) } /// Return true if the used 0MQ library has the given capability. /// /// The return value is always the `Some` variant; it used to return /// `None` for older, now unsupported versions of 0MQ that didn't have /// the wrapped `zmq_has` function. Thus, for code that requires `zmq` /// version 0.9.0 or newer, you can safely call `unwrap` on the return /// value. /// /// For a list of capabilities, please consult the `zmq_has` manual /// page. /// /// # Compatibility /// /// In the `zmq` 0.10.0, this function will simply return `bool`. /// pub fn has(capability: &str) -> Option { let c_str = ffi::CString::new(capability).unwrap(); unsafe { Some(zmq_sys::zmq_has(c_str.as_ptr()) == 1) } } /// A CURVE key pair generated by 0MQ. /// /// Note that for API consistency reasons, since version 0.9, the key /// pair is represented in the binary form. This is in contrast to /// libzmq, which returns the z85-encoded representation. #[derive(Debug)] pub struct CurveKeyPair { pub public_key: [u8; 32], pub secret_key: [u8; 32], } impl CurveKeyPair { /// Create a new key pair. pub fn new() -> Result { // Curve keypairs are currently 40 bytes long, plus terminating NULL. let mut ffi_public_key = [0u8; 41]; let mut ffi_secret_key = [0u8; 41]; zmq_try!(unsafe { zmq_sys::zmq_curve_keypair( ffi_public_key.as_mut_ptr() as *mut libc::c_char, ffi_secret_key.as_mut_ptr() as *mut libc::c_char, ) }); let mut pair = CurveKeyPair { public_key: [0; 32], secret_key: [0; 32], }; unsafe { // No need to check return code here, as zmq_curve_keypair // is supposed to generate valid z85-encoded keys zmq_sys::zmq_z85_decode( pair.public_key.as_mut_ptr(), ffi_public_key.as_ptr() as *mut libc::c_char, ); zmq_sys::zmq_z85_decode( pair.secret_key.as_mut_ptr(), ffi_secret_key.as_ptr() as *mut libc::c_char, ); } Ok(pair) } } /// Errors that can occur while encoding Z85. #[derive(Debug)] pub enum EncodeError { BadLength, FromUtf8Error(FromUtf8Error), } impl From for EncodeError { fn from(err: FromUtf8Error) -> Self { EncodeError::FromUtf8Error(err) } } impl fmt::Display for EncodeError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { EncodeError::BadLength => write!(f, "Invalid data length. Should be multiple of 4."), EncodeError::FromUtf8Error(ref e) => write!(f, "UTF8 conversion error: {}", e), } } } impl std::error::Error for EncodeError { fn description(&self) -> &str { match *self { EncodeError::BadLength => "invalid data length", EncodeError::FromUtf8Error(ref e) => e.description(), } } } /// Encode a binary key as Z85 printable text. /// /// Z85 is an encoding similar to Base64, but operates on 4-byte chunks, /// which are encoded into 5-byte sequences. /// /// The input slice *must* have a length divisible by 4. pub fn z85_encode(data: &[u8]) -> result::Result { if data.len() % 4 != 0 { return Err(EncodeError::BadLength); } let len = data.len() * 5 / 4 + 1; let mut dest = vec![0u8; len]; unsafe { zmq_sys::zmq_z85_encode( dest.as_mut_ptr() as *mut libc::c_char, data.as_ptr(), data.len(), ); } dest.truncate(len - 1); String::from_utf8(dest).map_err(EncodeError::FromUtf8Error) } /// Errors that can occur while decoding Z85. #[derive(Debug)] pub enum DecodeError { /// The input string slice's length was not a multiple of 5. BadLength, /// The input string slice had embedded NUL bytes. NulError(ffi::NulError), } impl From for DecodeError { fn from(err: ffi::NulError) -> Self { DecodeError::NulError(err) } } impl fmt::Display for DecodeError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { DecodeError::BadLength => write!(f, "Invalid data length. Should be multiple of 5."), DecodeError::NulError(ref e) => write!(f, "Nul byte error: {}", e), } } } impl std::error::Error for DecodeError { fn description(&self) -> &str { match *self { DecodeError::BadLength => "invalid data length", DecodeError::NulError(ref e) => e.description(), } } } /// Decode a binary key from Z85-encoded text. /// /// The input string must have a length divisible by 5. /// /// Note that 0MQ silently accepts characters outside the range defined for /// the Z85 encoding. pub fn z85_decode(data: &str) -> result::Result, DecodeError> { if data.len() % 5 != 0 { return Err(DecodeError::BadLength); } let len = data.len() * 4 / 5; let mut dest = vec![0u8; len]; let c_str = ffi::CString::new(data)?; unsafe { zmq_sys::zmq_z85_decode(dest.as_mut_ptr(), c_str.into_raw()); } Ok(dest) } zmq-0.9.2/src/message.rs010064400017500001750000000163201354137544000133430ustar0000000000000000use libc::size_t; use std::ffi; use std::fmt; use std::ops::{Deref, DerefMut}; use std::os::raw::c_void; use std::{ptr, slice, str}; use super::errno_to_error; /// Holds a 0MQ message. /// /// A message is a single frame, either received or created locally and then /// sent over the wire. Multipart messages are transmitted as multiple /// `Message`s. /// /// In rust-zmq, you aren't required to create message objects if you use the /// convenience APIs provided (e.g. `Socket::recv_bytes()` or /// `Socket::send()`). However, using message objects can make multiple /// operations in a loop more efficient, since allocated memory can be reused. pub struct Message { msg: zmq_sys::zmq_msg_t, } impl Drop for Message { fn drop(&mut self) { unsafe { let rc = zmq_sys::zmq_msg_close(&mut self.msg); assert_eq!(rc, 0); } } } impl fmt::Debug for Message { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:?}", self.deref()) } } unsafe extern "C" fn drop_msg_content_box(data: *mut c_void, _hint: *mut c_void) { let _ = Box::from_raw(data as *mut u8); } impl Message { unsafe fn alloc(f: F) -> Message where F: FnOnce(&mut zmq_sys::zmq_msg_t) -> i32, { let mut msg = zmq_sys::zmq_msg_t::default(); let rc = f(&mut msg); if rc == -1 { panic!(errno_to_error()) } Message { msg } } /// Create an empty `Message`. pub fn new() -> Message { unsafe { Self::alloc(|msg| zmq_sys::zmq_msg_init(msg)) } } /// Create a `Message` preallocated with `len` uninitialized bytes. /// /// Since it is very easy to introduce undefined behavior using this /// function, its use is not recommended, and it will be removed in a future /// release. If there is a use-case that cannot be handled efficiently by /// the safe message constructors, please file an issue. #[deprecated( since = "0.9.1", note = "This method has an unintuitive name, and should not be needed." )] pub unsafe fn with_capacity_unallocated(len: usize) -> Message { Self::alloc(|msg| zmq_sys::zmq_msg_init_size(msg, len as size_t)) } unsafe fn with_size_uninit(len: usize) -> Message { Self::alloc(|msg| zmq_sys::zmq_msg_init_size(msg, len as size_t)) } /// Create a `Message` with space for `len` bytes that are initialized to 0. pub fn with_size(len: usize) -> Message { unsafe { let mut msg = Message::with_size_uninit(len); ptr::write_bytes(msg.as_mut_ptr(), 0, len); msg } } /// Create a `Message` with space for `len` bytes that are initialized to 0. #[deprecated( since = "0.9.1", note = "This method has a name which does not match its semantics. Use `with_size` instead" )] pub fn with_capacity(len: usize) -> Message { Self::with_size(len) } /// Create a `Message` from a `&[u8]`. This will copy `data` into the message. /// /// This is equivalent to using the `From<&[u8]>` trait. #[deprecated(since = "0.9.1", note = "Use the `From` trait instead.")] pub fn from_slice(data: &[u8]) -> Message { Self::from(data) } /// Return the message content as a string slice if it is valid UTF-8. pub fn as_str(&self) -> Option<&str> { str::from_utf8(self).ok() } /// Return the `ZMQ_MORE` flag, which indicates if more parts of a multipart /// message will follow. pub fn get_more(&self) -> bool { let rc = unsafe { zmq_sys::zmq_msg_more(&self.msg) }; rc != 0 } /// Query a message metadata property. /// /// # Non-UTF8 values /// /// The `zmq_msg_gets` man page notes "The encoding of the property and /// value shall be UTF8". However, this is not actually enforced. For API /// compatibility reasons, this function will return `None` when /// encountering a non-UTF8 value; so a missing and a non-UTF8 value cannot /// currently be distinguished. /// /// This is considered a bug in the bindings, and will be fixed with the /// next API-breaking release. pub fn gets<'a>(&'a mut self, property: &str) -> Option<&'a str> { let c_str = ffi::CString::new(property.as_bytes()).unwrap(); let value = unsafe { zmq_sys::zmq_msg_gets(&self.msg, c_str.as_ptr()) }; if value.is_null() { None } else { str::from_utf8(unsafe { ffi::CStr::from_ptr(value) }.to_bytes()).ok() } } } impl Deref for Message { type Target = [u8]; fn deref(&self) -> &[u8] { // This is safe because we're constraining the slice to the lifetime of // this message. unsafe { let ptr = &self.msg as *const _ as *mut _; let data = zmq_sys::zmq_msg_data(ptr); let len = zmq_sys::zmq_msg_size(ptr) as usize; slice::from_raw_parts(data as *mut u8, len) } } } impl PartialEq for Message { fn eq(&self, other: &Message) -> bool { self[..] == other[..] } } impl Eq for Message {} impl DerefMut for Message { fn deref_mut(&mut self) -> &mut [u8] { // This is safe because we're constraining the slice to the lifetime of // this message. unsafe { let data = zmq_sys::zmq_msg_data(&mut self.msg); let len = zmq_sys::zmq_msg_size(&self.msg) as usize; slice::from_raw_parts_mut(data as *mut u8, len) } } } impl<'a> From<&'a [u8]> for Message { /// Construct a message from a byte slice by copying the data. fn from(data: &'a [u8]) -> Self { unsafe { let mut msg = Message::with_size_uninit(data.len()); ptr::copy_nonoverlapping(data.as_ptr(), msg.as_mut_ptr(), data.len()); msg } } } impl From> for Message { /// Construct a message from a byte vector without copying the data. fn from(msg: Vec) -> Self { Message::from(msg.into_boxed_slice()) } } impl From> for Message { /// Construct a message from a boxed slice without copying the data. fn from(data: Box<[u8]>) -> Self { let n = data.len(); if n == 0 { return Message::new(); } let raw = Box::into_raw(data); unsafe { Self::alloc(|msg| { zmq_sys::zmq_msg_init_data( msg, raw as *mut c_void, n, Some(drop_msg_content_box), ptr::null_mut(), ) }) } } } impl<'a> From<&'a str> for Message { /// Construct a message from a string slice by copying the UTF-8 data. fn from(msg: &str) -> Self { Message::from(msg.as_bytes()) } } impl<'a> From<&'a String> for Message { /// Construct a message from a string slice by copying the UTF-8 data. fn from(msg: &String) -> Self { Message::from(msg.as_bytes()) } } impl<'a, T> From<&'a T> for Message where T: Into + Clone, { fn from(v: &'a T) -> Self { v.clone().into() } } /// Get the low-level C pointer. pub fn msg_ptr(msg: &mut Message) -> *mut zmq_sys::zmq_msg_t { &mut msg.msg } zmq-0.9.2/src/sockopt.rs010064400017500001750000000077241354137150100134030ustar0000000000000000use libc::{c_int, c_uint, size_t}; use std::os::raw::c_void; use std::result; use std::string::FromUtf8Error; use std::{mem, ptr, str}; use super::{PollEvents, Result}; pub trait Getter where Self: Sized, { fn get(sock: *mut c_void, opt: c_int) -> Result; } pub trait Setter where Self: Sized, { fn set(sock: *mut c_void, opt: c_int, value: Self) -> Result<()>; } macro_rules! getsockopt_num( ($c_ty:ty, $ty:ty) => ( impl Getter for $ty { #[allow(trivial_casts)] fn get(sock: *mut c_void, opt: c_int) -> Result<$ty> { let mut value: $c_ty = 0; let value_ptr = &mut value as *mut $c_ty; let mut size = mem::size_of::<$c_ty>() as size_t; zmq_try!(unsafe { zmq_sys::zmq_getsockopt( sock, opt, value_ptr as *mut c_void, &mut size) }); Ok(value as $ty) } } ) ); getsockopt_num!(c_int, i32); getsockopt_num!(c_uint, u32); getsockopt_num!(i64, i64); getsockopt_num!(u64, u64); pub fn get_bytes(sock: *mut c_void, opt: c_int, size: size_t) -> Result> { let mut size = size; let mut value = vec![0u8; size]; zmq_try!(unsafe { zmq_sys::zmq_getsockopt(sock, opt, value.as_mut_ptr() as *mut c_void, &mut size) }); value.truncate(size); Ok(value) } pub fn get_string( sock: *mut c_void, opt: c_int, size: size_t, remove_nulbyte: bool, ) -> Result>> { let mut value = get_bytes(sock, opt, size)?; if remove_nulbyte { value.pop(); } Ok(String::from_utf8(value).map_err(FromUtf8Error::into_bytes)) } macro_rules! setsockopt_num( ($ty:ty) => ( impl Setter for $ty { #[allow(trivial_casts)] fn set(sock: *mut c_void, opt: c_int, value: $ty) -> Result<()> { let size = mem::size_of::<$ty>() as size_t; zmq_try!(unsafe { zmq_sys::zmq_setsockopt( sock, opt, (&value as *const $ty) as *const c_void, size) }); Ok(()) } } ) ); setsockopt_num!(i32); setsockopt_num!(i64); setsockopt_num!(u64); fn setsockopt_null(sock: *mut c_void, opt: c_int) -> Result<()> { zmq_try!(unsafe { zmq_sys::zmq_setsockopt(sock, opt, ptr::null(), 0) }); Ok(()) } impl<'a> Setter for &'a str { fn set(sock: *mut c_void, opt: c_int, value: Self) -> Result<()> { set(sock, opt, value.as_bytes()) } } impl<'a> Setter for Option<&'a str> { fn set(sock: *mut c_void, opt: c_int, value: Self) -> Result<()> { if let Some(s) = value { set(sock, opt, s.as_bytes()) } else { setsockopt_null(sock, opt) } } } impl Getter for bool { fn get(sock: *mut c_void, opt: c_int) -> Result { let result: i32 = get(sock, opt)?; Ok(result == 1) } } impl Setter for bool { fn set(sock: *mut c_void, opt: c_int, value: Self) -> Result<()> { set(sock, opt, if value { 1i32 } else { 0i32 }) } } impl<'a> Setter for &'a [u8] { fn set(sock: *mut c_void, opt: c_int, value: &'a [u8]) -> Result<()> { zmq_try!(unsafe { zmq_sys::zmq_setsockopt( sock, opt, value.as_ptr() as *const c_void, value.len() as size_t, ) }); Ok(()) } } impl Getter for PollEvents { fn get(sock: *mut c_void, opt: c_int) -> Result { get::(sock, opt).map(|bits| PollEvents::from_bits_truncate(bits as i16)) } } pub fn get(sock: *mut c_void, opt: c_int) -> Result { T::get(sock, opt) } pub fn set(sock: *mut c_void, opt: c_int, value: T) -> Result<()> { T::set(sock, opt, value) } zmq-0.9.2/tests/common/mod.rs010064400017500001750000000014651354137150100143370ustar0000000000000000#![allow(dead_code)] pub extern crate timebomb; use std::sync::Once; static LOGGER_INIT: Once = Once::new(); #[macro_export] macro_rules! test { ($name:ident, $block:block) => { #[test] fn $name() { $crate::common::ensure_env_logger_initialized(); $crate::common::timebomb::timeout_ms(|| $block, 10000); } }; } #[macro_export] macro_rules! test_capability { ($name:ident, $capability:literal, $block:block) => { #[test] fn $name() { if zmq::has($capability).unwrap() { $crate::common::ensure_env_logger_initialized(); $crate::common::timebomb::timeout_ms(|| $block, 10000); } } }; } pub fn ensure_env_logger_initialized() { LOGGER_INIT.call_once(env_logger::init); } zmq-0.9.2/tests/compile-fail/no-leaking-poll-items.rs010064400017500001750000000003761347377750000207550ustar0000000000000000extern crate zmq; fn main() { let context = zmq::Context::new(); let _poll_item = { let socket = context.socket(zmq::PAIR).unwrap(); socket.as_poll_item(zmq::POLLIN) }; //~^ ERROR `socket` does not live long enough [E0597] } zmq-0.9.2/tests/compile-fail/socket-thread-unsafe.rs010064400017500001750000000007421347377750000206570ustar0000000000000000extern crate zmq; use std::thread; macro_rules! t { ($e:expr) => ( $e.unwrap_or_else(|e| { panic!("{} failed with {:?}", stringify!($e), e) }) ) } fn main() { let mut context = zmq::Context::new(); let socket = t!(context.socket(zmq::REP)); let s = &socket; let t = thread::spawn(move || { //~ cannot be shared between threads safely [E0277] t!(s.bind("tcp://127.0.0.1:12345")) }); socket.send("ABC", 0); t.join().unwrap(); } zmq-0.9.2/tests/compile-tests.rs010064400017500001750000000012311347400165600150550ustar0000000000000000use std::env::var; use std::path::PathBuf; fn run_mode(mode: &'static str) { let mut config = compiletest_rs::Config::default(); let cfg_mode = mode.parse().expect("Invalid mode"); config.target_rustcflags = Some(format!( "-L target/{profile} -L target/{profile}/deps", profile = env!("BUILD_PROFILE") )); if let Ok(name) = var::<&str>("TESTNAME") { let s: String = name.to_owned(); config.filter = Some(s) } config.mode = cfg_mode; config.src_base = PathBuf::from(format!("tests/{}", mode)); compiletest_rs::run_tests(&config); } #[test] fn compile_test() { run_mode("compile-fail"); } zmq-0.9.2/tests/connection.rs010064400017500001750000000053011354137150100144200ustar0000000000000000//! These are all tests using PUSH/PULL sockets created from a shared //! context to connect two threads. As a compile-time test, this //! creates one socket from a context, and passes this context to the //! child thread, along with the endpoint address to connect to. The //! second socket is the created in the child thread. #[macro_use] mod common; #[cfg(unix)] #[path = "unix/connection.rs"] mod unix; use std::str; use std::thread; test!(test_inproc, { with_connection( "inproc://pub", zmq::PUSH, send_message, zmq::PULL, check_recv, ); }); test!(test_tcp, { with_connection( "tcp://127.0.0.1:*", zmq::PUSH, send_message, zmq::PULL, check_recv, ); }); test!(test_poll_inproc, { with_connection( "inproc://pub", zmq::PUSH, send_message, zmq::PULL, check_poll, ); }); test!(test_poll_tcp, { with_connection( "tcp://127.0.0.1:*", zmq::PUSH, send_message, zmq::PULL, check_poll, ); }); fn send_message(_ctx: &zmq::Context, socket: &zmq::Socket) { socket.send("Message1", 0).unwrap(); } fn check_poll(_ctx: &zmq::Context, pull_socket: &zmq::Socket) { { let mut poll_items = vec![pull_socket.as_poll_item(zmq::POLLIN)]; assert_eq!(zmq::poll(&mut poll_items, 1000).unwrap(), 1); assert_eq!(poll_items[0].get_revents(), zmq::POLLIN); } let msg = pull_socket.recv_msg(zmq::DONTWAIT).unwrap(); assert_eq!(&msg[..], b"Message1"); } fn check_recv(_ctx: &zmq::Context, pull_socket: &zmq::Socket) { let msg = pull_socket.recv_msg(0).unwrap(); assert_eq!(&msg[..], b"Message1"); } // // Utilities // pub fn with_connection( address: &str, parent_type: zmq::SocketType, parent: F, child_type: zmq::SocketType, child: G, ) where F: for<'r> Fn(&'r zmq::Context, &zmq::Socket) + Send + 'static, G: for<'r> Fn(&'r zmq::Context, &zmq::Socket) + Send + 'static, { let ctx = zmq::Context::new(); let push_socket = ctx.socket(parent_type).unwrap(); push_socket.bind(address).unwrap(); let endpoint = push_socket.get_last_endpoint().unwrap().unwrap(); let thread = { let w_ctx = ctx.clone(); thread::spawn(move || { let pull_socket = connect_socket(&w_ctx, child_type, &endpoint).unwrap(); child(&w_ctx, &pull_socket); }) }; parent(&ctx, &push_socket); thread.join().unwrap(); } fn connect_socket( ctx: &zmq::Context, typ: zmq::SocketType, address: &str, ) -> Result { ctx.socket(typ) .and_then(|socket| socket.connect(address).map(|_| socket)) } zmq-0.9.2/tests/curve.rs010064400017500001750000000054241354137150100134130ustar0000000000000000#[macro_use] mod common; use zmq::{z85_decode, Context, CurveKeyPair, Socket}; fn create_socketpair() -> (Socket, Socket) { let ctx = Context::default(); let sender = ctx.socket(zmq::REQ).unwrap(); let receiver = ctx.socket(zmq::REP).unwrap(); let server_pair = CurveKeyPair::new().unwrap(); let client_pair = CurveKeyPair::new().unwrap(); // receiver socket acts as server, will accept connections receiver.set_curve_server(true).unwrap(); receiver .set_curve_secretkey(&server_pair.secret_key) .unwrap(); // sender socket, acts as client sender.set_curve_serverkey(&server_pair.public_key).unwrap(); sender.set_curve_publickey(&client_pair.public_key).unwrap(); sender.set_curve_secretkey(&client_pair.secret_key).unwrap(); receiver.bind("tcp://127.0.0.1:*").unwrap(); let ep = receiver.get_last_endpoint().unwrap().unwrap(); sender.connect(&ep).unwrap(); (sender, receiver) } test_capability!(test_curve_messages, "curve", { let (sender, receiver) = create_socketpair(); sender.send("foo", 0).unwrap(); let msg = receiver.recv_msg(0).unwrap(); assert_eq!(&msg[..], b"foo"); assert_eq!(msg.as_str(), Some("foo")); println!("this is it {0}", msg.as_str().unwrap()); assert_eq!(format!("{:?}", msg), "[102, 111, 111]"); receiver.send("bar", 0).unwrap(); let msg = sender.recv_msg(0).unwrap(); assert_eq!(&msg[..], b"bar"); }); test_capability!(test_curve_keypair, "curve", { let keypair = CurveKeyPair::new().unwrap(); assert!(keypair.public_key.len() == 32); assert!(keypair.secret_key.len() == 32); }); test_capability!(test_getset_curve_server, "curve", { let ctx = Context::new(); let sock = ctx.socket(zmq::REQ).unwrap(); sock.set_curve_server(true).unwrap(); assert_eq!(sock.is_curve_server().unwrap(), true); }); test_capability!(test_getset_curve_publickey, "curve", { let ctx = Context::new(); let sock = ctx.socket(zmq::REQ).unwrap(); let key = z85_decode("FX5b8g5ZnOk7$Q}^)Y&?.v3&MIe+]OU7DTKynkUL").unwrap(); sock.set_curve_publickey(&key).unwrap(); assert_eq!(sock.get_curve_publickey().unwrap(), key); }); test_capability!(test_getset_curve_secretkey, "curve", { let ctx = Context::new(); let sock = ctx.socket(zmq::REQ).unwrap(); let key = z85_decode("s9N%S3*NKSU$6pUnpBI&K5HBd[]G$Y3yrK?mhdbS").unwrap(); sock.set_curve_secretkey(&key).unwrap(); assert_eq!(sock.get_curve_secretkey().unwrap(), key); }); test_capability!(test_getset_curve_serverkey, "curve", { let ctx = Context::new(); let sock = ctx.socket(zmq::REQ).unwrap(); let key = z85_decode("FX5b8g5ZnOk7$Q}^)Y&?.v3&MIe+]OU7DTKynkUL").unwrap(); sock.set_curve_serverkey(&key).unwrap(); assert_eq!(sock.get_curve_serverkey().unwrap(), key); }); zmq-0.9.2/tests/error.rs010064400017500001750000000002251347400165600134200ustar0000000000000000use zmq::*; use zmq_sys::errno; #[test] fn from_raw_eintr() { let error = Error::from_raw(errno::EINTR); assert_eq!(error, Error::EINTR); } zmq-0.9.2/tests/gssapi.rs010064400017500001750000000021251354137150100135500ustar0000000000000000#[macro_use] mod common; use zmq::Context; test_capability!(test_getset_gssapi_server, "gssapi", { let ctx = Context::new(); let sock = ctx.socket(zmq::REQ).unwrap(); sock.set_gssapi_server(true).unwrap(); assert_eq!(sock.is_gssapi_server().unwrap(), true); }); test_capability!(test_getset_gssapi_principal, "gssapi", { let ctx = Context::new(); let sock = ctx.socket(zmq::REQ).unwrap(); sock.set_gssapi_principal("principal").unwrap(); assert_eq!(sock.get_gssapi_principal().unwrap().unwrap(), "principal"); }); test_capability!(test_getset_gssapi_service_principal, "gssapi", { let ctx = Context::new(); let sock = ctx.socket(zmq::REQ).unwrap(); sock.set_gssapi_service_principal("principal").unwrap(); assert_eq!( sock.get_gssapi_service_principal().unwrap().unwrap(), "principal" ); }); test_capability!(test_getset_gssapi_plaintext, "gssapi", { let ctx = Context::new(); let sock = ctx.socket(zmq::REQ).unwrap(); sock.set_gssapi_plaintext(true).unwrap(); assert_eq!(sock.is_gssapi_plaintext().unwrap(), true); }); zmq-0.9.2/tests/has.rs010064400017500001750000000003331347400165600130420ustar0000000000000000extern crate zmq; #[test] fn test_has() { // Until we can clean up the API `has` must return Some(_), not matter // wether the capability is actually supported or not. assert!(zmq::has("ipc").is_some()); } zmq-0.9.2/tests/message.rs010064400017500001750000000014761347400165600137240ustar0000000000000000#[macro_use] mod common; use quickcheck::{quickcheck, Arbitrary, Gen}; use zmq::Message; // A pair which contains two non-equal values #[derive(Clone, Debug)] struct NePair(T, T); impl Arbitrary for NePair where T: Eq + Arbitrary, { fn arbitrary(g: &mut G) -> Self { let v1 = T::arbitrary(g); let v2 = (0..).map(|_| T::arbitrary(g)).find(|v| *v != v1).unwrap(); NePair(v1, v2) } } quickcheck! { fn msg_cmp_eq(input: Vec) -> bool { Message::from(&input) == Message::from(&input) } fn msg_cmp_ne(input: NePair>) -> bool { Message::from(&input.0) != Message::from(&input.1) } fn msg_vec_roundtrip(input: Vec) -> bool { let original = Message::from(&input.clone()); Message::from(input) == original } } zmq-0.9.2/tests/monitor.rs010064400017500001750000000105001354137150100137450ustar0000000000000000#[macro_use] mod common; use std::str; use std::u16; fn version_ge_4_3() -> bool { let (major, minor, _) = zmq::version(); (major > 4) || (major == 4 && minor >= 3) } /// Read one event off the monitor socket; return the SocketEvent value. fn get_monitor_event(monitor: &mut zmq::Socket) -> zmq::Result { let msg = monitor.recv_msg(0)?; // TODO: could be simplified by using `TryInto` (since 1.34) let event = u16::from_ne_bytes([msg[0], msg[1]]); assert!( monitor.get_rcvmore()?, "Monitor socket should have two messages per event" ); // the address, we'll ignore it let _ = monitor.recv_msg(0)?; Ok(zmq::SocketEvent::from_raw(event)) } fn expect_event(mon: &mut zmq::Socket, expected: zmq::SocketEvent) { let event = get_monitor_event(mon).unwrap(); assert_eq!(expected, event); } /// Send a series of pings between the client and the server. /// The messages should round trip from the client to the server /// and back again. fn bounce(client: &mut zmq::Socket, server: &mut zmq::Socket) { let data = "12345678ABCDEFGH12345678abcdefgh"; // Send message from client to server client.send(data.as_bytes(), zmq::SNDMORE).unwrap(); client.send(data.as_bytes(), 0).unwrap(); // Receive message at server side let mut recv_data = server.recv_bytes(0).unwrap(); assert_eq!(str::from_utf8(&recv_data).unwrap(), data); assert!(server.get_rcvmore().unwrap()); recv_data = server.recv_bytes(0).unwrap(); assert_eq!(str::from_utf8(&recv_data).unwrap(), data); assert!(!server.get_rcvmore().unwrap()); // Send message from client to server server.send(&recv_data, zmq::SNDMORE).unwrap(); server.send(&recv_data, 0).unwrap(); // Receive the two parts at the client side recv_data = client.recv_bytes(0).unwrap(); assert_eq!(str::from_utf8(&recv_data).unwrap(), data); assert!(client.get_rcvmore().unwrap()); recv_data = client.recv_bytes(0).unwrap(); assert_eq!(str::from_utf8(&recv_data).unwrap(), data); assert!(!client.get_rcvmore().unwrap()); } /// Close the given socket with LINGER set to 0 fn close_zero_linger(socket: zmq::Socket) { socket.set_linger(0).unwrap(); drop(socket); } test!(test_monitor_events, { let ctx = zmq::Context::new(); let mut client = ctx.socket(zmq::DEALER).unwrap(); let mut server = ctx.socket(zmq::DEALER).unwrap(); let err = client .monitor("tcp://127.0.0.1:9999", 0) .expect_err("Socket monitoring only works over inproc://"); assert_eq!(zmq::Error::EPROTONOSUPPORT, err); assert!(client .monitor("inproc://monitor-client", zmq::SocketEvent::ALL as i32) .is_ok()); assert!(server .monitor("inproc://monitor-server", zmq::SocketEvent::ALL as i32) .is_ok()); let mut client_mon = ctx.socket(zmq::PAIR).unwrap(); let mut server_mon = ctx.socket(zmq::PAIR).unwrap(); // Connect these to the inproc endpoints so they'll get events client_mon.connect("inproc://monitor-client").unwrap(); server_mon.connect("inproc://monitor-server").unwrap(); // Now do a basic ping test server.bind("tcp://127.0.0.1:9998").unwrap(); client.connect("tcp://127.0.0.1:9998").unwrap(); bounce(&mut client, &mut server); // Close client and server close_zero_linger(client); close_zero_linger(server); // Now collect and check events from both sockets let mut event = get_monitor_event(&mut client_mon).unwrap(); if event == zmq::SocketEvent::CONNECT_DELAYED { event = get_monitor_event(&mut client_mon).unwrap(); } assert_eq!(zmq::SocketEvent::CONNECTED, event); if version_ge_4_3() { expect_event(&mut client_mon, zmq::SocketEvent::HANDSHAKE_SUCCEEDED); } expect_event(&mut client_mon, zmq::SocketEvent::MONITOR_STOPPED); // This is the flow of server events expect_event(&mut server_mon, zmq::SocketEvent::LISTENING); expect_event(&mut server_mon, zmq::SocketEvent::ACCEPTED); if version_ge_4_3() { expect_event(&mut server_mon, zmq::SocketEvent::HANDSHAKE_SUCCEEDED); } expect_event(&mut server_mon, zmq::SocketEvent::CLOSED); expect_event(&mut server_mon, zmq::SocketEvent::MONITOR_STOPPED); // Close down the sockets close_zero_linger(client_mon); close_zero_linger(server_mon); }); zmq-0.9.2/tests/poll.rs010064400017500001750000000000601314164234500132270ustar0000000000000000#[cfg(unix)] #[path = "poll/unix.rs"] mod unix; zmq-0.9.2/tests/poll/unix.rs010064400017500001750000000014711347400165600142240ustar0000000000000000// Test whether `zmq::poll()` works with `PollItem`s constructed from // arbitrary FDs. use nix::unistd; use std::os::unix::io::RawFd; use std::thread; #[test] fn test_pipe_poll() { let (pipe_read, pipe_write) = unistd::pipe().expect("pipe creation failed"); let writer_thread = thread::spawn(move || { pipe_writer(pipe_write); }); let pipe_item = zmq::PollItem::from_fd(pipe_read, zmq::POLLIN); let mut poll_items = [pipe_item]; assert_eq!(zmq::poll(&mut poll_items, 1000).unwrap(), 1); assert_eq!(poll_items[0].get_revents(), zmq::POLLIN); let mut buf = vec![0]; assert_eq!(unistd::read(pipe_read, &mut buf).unwrap(), 1); assert_eq!(buf, b"X"); writer_thread.join().unwrap(); } fn pipe_writer(fd: RawFd) { unistd::write(fd, b"X").expect("pipe write failed"); } zmq-0.9.2/tests/test.rs010064400017500001750000000406541354137150100132520ustar0000000000000000#[macro_use] mod common; use std::io; use std::net::TcpStream; use zmq::*; fn version_ge_4_2() -> bool { let (major, minor, _) = version(); (major > 4) || (major == 4 && minor >= 2) } fn create_socketpair() -> (Socket, Socket) { let ctx = Context::default(); let sender = ctx.socket(zmq::REQ).unwrap(); let receiver = ctx.socket(zmq::REP).unwrap(); // Don't block forever sender.set_sndtimeo(1000).unwrap(); sender.set_rcvtimeo(1000).unwrap(); if version_ge_4_2() { sender.set_connect_timeout(1000).unwrap(); } receiver.set_sndtimeo(1000).unwrap(); receiver.set_rcvtimeo(1000).unwrap(); receiver.bind("tcp://127.0.0.1:*").unwrap(); let ep = receiver.get_last_endpoint().unwrap().unwrap(); sender.connect(&ep).unwrap(); (sender, receiver) } test!(test_exchanging_messages, { let (sender, receiver) = create_socketpair(); sender.send("foo", 0).unwrap(); let msg = receiver.recv_msg(0).unwrap(); assert_eq!(&msg[..], b"foo"); assert_eq!(msg.as_str(), Some("foo")); assert_eq!(format!("{:?}", msg), "[102, 111, 111]"); receiver.send("bar", 0).unwrap(); let msg = sender.recv_msg(0).unwrap(); assert_eq!(&msg[..], b"bar"); }); test!(test_exchanging_bytes, { let (sender, receiver) = create_socketpair(); sender.send("bar", 0).unwrap(); assert_eq!(receiver.recv_bytes(0).unwrap(), b"bar"); receiver.send("a quite long string", 0).unwrap(); let mut buf = [0_u8; 10]; sender.recv_into(&mut buf, 0).unwrap(); // this should truncate the message assert_eq!(&buf[..], b"a quite lo"); }); test!(test_exchanging_strings, { let (sender, receiver) = create_socketpair(); sender.send("bäz", 0).unwrap(); assert_eq!(receiver.recv_string(0).unwrap().unwrap(), "bäz"); // non-UTF8 strings -> get an Err with bytes when receiving receiver.send(b"\xff\xb7".as_ref(), 0).unwrap(); let result = sender.recv_string(0).unwrap(); assert_eq!(result, Err(vec![0xff, 0xb7])); }); test!(test_exchanging_multipart, { let (sender, receiver) = create_socketpair(); // convenience API sender.send_multipart(&["foo", "bar"], 0).unwrap(); assert_eq!(receiver.recv_multipart(0).unwrap(), vec![b"foo", b"bar"]); // manually receiver.send("foo", SNDMORE).unwrap(); receiver.send("bar", 0).unwrap(); let msg1 = sender.recv_msg(0).unwrap(); assert!(msg1.get_more()); assert!(sender.get_rcvmore().unwrap()); assert_eq!(&msg1[..], b"foo"); let msg2 = sender.recv_msg(0).unwrap(); assert!(!msg2.get_more()); assert!(!sender.get_rcvmore().unwrap()); assert_eq!(&msg2[..], b"bar"); }); test!(test_polling, { let (sender, receiver) = create_socketpair(); // no message yet assert_eq!(receiver.poll(POLLIN, 1000).unwrap(), 0); // send message sender.send("Hello!", 0).unwrap(); let mut poll_items = vec![receiver.as_poll_item(POLLIN)]; assert_eq!(poll(&mut poll_items, 1000).unwrap(), 1); assert_eq!(poll_items[0].get_revents(), POLLIN); }); test!(test_raw_roundtrip, { let ctx = Context::new(); let mut sock = ctx.socket(SocketType::REQ).unwrap(); let ptr = sock.as_mut_ptr(); // doesn't consume the socket // NOTE: the socket will give up its context referecnce, but because we // still hold a reference in `ctx`, we won't get a deadlock. let raw = sock.into_raw(); // consumes the socket assert_eq!(ptr, raw); let _ = unsafe { Socket::from_raw(raw) }; }); test!(test_version, { let (major, _, _) = version(); assert!(major == 3 || major == 4); }); test!(test_zmq_error, { use std::error::Error as StdError; let ctx = Context::new(); let sock = ctx.socket(SocketType::REP).unwrap(); // cannot send from REP unless we received a message first let err = sock.send("...", 0).unwrap_err(); assert_eq!(err, Error::EFSM); // ZMQ error strings might not be guaranteed, so we'll not check // against specific messages, but still check that formatting does // not segfault, for example, and gives the same strings. let desc = err.description(); let display = format!("{}", err); let debug = format!("{:?}", err); assert_eq!(desc, display); assert_eq!(desc, debug); }); test!(test_into_io_error, { let e: io::Error = Error::ENOENT.into(); assert!(e.kind() == io::ErrorKind::NotFound); }); test!(test_get_socket_type, { let ctx = Context::new(); let mut socket_types = vec![ SocketType::PAIR, SocketType::PUB, SocketType::SUB, SocketType::REQ, SocketType::REP, SocketType::DEALER, SocketType::ROUTER, SocketType::PULL, SocketType::PUSH, SocketType::XPUB, SocketType::XSUB, SocketType::STREAM, ]; for sock_type in socket_types.drain(..) { let sock = ctx.socket(sock_type).unwrap(); assert_eq!(sock.get_socket_type().unwrap(), sock_type); } }); test!(test_create_stream_socket, { let ctx = Context::new(); let sock = ctx.socket(STREAM).unwrap(); assert!(sock.bind("tcp://127.0.0.1:*").is_ok()); let ep = sock.get_last_endpoint().unwrap().unwrap(); let tcp = "tcp://"; assert!(ep.starts_with(tcp)); assert!(TcpStream::connect(&ep[tcp.len()..]).is_ok()); }); test!(test_getset_maxmsgsize, { let ctx = Context::new(); let sock = ctx.socket(REQ).unwrap(); sock.set_maxmsgsize(512_000).unwrap(); assert_eq!(sock.get_maxmsgsize().unwrap(), 512_000); }); test!(test_getset_sndhwm, { let ctx = Context::new(); let sock = ctx.socket(REQ).unwrap(); sock.set_sndhwm(500).unwrap(); assert_eq!(sock.get_sndhwm().unwrap(), 500); }); test!(test_getset_rcvhwm, { let ctx = Context::new(); let sock = ctx.socket(REQ).unwrap(); sock.set_rcvhwm(500).unwrap(); assert_eq!(sock.get_rcvhwm().unwrap(), 500); }); test!(test_getset_affinity, { let ctx = Context::new(); let sock = ctx.socket(REQ).unwrap(); sock.set_affinity(1024).unwrap(); assert_eq!(sock.get_affinity().unwrap(), 1024); }); test!(test_getset_identity, { let ctx = Context::new(); let sock = ctx.socket(REQ).unwrap(); sock.set_identity(b"moo").unwrap(); assert_eq!(sock.get_identity().unwrap(), b"moo"); }); test!(test_subscription, { let ctx = Context::new(); let sock = ctx.socket(SUB).unwrap(); assert!(sock.set_subscribe(b"/channel").is_ok()); assert!(sock.set_unsubscribe(b"/channel").is_ok()); }); test!(test_set_req_relaxed, { let ctx = Context::new(); let sock = ctx.socket(REQ).unwrap(); assert!(sock.set_req_relaxed(true).is_ok()); assert!(sock.set_req_relaxed(false).is_ok()); }); test!(test_set_req_correlate, { let ctx = Context::new(); let sock = ctx.socket(REQ).unwrap(); assert!(sock.set_req_correlate(true).is_ok()); assert!(sock.set_req_correlate(false).is_ok()); }); test!(test_getset_rate, { let ctx = Context::new(); let sock = ctx.socket(REQ).unwrap(); sock.set_rate(200).unwrap(); assert_eq!(sock.get_rate().unwrap(), 200); }); test!(test_getset_recovery_ivl, { let ctx = Context::new(); let sock = ctx.socket(REQ).unwrap(); sock.set_recovery_ivl(100).unwrap(); assert_eq!(sock.get_recovery_ivl().unwrap(), 100); }); test!(test_getset_sndbuf, { let ctx = Context::new(); let sock = ctx.socket(REQ).unwrap(); sock.set_sndbuf(100).unwrap(); assert_eq!(sock.get_sndbuf().unwrap(), 100); }); test!(test_getset_rcvbuf, { let ctx = Context::new(); let sock = ctx.socket(REQ).unwrap(); sock.set_rcvbuf(100).unwrap(); assert_eq!(sock.get_rcvbuf().unwrap(), 100); }); test!(test_getset_tos, { let ctx = Context::new(); let sock = ctx.socket(REQ).unwrap(); sock.set_tos(100).unwrap(); assert_eq!(sock.get_tos().unwrap(), 100); }); test!(test_getset_linger, { let ctx = Context::new(); let sock = ctx.socket(REQ).unwrap(); sock.set_linger(100).unwrap(); assert_eq!(sock.get_linger().unwrap(), 100); }); test!(test_getset_reconnect_ivl, { let ctx = Context::new(); let sock = ctx.socket(REQ).unwrap(); sock.set_reconnect_ivl(100).unwrap(); assert_eq!(sock.get_reconnect_ivl().unwrap(), 100); }); test!(test_getset_reconnect_ivl_max, { let ctx = Context::new(); let sock = ctx.socket(REQ).unwrap(); sock.set_reconnect_ivl_max(100).unwrap(); assert_eq!(sock.get_reconnect_ivl_max().unwrap(), 100); }); test!(test_getset_backlog, { let ctx = Context::new(); let sock = ctx.socket(REQ).unwrap(); sock.set_backlog(50).unwrap(); assert_eq!(sock.get_backlog().unwrap(), 50); }); test!(test_getset_multicast_hops, { let ctx = Context::new(); let sock = ctx.socket(REQ).unwrap(); sock.set_multicast_hops(20).unwrap(); assert_eq!(sock.get_multicast_hops().unwrap(), 20); }); test!(test_getset_rcvtimeo, { let ctx = Context::new(); let sock = ctx.socket(REQ).unwrap(); sock.set_rcvtimeo(5000).unwrap(); assert_eq!(sock.get_rcvtimeo().unwrap(), 5000); }); test!(test_getset_sndtimeo, { let ctx = Context::new(); let sock = ctx.socket(REQ).unwrap(); sock.set_sndtimeo(5000).unwrap(); assert_eq!(sock.get_sndtimeo().unwrap(), 5000); }); test!(test_getset_ipv6, { let ctx = Context::new(); let sock = ctx.socket(REQ).unwrap(); sock.set_ipv6(true).unwrap(); assert!(sock.is_ipv6().unwrap()); sock.set_ipv6(false).unwrap(); assert!(!sock.is_ipv6().unwrap()); }); test!(test_getset_socks_proxy, { let ctx = Context::new(); let sock = ctx.socket(REQ).unwrap(); sock.set_socks_proxy(Some("my_socks_server.com:10080")) .unwrap(); assert_eq!( sock.get_socks_proxy().unwrap().unwrap(), "my_socks_server.com:10080" ); sock.set_socks_proxy(None).unwrap(); assert_eq!(sock.get_socks_proxy().unwrap().unwrap(), ""); }); test!(test_getset_keepalive, { let ctx = Context::new(); let sock = ctx.socket(REQ).unwrap(); sock.set_tcp_keepalive(-1).unwrap(); assert_eq!(sock.get_tcp_keepalive().unwrap(), -1); sock.set_tcp_keepalive(0).unwrap(); assert_eq!(sock.get_tcp_keepalive().unwrap(), 0); sock.set_tcp_keepalive(1).unwrap(); assert_eq!(sock.get_tcp_keepalive().unwrap(), 1); }); test!(test_getset_keepalive_cnt, { let ctx = Context::new(); let sock = ctx.socket(REQ).unwrap(); sock.set_tcp_keepalive_cnt(-1).unwrap(); assert_eq!(sock.get_tcp_keepalive_cnt().unwrap(), -1); sock.set_tcp_keepalive_cnt(500).unwrap(); assert_eq!(sock.get_tcp_keepalive_cnt().unwrap(), 500); }); test!(test_getset_keepalive_idle, { let ctx = Context::new(); let sock = ctx.socket(REQ).unwrap(); sock.set_tcp_keepalive_idle(-1).unwrap(); assert_eq!(sock.get_tcp_keepalive_idle().unwrap(), -1); sock.set_tcp_keepalive_idle(500).unwrap(); assert_eq!(sock.get_tcp_keepalive_idle().unwrap(), 500); }); test!(test_getset_tcp_keepalive_intvl, { let ctx = Context::new(); let sock = ctx.socket(REQ).unwrap(); sock.set_tcp_keepalive_intvl(-1).unwrap(); assert_eq!(sock.get_tcp_keepalive_intvl().unwrap(), -1); sock.set_tcp_keepalive_intvl(500).unwrap(); assert_eq!(sock.get_tcp_keepalive_intvl().unwrap(), 500); }); test!(test_getset_immediate, { let ctx = Context::new(); let sock = ctx.socket(REQ).unwrap(); sock.set_immediate(true).unwrap(); assert!(sock.is_immediate().unwrap()); sock.set_immediate(false).unwrap(); assert!(!sock.is_immediate().unwrap()); }); test!(test_getset_plain_server, { let ctx = Context::new(); let sock = ctx.socket(REQ).unwrap(); sock.set_plain_server(true).unwrap(); assert!(sock.is_plain_server().unwrap()); sock.set_plain_server(false).unwrap(); assert!(!sock.is_plain_server().unwrap()); }); test!(test_getset_plain_username, { let ctx = Context::new(); let sock = ctx.socket(REQ).unwrap(); sock.set_plain_username(Some("billybob")).unwrap(); assert_eq!(sock.get_plain_username().unwrap().unwrap(), "billybob"); assert_eq!(sock.get_mechanism().unwrap(), Mechanism::ZMQ_PLAIN); sock.set_plain_username(None).unwrap(); assert!(sock.get_mechanism().unwrap() == Mechanism::ZMQ_NULL); }); test!(test_getset_plain_password, { let ctx = Context::new(); let sock = ctx.socket(REQ).unwrap(); sock.set_plain_password(Some("m00c0w")).unwrap(); assert_eq!(sock.get_plain_password().unwrap().unwrap(), "m00c0w"); assert_eq!(sock.get_mechanism().unwrap(), Mechanism::ZMQ_PLAIN); sock.set_plain_password(None).unwrap(); assert!(sock.get_mechanism().unwrap() == Mechanism::ZMQ_NULL); }); test!(test_zmq_set_xpub_verbose, { let ctx = Context::new(); let xpub = ctx.socket(XPUB).unwrap(); let sub = ctx.socket(SUB).unwrap(); xpub.bind("inproc://set_xpub_verbose").unwrap(); xpub.set_xpub_verbose(true).unwrap(); sub.connect("inproc://set_xpub_verbose").unwrap(); for _ in 0..2 { sub.set_subscribe(b"topic").unwrap(); let event = xpub.recv_msg(0).unwrap(); assert_eq!(event[0], 1); assert_eq!(&event[1..], b"topic"); } }); test!(test_zmq_xpub_welcome_msg, { let ctx = Context::new(); let xpub = ctx.socket(XPUB).unwrap(); xpub.bind("inproc://xpub_welcome_msg").unwrap(); xpub.set_xpub_welcome_msg(Some("welcome")).unwrap(); let sub = ctx.socket(SUB).unwrap(); sub.set_subscribe(b"").unwrap(); sub.connect("inproc://xpub_welcome_msg").unwrap(); let from_pub = xpub.recv_bytes(0).unwrap(); assert_eq!(from_pub, b"\x01"); let from_xsub = sub.recv_bytes(0).unwrap(); assert_eq!(from_xsub, b"welcome"); }); test!(test_getset_zap_domain, { let ctx = Context::new(); let sock = ctx.socket(REQ).unwrap(); sock.set_zap_domain("test_domain").unwrap(); assert_eq!(sock.get_zap_domain().unwrap().unwrap(), "test_domain"); }); test!(test_get_fd, { let ctx = Context::new(); let sock_a = ctx.socket(REQ).unwrap(); let sock_b = ctx.socket(REQ).unwrap(); let mut fds_a: Vec<_> = (0..10).map(|_| sock_a.get_fd()).collect(); fds_a.dedup(); assert_eq!(fds_a.len(), 1); let mut fds_b: Vec<_> = (0..10).map(|_| sock_b.get_fd()).collect(); fds_b.dedup(); assert_eq!(fds_b.len(), 1); assert_ne!(fds_a[0], fds_b[0]); }); test!(test_ctx_nohang, { // Test that holding on to a socket keeps the context it was // created from from being destroyed. Destroying the context while // a socket is still open would block, thus hanging this test in // the failing case. let sock = { let ctx = Context::new(); ctx.socket(REQ).unwrap() }; assert_eq!(sock.get_socket_type(), Ok(REQ)); }); test!(test_getset_conflate, { let ctx = Context::new(); let sock = ctx.socket(REQ).unwrap(); sock.set_conflate(true).unwrap(); assert_eq!(sock.is_conflate().unwrap(), true); }); test!(test_disconnect, { // Make a connected socket pair let (sender, receiver) = create_socketpair(); // Now disconnect them let ep = receiver.get_last_endpoint().unwrap().unwrap(); sender.disconnect(&ep).unwrap(); // And check that the message can no longer be sent assert_eq!(Error::EAGAIN, sender.send("foo", DONTWAIT).unwrap_err()); }); test!(test_disconnect_err, { let (sender, _) = create_socketpair(); // Check that disconnect propagates errors. The endpoint is not connected. assert_eq!( Error::ENOENT, sender.disconnect("tcp://192.0.2.1:2233").unwrap_err() ); }); test!(test_getset_handshake_ivl, { let ctx = Context::new(); let sock = ctx.socket(REQ).unwrap(); sock.set_handshake_ivl(50000).unwrap(); assert_eq!(sock.get_handshake_ivl().unwrap(), 50000); }); test!(test_getset_connect_timeout, { if version_ge_4_2() { let ctx = Context::new(); let sock = ctx.socket(REQ).unwrap(); sock.set_connect_timeout(5000).unwrap(); assert_eq!(sock.get_connect_timeout().unwrap(), 5000); } }); #[cfg(feature = "compiletest_rs")] mod compile { extern crate compiletest_rs as compiletest; use std::path::PathBuf; fn run_mode(mode: &'static str) { let mut config = compiletest::Config::default(); let cfg_mode = mode.parse().expect("Invalid mode"); config.mode = cfg_mode; config.src_base = PathBuf::from(format!("tests/{}", mode)); config.target_rustcflags = Some("-L target/debug -L target/debug/deps".to_string()); compiletest::run_tests(&config); } #[test] fn expected_failures() { run_mode("compile-fail"); } } zmq-0.9.2/tests/unix/connection.rs010064400017500001750000000057471354141107200154170ustar0000000000000000// Test integration of zmq with a simple external event loop // // This excercises the `Socket::get_fd()` method in combination with // `Socket::get_events()` to integrate with Unix `poll(2)` to check // the basis for integration with external event loops works. use log::debug; use nix::poll::{self, PollFlags}; use super::with_connection; test!(test_external_poll_inproc, { with_connection( "inproc://test-poll", zmq::REQ, poll_client, zmq::REP, poll_worker, ); }); test!(test_external_poll_ipc, { with_connection( "ipc:///tmp/zmq-tokio-test", zmq::REQ, poll_client, zmq::REP, poll_worker, ); }); test!(test_external_poll_tcp, { with_connection( "tcp://127.0.0.1:*", zmq::REQ, poll_client, zmq::REP, poll_worker, ); }); fn poll_client(_ctx: &zmq::Context, socket: &zmq::Socket) { // TODO: we should use `poll::poll()` here as well. for i in 0..10 { let payload = format!("message {}", i); socket.send(&payload, 0).unwrap(); let reply = socket.recv_msg(0).unwrap(); assert_eq!(payload.as_bytes(), &reply[..]); } socket.send("", 0).unwrap(); let last = socket.recv_msg(0).unwrap(); assert_eq!(b"", &last[..]); } /// Keeps track of the polling state for the event signalling FD of a /// single socket. struct PollState<'a> { socket: &'a zmq::Socket, fds: [poll::PollFd; 1], } impl<'a> PollState<'a> { fn new(socket: &'a zmq::Socket) -> Self { let fd = socket.get_fd().unwrap(); PollState { socket, fds: [poll::PollFd::new(fd, PollFlags::POLLIN)], } } /// Wait for one of `events` to happen. fn wait(&mut self, events: zmq::PollEvents) { while !(self.events().intersects(events)) { debug!("polling"); let fds = &mut self.fds; poll::poll(fds, -1).unwrap(); debug!("poll done, events: {:?}", fds[0].revents()); match fds[0].revents() { Some(events) => { if !events.contains(PollFlags::POLLIN) { continue; } } _ => continue, } } } fn events(&self) -> zmq::PollEvents { self.socket.get_events().unwrap() as zmq::PollEvents } } fn poll_worker(_ctx: &zmq::Context, socket: &zmq::Socket) { let mut reply = None; let mut state = PollState::new(&socket); loop { match reply.take() { None => { state.wait(zmq::POLLIN); let msg = socket.recv_msg(zmq::DONTWAIT).unwrap(); reply = Some(msg); } Some(msg) => { state.wait(zmq::POLLOUT); let done = msg.len() == 0; socket.send(msg, zmq::DONTWAIT).unwrap(); if done { break; } } } } } zmq-0.9.2/tests/z85.rs010064400017500001750000000026271347400165600127250ustar0000000000000000use quickcheck::{quickcheck, Arbitrary, Gen}; use rand::Rng; use zmq::{z85_decode, z85_encode, DecodeError, EncodeError}; use std::iter; #[test] fn test_z85() { let test_str = "/AB8cGJ*-$lEbr2=TW$Q?i7:) (), _ => panic!("expected bad length error"), } let bad_str = "/AB\x008"; match z85_decode(bad_str) { Err(DecodeError::NulError(_)) => (), _ => panic!("expected nul error"), } let bad_bytes = b"\x01\x01\x01\x01\x01"; match z85_encode(bad_bytes) { Err(EncodeError::BadLength) => (), _ => panic!("expected bad length error"), } } // Valid input for z85 encoding (i.e. a slice of bytes with its length // being a multiple of 4) #[derive(Clone, Debug)] struct Input(Vec); impl Arbitrary for Input { fn arbitrary(g: &mut G) -> Self { let len = g.gen_range(0, 256) * 4; Input(iter::repeat(()).map(|_| g.gen()).take(len).collect()) } } quickcheck! { fn z85_roundtrip(input: Input) -> bool { let encoded = z85_encode(&input.0).unwrap(); let decoded = z85_decode(&encoded).unwrap(); input.0 == decoded } } zmq-0.9.2/.cargo_vcs_info.json0000644000000001120000000000000117040ustar00{ "git": { "sha1": "e2016220a52b25d6cf7212477549b003c1e045dc" } } zmq-0.9.2/Cargo.lock0000644000001000760000000000000076710ustar00# This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] name = "aho-corasick" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "atom" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "atty" version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "backtrace" version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "backtrace-sys" version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "bitflags" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "c2-chacha" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cc" version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cfg-if" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cmake" version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "compiletest_rs" version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustfix 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "tester 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "diff" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "env_logger" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "error-chain" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "failure" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "backtrace 0.3.37 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "failure_derive" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "filetime" version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "getopts" version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "getrandom" version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "humantime" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "itoa" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "kernel32-sys" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" version = "0.2.62" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "log" version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "memchr" version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "metadeps" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "miow" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "socket2 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "nix" version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "pkg-config" version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "ppv-lite86" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro2" version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "proc-macro2" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "pulse" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "atom 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "quick-error" version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "quickcheck" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "quote" version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "quote" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_chacha" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_core" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_hc" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "redox_syscall" version = "0.1.56" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "regex" version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "regex-syntax" version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "remove_dir_all" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rustc-demangle" version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rustfix" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ryu" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive" version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_json" version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "socket2" version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "syn" version = "0.15.44" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "syn" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "synstructure" version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tempfile" version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "term" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "termcolor" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tester" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "thread_local" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "time" version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "timebomb" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "pulse 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "toml" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "unicode-width" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "unicode-xid" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "unicode-xid" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "void" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "wasi" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winapi" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winapi" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "winapi-build" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winapi-util" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "wincolor" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "zeromq-src" version = "0.1.8+4.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cmake 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "zmq" version = "0.9.2" dependencies = [ "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "compiletest_rs 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "quickcheck 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "timebomb 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "zmq-sys 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "zmq-sys" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "metadeps 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "zeromq-src 0.1.8+4.3.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [metadata] "checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" "checksum atom 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3c86699c3f02778ec07158376991c8f783dd1f2f95c579ffaf0738dc984b2fe2" "checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" "checksum backtrace 0.3.37 (registry+https://github.com/rust-lang/crates.io-index)" = "5180c5a20655b14a819b652fd2378fa5f1697b6c9ddad3e695c2f9cedf6df4e2" "checksum backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "82a830b4ef2d1124a711c71d263c5abdc710ef8e907bd508c88be475cebc422b" "checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" "checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" "checksum cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)" = "4fc9a35e1f4290eb9e5fc54ba6cf40671ed2a2514c3eeb2b2a908dda2ea5a1be" "checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" "checksum cmake 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "81fb25b677f8bf1eb325017cb6bb8452f87969db0fedb4f757b297bee78a7c62" "checksum compiletest_rs 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "f40ecc9332b68270998995c00f8051ee856121764a0d3230e64c9efd059d27b6" "checksum diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3c2b69f912779fbb121ceb775d74d51e915af17aaebc38d28a592843a2dd0a3a" "checksum env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" "checksum error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9435d864e017c3c6afeac1654189b06cdb491cf2ff73dbf0d73b0f292f42ff8" "checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" "checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" "checksum filetime 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6bd7380b54ced79dda72ecc35cc4fbbd1da6bba54afaa37e96fd1c2a308cd469" "checksum getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" "checksum getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "473a1265acc8ff1e808cd0a1af8cee3c2ee5200916058a2ca113c29f2d903571" "checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" "checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" "checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" "checksum metadeps 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "73b122901b3a675fac8cecf68dcb2f0d3036193bc861d1ac0e1c337f7d5254c2" "checksum miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "396aa0f2003d7df8395cb93e09871561ccc3e785f0acb369170e8cc74ddf9226" "checksum nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3b2e0b4f3320ed72aaedb9a5ac838690a8047c7b275da22711fddff4f8a14229" "checksum pkg-config 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "72d5370d90f49f70bd033c3d75e87fc529fbfff9d6f7cccef07d6170079d91ea" "checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" "checksum proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afdc77cc74ec70ed262262942ebb7dac3d479e9e5cfa2da1841c0806f6cdabcc" "checksum pulse 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "655612b6c8d96a8a02f331fe296cb4f925b68e87c1d195544675abca2d9b9af0" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" "checksum quickcheck 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d5ca504a2fdaa08d3517f442fbbba91ac24d1ec4c51ea68688a038765e3b2662" "checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" "checksum rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae1b169243eaf61759b8475a998f0a385e42042370f3a7dbaf35246eacc8412" "checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" "checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd" "checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716" "checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" "checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" "checksum rustfix 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7150ac777a2931a53489f5a41eb0937b84e3092a20cd0e73ad436b65b507f607" "checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" "checksum serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "9796c9b7ba2ffe7a9ce53c2287dfc48080f4b2b362fcc245a259b3a7201119dd" "checksum serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "4b133a43a1ecd55d4086bd5b4dc6c1751c68b1bfbeba7a5040442022c7e7c02e" "checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704" "checksum socket2 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "e8b74de517221a2cb01a53349cf54182acdc31a074727d3079068448c0676d85" "checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" "checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" "checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" "checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1" "checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e" "checksum tester 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5e812cb26c597f86a49b26dbb58b878bd2a2b4b93fc069dc39499228fe556ff6" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum timebomb 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f0886f4b637067027d8c9a038a9249d95648689d1a91009d9abb895625f883a" "checksum toml 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "736b60249cb25337bc196faa43ee12c705e426f3d55c214d73a4e7be06f92cb4" "checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" "checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96f5016b18804d24db43cebf3c77269e7569b8954a8464501c216cc5e070eaa9" "checksum zeromq-src 0.1.8+4.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a1e9589782fca63e346d91e9c708dd4feaa69fbe3099b885b04a2fed7adc805" "checksum zmq-sys 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d33a2c51dde24d5b451a2ed4b488266df221a5eaee2ee519933dc46b9a9b3648"