├── .github ├── dependabot.yml └── workflows │ └── ci.yaml ├── .gitignore ├── CONTRIBUTING.md ├── Cargo.toml ├── HACKING.md ├── LICENSE-APACHE ├── LICENSE-MIT ├── NEWS.md ├── README.md ├── build.rs ├── examples ├── msgsend │ └── main.rs ├── stream │ └── logserver.rs └── zguide │ ├── README.md │ ├── asyncsrv │ └── main.rs │ ├── fileio3 │ └── main.rs │ ├── helloworld_client │ └── main.rs │ ├── helloworld_server │ └── main.rs │ ├── lbbroker │ └── main.rs │ ├── lvcache │ └── main.rs │ ├── msgqueue │ └── main.rs │ ├── mspoller │ └── main.rs │ ├── msreader │ └── main.rs │ ├── mtrelay │ └── main.rs │ ├── mtserver │ └── main.rs │ ├── pathopub │ └── main.rs │ ├── pathosub │ └── main.rs │ ├── psenvpub │ └── main.rs │ ├── psenvsub │ └── main.rs │ ├── rrbroker │ └── main.rs │ ├── rrclient │ └── main.rs │ ├── rrworker │ └── main.rs │ ├── rtdealer │ └── main.rs │ ├── rtreq │ └── main.rs │ ├── syncpub │ └── main.rs │ ├── syncsub │ └── main.rs │ ├── tasksink │ └── main.rs │ ├── tasksink2 │ └── main.rs │ ├── taskvent │ └── main.rs │ ├── taskwork │ └── main.rs │ ├── taskwork2 │ └── main.rs │ ├── version │ └── main.rs │ ├── weather_client │ └── main.rs │ ├── weather_server │ └── main.rs │ └── wuproxy │ └── main.rs ├── msrv-test ├── Cargo.toml └── src │ └── main.rs ├── src ├── lib.rs ├── message.rs └── sockopt.rs ├── tests ├── common │ └── mod.rs ├── compile-fail │ ├── no-leaking-poll-items.rs │ ├── no-leaking-poll-items.stderr │ ├── socket-thread-unsafe.rs │ └── socket-thread-unsafe.stderr ├── compile-tests.rs ├── connection.rs ├── context.rs ├── curve.rs ├── error.rs ├── gssapi.rs ├── has.rs ├── message.rs ├── message_from_boxed_slice.rs ├── monitor.rs ├── poll.rs ├── poll │ └── unix.rs ├── test.rs ├── unix │ └── connection.rs └── z85.rs └── zmq-sys ├── .gitignore ├── Cargo.toml ├── build └── main.rs └── src ├── errno.rs ├── ffi.rs ├── lib.rs ├── unix.rs └── windows.rs /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: cargo 4 | directory: "/" 5 | schedule: 6 | interval: weekly 7 | open-pull-requests-limit: 10 8 | allow: 9 | - dependency-type: all 10 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | on: [push, pull_request] 2 | 3 | name: Continuous integration 4 | 5 | jobs: 6 | build: 7 | name: Build 8 | strategy: 9 | matrix: 10 | os: [ubuntu-latest, windows-latest, macos-latest] 11 | runs-on: ${{ matrix.os }} 12 | steps: 13 | - uses: actions/checkout@v2 14 | - name: Cargo build 15 | run: cargo build --workspace --all-targets 16 | test: 17 | name: Test 18 | strategy: 19 | matrix: 20 | os: [ubuntu-latest, windows-latest, macos-latest] 21 | runs-on: ${{ matrix.os }} 22 | steps: 23 | - uses: actions/checkout@v2 24 | - name: Cargo test 25 | run: cargo test --workspace --all-targets 26 | lint: 27 | name: Lint 28 | strategy: 29 | matrix: 30 | os: [ubuntu-latest, windows-latest, macos-latest] 31 | runs-on: ${{ matrix.os }} 32 | steps: 33 | - uses: actions/checkout@v2 34 | - name: Cargo clippy 35 | run: cargo clippy --workspace --all-targets -- -D warnings 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *~ 3 | \#*\# 4 | *.dylib 5 | *.dSYM 6 | *.o 7 | *.a 8 | /target/ 9 | Cargo.lock 10 | /msrv-test/target/ 11 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to rust-zmq 2 | 3 | Thank you for your interest in contributing to rust-zmq! 4 | 5 | ## Bug reports 6 | 7 | Please describe what you did, what you expected, and what happened 8 | instead. Please use https://gist.github.com/ if your examples run 9 | long. 10 | 11 | ## Feature requests 12 | 13 | If you find a missing feature, such as functionality provided by the 14 | underlying `libzmq` library, but not available via the Rust API 15 | provided by the `zmq` crate, or a suggestion to improve the existing 16 | API to make it more ergonomic, please file an issue before starting to 17 | work on a pull request, especially when the feature requires API 18 | changes or adds to the existing API in non-trivial ways. 19 | 20 | This gives the maintainers a chance to provide guidance on how the 21 | feature might be best implemented, or point out additional constraints 22 | that need to be considered when tackling the feature. 23 | 24 | ## Pull requests 25 | 26 | rust-zmq uses the "fork and pull" model [described 27 | here](https://help.github.com/en/articles/about-collaborative-development-models). It 28 | is highly recommended that you create a dedicated branch in your 29 | repository for each pull request you submit, instead of submitting 30 | using your `master` branch. This will make it easier on you when you 31 | end up having multiple pull requests outstanding, and will let you 32 | avoid rewriting history on your fork's `master` branch (see below). 33 | 34 | ### Version history 35 | 36 | The rust-zmq project aims to keep the version history useful and 37 | reasonably simple. Thus, when preparing and updating your pull 38 | request, you should make liberal use of git's history rewriting 39 | capabilities, such as amending and squashing commits. Try to observe 40 | the following guidelines: 41 | 42 | - Unless you are working on a complex feature that can be implemented 43 | in multiple, independent changes, the pull request should contain a 44 | single commit. Do not submit "fixup" commits, instead amend your 45 | commit (`git commit --amend`) or use interactive rebase (`git rebase 46 | -i`) to prepare commits that can be considered on their own, instead 47 | of requiring a reviewer to take later fixup commits into account. 48 | 49 | - Each commit message should give a rough description of what was 50 | changed, and why. See ["How to Write a Commit Message"] for details 51 | on what a good commit message looks like, and why it matters. 52 | 53 | - Do not merge the target branch into your pull request branch if you 54 | need to update your pull request with changes made in the target 55 | branch. Instead, use `git rebase`. 56 | 57 | ["How to Write a Commit Message"]: https://chris.beams.io/posts/git-commit/ 58 | 59 | ### Tests 60 | 61 | If you add a feature, or fix an issue, think about how it could be 62 | tested, and add to the testsuite, if possible. This will make it 63 | easier for reviewers to see that your code actually does what it is 64 | supposed to do, and will prevent future regressions. 65 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "zmq" 3 | version = "0.10.0" 4 | authors = [ 5 | "a.rottmann@gmx.at", 6 | "erick.tryzelaar@gmail.com", 7 | "opensource@traversersearch.nl", 8 | ] 9 | license = "MIT/Apache-2.0" 10 | description = "High-level bindings to the zeromq library" 11 | keywords = ["bindings", "protocol"] 12 | categories = ["api-bindings", "network-programming"] 13 | repository = "https://github.com/erickt/rust-zmq" 14 | readme = "README.md" 15 | build = "build.rs" 16 | edition = "2018" 17 | 18 | [badges] 19 | maintenance = { status = "actively-maintained" } 20 | 21 | [features] 22 | default = ["zmq_has"] 23 | # zmq_has was added in zeromq 4.1. As we now require 4.1 or newer, 24 | # this feature is a no-op and only present for backward-compatibility; 25 | # it will be removed in the next API-breaking release. 26 | zmq_has = [] 27 | 28 | [dependencies] 29 | bitflags = "1.0" 30 | libc = "0.2.15" 31 | zmq-sys = { version = "0.12.0", path = "zmq-sys" } 32 | 33 | [dev-dependencies] 34 | trybuild = { version = "1" } 35 | env_logger = { version = "0.9", default-features = false } 36 | log = "0.4.3" 37 | nix = "0.23" 38 | quickcheck = "1" 39 | rand = "0.8" 40 | tempfile = "3" 41 | timebomb = "0.1.2" 42 | 43 | [[example]] 44 | name = "helloworld_client" 45 | path = "examples/zguide/helloworld_client/main.rs" 46 | 47 | [[example]] 48 | name = "helloworld_server" 49 | path = "examples/zguide/helloworld_server/main.rs" 50 | 51 | [[example]] 52 | name = "msreader" 53 | path = "examples/zguide/msreader/main.rs" 54 | 55 | [[example]] 56 | name = "mspoller" 57 | path = "examples/zguide/mspoller/main.rs" 58 | 59 | [[example]] 60 | name = "pathopub" 61 | path = "examples/zguide/pathopub/main.rs" 62 | 63 | [[example]] 64 | name = "pathosub" 65 | path = "examples/zguide/pathosub/main.rs" 66 | 67 | [[example]] 68 | name = "lvcache" 69 | path = "examples/zguide/lvcache/main.rs" 70 | 71 | [[example]] 72 | name = "msgsend" 73 | path = "examples/msgsend/main.rs" 74 | 75 | [[example]] 76 | name = "stream-logserver" 77 | path = "examples/stream/logserver.rs" 78 | 79 | [[example]] 80 | name = "tasksink" 81 | path = "examples/zguide/tasksink/main.rs" 82 | 83 | [[example]] 84 | name = "taskvent" 85 | path = "examples/zguide/taskvent/main.rs" 86 | 87 | [[example]] 88 | name = "taskwork" 89 | path = "examples/zguide/taskwork/main.rs" 90 | 91 | [[example]] 92 | name = "version" 93 | path = "examples/zguide/version/main.rs" 94 | 95 | [[example]] 96 | name = "weather_client" 97 | path = "examples/zguide/weather_client/main.rs" 98 | 99 | [[example]] 100 | name = "weather_server" 101 | path = "examples/zguide/weather_server/main.rs" 102 | 103 | [[example]] 104 | name = "rtdealer" 105 | path = "examples/zguide/rtdealer/main.rs" 106 | 107 | [[example]] 108 | name = "fileio3" 109 | path = "examples/zguide/fileio3/main.rs" 110 | 111 | [[example]] 112 | name = "rrclient" 113 | path = "examples/zguide/rrclient/main.rs" 114 | 115 | [[example]] 116 | name = "rrworker" 117 | path = "examples/zguide/rrworker/main.rs" 118 | 119 | [[example]] 120 | name = "rrbroker" 121 | path = "examples/zguide/rrbroker/main.rs" 122 | 123 | [[example]] 124 | name = "msgqueue" 125 | path = "examples/zguide/msgqueue/main.rs" 126 | 127 | [[example]] 128 | name = "wuproxy" 129 | path = "examples/zguide/wuproxy/main.rs" 130 | 131 | [[example]] 132 | name = "tasksink2" 133 | path = "examples/zguide/tasksink2/main.rs" 134 | 135 | [[example]] 136 | name = "taskwork2" 137 | path = "examples/zguide/taskwork2/main.rs" 138 | 139 | [[example]] 140 | name = "mtserver" 141 | path = "examples/zguide/mtserver/main.rs" 142 | 143 | [[example]] 144 | name = "mtrelay" 145 | path = "examples/zguide/mtrelay/main.rs" 146 | 147 | [[example]] 148 | name = "syncpub" 149 | path = "examples/zguide/syncpub/main.rs" 150 | 151 | [[example]] 152 | name = "syncsub" 153 | path = "examples/zguide/syncsub/main.rs" 154 | 155 | [[example]] 156 | name = "psenvpub" 157 | path = "examples/zguide/psenvpub/main.rs" 158 | 159 | [[example]] 160 | name="psenvsub" 161 | path="examples/zguide/psenvsub/main.rs" 162 | 163 | [[example]] 164 | name="rtreq" 165 | path="examples/zguide/rtreq/main.rs" 166 | 167 | [[example]] 168 | name="lbbroker" 169 | path="examples/zguide/lbbroker/main.rs" 170 | 171 | [[example]] 172 | name="asyncsrv" 173 | path="examples/zguide/asyncsrv/main.rs" 174 | -------------------------------------------------------------------------------- /HACKING.md: -------------------------------------------------------------------------------- 1 | # Hacking on rust-zmq 2 | 3 | This file is intended to collect useful knowledge when hacking on the 4 | rust-zmq crate. 5 | 6 | If you intend to provide a contribution, please check the 7 | [contribution guidelines]. 8 | 9 | [contribution guidelines]: ./CONTRIBUTING.md 10 | 11 | ## Regenerating the C bindings 12 | 13 | The C low-level, unsafe C binding is provided by the `zmq-sys` crate, 14 | also hosted in this repository. The bindings are only partially 15 | auto-generated, to allow getting some platform-specific details 16 | right. 17 | 18 | The autogenerated part produced by the `bindgen` crate is stored in 19 | the [`ffi.rs`] file inside the `zmq-sys` crate, and is created using 20 | the `zmq.h` header file; using the following command: 21 | 22 | ```sh 23 | bindgen \ 24 | --with-derive-default \ 25 | --whitelist-function "^zmq_.*" \ 26 | --whitelist-type "^zmq_.*" \ 27 | --whitelist-var "^ZMQ_.*" ~/src/zeromq-4.1.6/include/zmq.h 28 | > zmq-sys/src/ffi.rs 29 | ``` 30 | 31 | [`ffi.rs`]: ./zmq-sys/src/ffi.rs 32 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011-2014 Erick Tryzelaar 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | # 0.9.2 2 | 3 | ## New and improved functionality 4 | 5 | - Support for the `ZMQ_REQ_RELAXED` and `ZMQ_REQ_CORRELATE` socket 6 | options, implemented in #285. 7 | 8 | ## Compatibility 9 | 10 | - `SocketType`, `Mechanism`, and `Error` can not longer be cast to an 11 | integer type and expected to get the corresponding `libzmq` C-level 12 | value. The ability to cast to integers and get the C enum values was 13 | never a documented part of the API, so this is not considered a 14 | breaking change. 15 | 16 | Unfortunately, the `SocketEvent` can not be future-proofed in this 17 | way; the monitoring API needs breaking changes to gain a reasonable 18 | level of type-safety. 19 | 20 | ## Fixes 21 | 22 | - A potential panic in `Message::gets` involving messages with 23 | non-UTF8 property values has been fixed; see #288. 24 | 25 | # 0.9.1 26 | 27 | ## New and improved functionality 28 | 29 | - Added `vendored` feature which build `libzmq` from source via 30 | [`zeromq-src`], see the [`README`] for details; discussed in #257 31 | and implemented in #267. 32 | 33 | - The installed `libzmq` C library is no longer feature-probed at 34 | build time, and all the wrapped API is exposed. Using features 35 | unsupported by the installed `libzmq` library will lead to run-time 36 | errors, like they would in C. 37 | 38 | This should enable cross-compiling without jumping through 39 | additional hoops. 40 | 41 | Implemented in #276. 42 | 43 | - The `Message` data type now implements `From`. 44 | 45 | - The `Message` data type has gained a new constructor `with_size`, 46 | which replaces the now-deprecated, confusingly-named `with_capacity` 47 | constructor. Reported in #215 and fixed in #272. 48 | 49 | - New functions `proxy_steerable` and `proxy_steerable_with_capture`, 50 | which wrap the `zmq_proxy_steerable` C function. Implemented in 51 | #242. 52 | 53 | [`README`]: ./README.md 54 | [`zeromq-src`]: https://github.com/jean-airoldie/zeromq-src-rs 55 | 56 | ## Deprecations 57 | 58 | - The `Message` constructors `with_capacity_unallocated`, 59 | `with_capacity` and `from_slice` methods are deprecated, the first 60 | one without a planned alternative (#272). 61 | 62 | ## Platform requirements 63 | 64 | - The codebase has been switched to the Rust 2018 edition and requires 65 | `rustc` 1.32.0 or newer. Compatibility back to 1.32.0 is now ensured 66 | via CI. 67 | 68 | # 0.9.0 69 | 70 | ## Incompatible API changes 71 | 72 | - Requires ZeroMQ 4.1+. 73 | 74 | - The deprecated `Constants` enum has been removed from the API. 75 | 76 | - Message allocation, e.g. `Message::new()` directly returns `Message` 77 | instead of `Result` and will panic on allocation failure, 78 | as is customary in Rust. Reported in #118 and fixed by #130. 79 | 80 | ## New and improved functionality 81 | 82 | - `Message` now implements `From` for various types that have an 83 | obvious byte-level representation. This is possible due to the 84 | message allocation API change (see above). 85 | 86 | - `Message::send()` now works on `Into` types, obsoleting 87 | `send_msg()` and `send_str()`. 88 | 89 | - Added support for connection timeouts, heartbeats, and xpub welcome messages. 90 | 91 | ## Deprecations 92 | 93 | - `Message::send_msg()` and `send_str()` are deprecated in favor of 94 | `Message::send()`. 95 | 96 | # 0.8.3 97 | 98 | ## New and improved functionality 99 | 100 | - Support for the `zmq_socket_monitor` API. 101 | - Added `PollItem::set_events`, which allows for constructing a `PollItem` from 102 | arbitrary file descriptors. 103 | 104 | ## Bug fixes 105 | 106 | - Fix feature detection for `zmq_has` (issue #207). 107 | 108 | # 0.8.2 109 | 110 | ## New and improved functionality 111 | 112 | - Support for the `ZMQ_PROBE_ROUTER` and `ZMQ_ROUTER_MANDATORY` socket 113 | options. 114 | - `zmq_disconnect` is now exposed as `Socket::disconnect`. 115 | 116 | ## Bug fixes 117 | 118 | - Fix build on OpenBSD (issue #170). 119 | - Account for OpenBSD not defining `EPROTO`. 120 | - Fix build for 32-bit Windows. 121 | - Handle `EINTR` in `Error::from_raw` (issue #174). 122 | - Alignment of `zmq_msg_t` FFI type fixed. 123 | - Fix `build.rs` to portably construct paths, instead of hard-coding 124 | slash as path separator. 125 | 126 | # 0.8.1 127 | 128 | This release fixes the remaining Windows-specific issues exposed by 129 | our test suite, as well as improving API convenience a bit. 130 | 131 | ## New and improved functionality 132 | 133 | - Should now work on Windows. 134 | - `Message` now provides the `Eq` trait. 135 | - `From` is now provided for `std::io::Error` (issue #136). 136 | - There is now a type alias `PollEvents` mapping to `i16`. Use that 137 | instead of `i16` to refer to a set of poll events; in 0.9, 138 | `PollEvents` will become a separate type. 139 | - `PollItem` now has methods `is_readable`, `is_writable` and 140 | `is_error`; use those in preference to using bit masking operations 141 | when applicable. 142 | - New example zguide example `mspoller`. 143 | - Some documentation improvements. 144 | - There is now a Unix-specific test integrating `zmq` with Unix 145 | `poll(2)`. 146 | 147 | ## Incompatible API changes 148 | 149 | There has been a minor API change that was deemed necessary for 150 | cross-platform support and to fix broken parts of the API: 151 | 152 | - There is now an internal `RawFd` type alias that maps to `RawFd` on 153 | Unixoids and `RawSocket` on Windows. `Socket::get_fd()` and 154 | `PollItem::from_fd()` now use that instead of `i64` and `c_int`, 155 | respectively. 156 | 157 | # 0.8.0 158 | 159 | This is a feature and bugfix release. The API has changed, partially 160 | in slightly incompatible ways. Typical code, for some suitable value 161 | of "typical", should still compile when it did with 0.7, but expect a 162 | lot of warnings due to reduced mutability requirements for `Socket` 163 | and `Context`. 164 | 165 | Note that this release adds initial support for the Windows platform 166 | (PR #124). While the code now compiles, the test suite is still broken 167 | under Windows (issue #125). 168 | 169 | Since these release notes have been assembled post-hoc, they are 170 | highly likely to be incomplete. 171 | 172 | ## Incompatible API changes 173 | 174 | The following methods of `Socket` changed: 175 | 176 | - The deprecated `close()` method has been removed. 177 | - `to_raw()` is now known as `into_raw()`. 178 | - `borrow_raw()` is known as `as_mut_ptr()`, and takes a `&mut self` 179 | now. 180 | 181 | ## New and improved functionality 182 | 183 | Note that the added `CURVE` and `GSSAPI` parts of the API are 184 | conditional, depending on the compile-time detected capabilities of 185 | libzmq. 186 | 187 | - Most methods of `Socket` no longer require `&mut self`. 188 | - `Context` now can be shared across threads 189 | - rust-zmq should now work across a wider range of libzmq versions. 190 | - More functions now have minimal documentation, but there is still 191 | lots of improvements to make in this area. 192 | - Initial API coverage for encryption via the `Mechanism` and 193 | `CurveKeyPair` data types. 194 | - Wrappers for the Z85 codec (`z85_encode` and `z85_decode`). 195 | - New socket option accessors for: 196 | - `ZMQ_LAST_ENDPOINT` 197 | - `ZMQ_IMMEDIATE` 198 | - `ZMQ_PROBE_ROUTER`, `ZMQ_ROUTER_MANDATORY` 199 | - `ZMQ_RCVTIMEO`, `ZMQ_SNDTIMEO` 200 | - Various Kerberos (aka `GSSAPI`) and encryption-related (aka 201 | `CURVE`) options. 202 | - New zguide examples `fileio3`, `msreader`, `rtdealer`, `lvcache`, 203 | `pathopub` and `pathosub`. 204 | - There now is a test suite. 205 | 206 | ## Deprecations 207 | 208 | `Constants` will be removed from public API in the next release; it 209 | should not be needed in client code, since corresponding functionality 210 | is provided in a higher-level form. 211 | 212 | ## Bugfixes 213 | 214 | Yes, there have been bugs that were fixed; hopefully for the next 215 | releases, a reasonably accurate list of those will be provided. 216 | 217 | ## Internals 218 | 219 | Some redundancy in error handling and socket option handling has been 220 | abstracted over using macros. 221 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Rust ZeroMQ bindings. 2 | 3 | [![Travis Build Status](https://travis-ci.org/erickt/rust-zmq.png?branch=master)](https://travis-ci.org/erickt/rust-zmq) 4 | [![Appveyor Build status](https://ci.appveyor.com/api/projects/status/xhytsx4jwyb9qk7m?svg=true)](https://ci.appveyor.com/project/erickt/rust-zmq) 5 | [![Coverage Status](https://coveralls.io/repos/erickt/erickt-zmq/badge.svg?branch=master)](https://coveralls.io/r/erickt/erickt-zmq?branch=master) 6 | [![Apache 2.0 licensed](https://img.shields.io/badge/license-Apache2.0-blue.svg)](./LICENSE-APACHE) 7 | [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE-MIT) 8 | [![crates.io](http://meritbadge.herokuapp.com/zmq)](https://crates.io/crates/zmq) 9 | [![docs](https://docs.rs/zmq/badge.svg)](https://docs.rs/zmq) 10 | 11 | [Documentation](https://docs.rs/crate/zmq/) 12 | 13 | [Release Notes](https://github.com/erickt/rust-zmq/tree/master/NEWS.md) 14 | 15 | # About 16 | 17 | The `zmq` crate provides bindings for the `libzmq` library from the 18 | [ZeroMQ](https://zeromq.org/) project. The API exposed by `zmq` should 19 | be safe (in the usual Rust sense), but it follows the C API closely, 20 | so it is not very idiomatic. 21 | 22 | # Compatibility 23 | 24 | The aim of this project is to track latest zmq releases as close as possible. 25 | 26 | Regarding the minimum Rust version required, `zmq` is CI-tested on current 27 | stable channels of Rust. 28 | 29 | # Usage 30 | 31 | `zmq` is a pretty straight forward port of the C API into Rust: 32 | 33 | ```rust 34 | fn main() { 35 | let ctx = zmq::Context::new(); 36 | 37 | let socket = ctx.socket(zmq::REQ).unwrap(); 38 | socket.connect("tcp://127.0.0.1:1234").unwrap(); 39 | socket.send("hello world!", 0).unwrap(); 40 | } 41 | ``` 42 | 43 | You can find more usage examples in 44 | https://github.com/erickt/rust-zmq/tree/master/examples. 45 | 46 | # Contributing 47 | 48 | Unless you explicitly state otherwise, any contribution intentionally 49 | submitted for inclusion in the work by you, as defined in the 50 | Apache-2.0 license, shall be dual licensed under the terms of both the 51 | Apache License, Version 2.0 and the MIT license without any additional 52 | terms or conditions. 53 | 54 | See the [contribution guidelines] for what to watch out for when 55 | submitting a pull request. 56 | 57 | [contribution guidelines]: ./CONTRIBUTING.md 58 | -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!( 3 | "cargo:rustc-env=BUILD_PROFILE={}", 4 | std::env::var("PROFILE").unwrap() 5 | ); 6 | } 7 | -------------------------------------------------------------------------------- /examples/msgsend/main.rs: -------------------------------------------------------------------------------- 1 | // A port of the simplistic benchmark from 2 | // 3 | // http://github.com/PaulKeeble/ScalaVErlangAgents 4 | // 5 | // I *think* it's the same, more or less. 6 | 7 | #![crate_name = "msgsend"] 8 | 9 | use std::env; 10 | use std::f64; 11 | use std::sync::mpsc::{channel, Receiver, Sender}; 12 | use std::thread; 13 | use std::time::{Duration, Instant}; 14 | 15 | fn server(pull_socket: &zmq::Socket, push_socket: &zmq::Socket, mut workers: u64) { 16 | let mut count = 0; 17 | let mut msg = zmq::Message::new(); 18 | 19 | while workers != 0 { 20 | pull_socket.recv(&mut msg, 0).unwrap(); 21 | let s = msg.as_str().unwrap(); 22 | if s.is_empty() { 23 | workers -= 1; 24 | } else { 25 | count += s.parse::().unwrap(); 26 | } 27 | } 28 | 29 | push_socket.send(&count.to_string(), 0).unwrap(); 30 | } 31 | 32 | fn spawn_server(ctx: &mut zmq::Context, workers: u64) -> Sender<()> { 33 | let pull_socket = ctx.socket(zmq::PULL).unwrap(); 34 | let push_socket = ctx.socket(zmq::PUSH).unwrap(); 35 | 36 | pull_socket.bind("inproc://server-pull").unwrap(); 37 | push_socket.bind("inproc://server-push").unwrap(); 38 | 39 | // Spawn the server. 40 | let (ready_tx, ready_rx) = channel(); 41 | let (start_tx, start_rx) = channel(); 42 | 43 | thread::spawn(move || { 44 | // Let the main thread know we're ready. 45 | ready_tx.send(()).unwrap(); 46 | 47 | // Wait until we need to start. 48 | start_rx.recv().unwrap(); 49 | 50 | server(&pull_socket, &push_socket, workers); 51 | }); 52 | 53 | // Wait for the server to start. 54 | ready_rx.recv().unwrap(); 55 | 56 | start_tx 57 | } 58 | 59 | fn worker(push_socket: &zmq::Socket, count: u64) { 60 | for _ in 0..count { 61 | push_socket.send(&100.to_string(), 0).unwrap(); 62 | } 63 | 64 | // Let the server know we're done. 65 | push_socket.send("", 0).unwrap(); 66 | } 67 | 68 | fn spawn_worker(ctx: &mut zmq::Context, count: u64) -> Receiver<()> { 69 | let push_socket = ctx.socket(zmq::PUSH).unwrap(); 70 | 71 | push_socket.connect("inproc://server-pull").unwrap(); 72 | //push_socket.connect("tcp://127.0.0.1:3456").unwrap(); 73 | 74 | // Spawn the worker. 75 | let (tx, rx) = channel(); 76 | thread::spawn(move || { 77 | // Let the main thread we're ready. 78 | tx.send(()).unwrap(); 79 | 80 | worker(&push_socket, count); 81 | 82 | tx.send(()).unwrap(); 83 | }); 84 | 85 | // Wait for the worker to start. 86 | rx.recv().unwrap(); 87 | 88 | rx 89 | } 90 | 91 | fn seconds(d: &Duration) -> f64 { 92 | d.as_secs() as f64 + (f64::from(d.subsec_nanos()) / 1e9) 93 | } 94 | 95 | fn run(ctx: &mut zmq::Context, size: u64, workers: u64) { 96 | let start_ch = spawn_server(ctx, workers); 97 | 98 | // Create some command/control sockets. 99 | let push_socket = ctx.socket(zmq::PUSH).unwrap(); 100 | let pull_socket = ctx.socket(zmq::PULL).unwrap(); 101 | 102 | push_socket.connect("inproc://server-pull").unwrap(); 103 | pull_socket.connect("inproc://server-push").unwrap(); 104 | //push_socket.connect("tcp://127.0.0.1:3456").unwrap(); 105 | //pull_socket.connect("tcp://127.0.0.1:3457").unwrap(); 106 | 107 | // Spawn all the workers. 108 | let mut worker_results = Vec::new(); 109 | for _ in 0..workers { 110 | worker_results.push(spawn_worker(ctx, size / workers)); 111 | } 112 | 113 | let start = Instant::now(); 114 | 115 | start_ch.send(()).unwrap(); 116 | 117 | // Block until all the workers finish. 118 | for po in worker_results { 119 | po.recv().unwrap(); 120 | } 121 | 122 | // Receive the final count. 123 | let msg = pull_socket.recv_msg(0).unwrap(); 124 | let result = msg.as_str().unwrap().parse::().unwrap(); 125 | 126 | let elapsed = seconds(&start.elapsed()); 127 | 128 | println!("Count is {}", result); 129 | println!("Test took {} seconds", elapsed); 130 | let thruput = ((size / workers * workers) as f64) / elapsed; 131 | println!("Throughput={} per sec", thruput); 132 | } 133 | 134 | fn main() { 135 | let args: Vec = env::args().collect(); 136 | 137 | let args = if env::var("RUST_BENCH").is_ok() { 138 | vec!["".to_string(), "1000000".to_string(), "10000".to_string()] 139 | } else if args.len() <= 1 { 140 | vec!["".to_string(), "10000".to_string(), "4".to_string()] 141 | } else { 142 | args 143 | }; 144 | 145 | let size = args[1].parse().unwrap(); 146 | let workers = args[2].parse().unwrap(); 147 | 148 | let mut ctx = zmq::Context::new(); 149 | 150 | run(&mut ctx, size, workers); 151 | } 152 | -------------------------------------------------------------------------------- /examples/stream/logserver.rs: -------------------------------------------------------------------------------- 1 | // Very basic example to listen tcp socket from zmq using STREAM sockets 2 | // You can use telnet to send messages and they will be output to console 3 | // ZMQ_STREAM socket will prepend socket identity on message, that's why we use recv_multipart here 4 | 5 | use std::str; 6 | 7 | fn main() { 8 | println!("Hello, world!"); 9 | 10 | let ctx = zmq::Context::new(); 11 | 12 | let socket = ctx.socket(zmq::STREAM).unwrap(); 13 | socket.bind("tcp://*:8888").unwrap(); 14 | loop { 15 | let data = socket.recv_multipart(0).unwrap(); 16 | println!( 17 | "Identity: {:?} Message : {}", 18 | data[0], 19 | str::from_utf8(&data[1]).unwrap() 20 | ); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /examples/zguide/README.md: -------------------------------------------------------------------------------- 1 | This is the C examples from the zeromq guide (http://zguide.zeromq.org/), 2 | written in Rust. 3 | 4 | The coding guidelines for porting examples is: 5 | 6 | - Faithfully implement the semantics from the guide, and also follow 7 | their code structure as far as reasonable. This allows for knowledge 8 | transfer between languages. 9 | 10 | - Use ideomatic Rust, and use the most fitting abstraction offered by 11 | the bindings. We want these to also highlight the differences in API 12 | usage and the higher-level abstractions provided, if applicable. 13 | 14 | Besides giving potential rust-zmq users an impression of the bindings, 15 | these examples are also intended as a "proving ground" for API 16 | additions and changes. Ideally, an API change should be reflected in 17 | changes to the examples that improve code quality (by whatever 18 | metric). 19 | -------------------------------------------------------------------------------- /examples/zguide/asyncsrv/main.rs: -------------------------------------------------------------------------------- 1 | // Asynchronous client-to-server (DEALER to ROUTER) 2 | // 3 | // While this example runs in a single process, that is to make 4 | // it easier to start and stop the example. Each task has its own 5 | // context and conceptually acts as a separate process. 6 | #![crate_name = "asyncsrv"] 7 | 8 | use rand::{thread_rng, Rng}; 9 | use std::time::Duration; 10 | use std::{str, thread}; 11 | 12 | fn client_task() { 13 | let context = zmq::Context::new(); 14 | let client = context.socket(zmq::DEALER).unwrap(); 15 | let mut rng = thread_rng(); 16 | let identity = format!("{:04X}-{:04X}", rng.gen::(), rng.gen::()); 17 | client 18 | .set_identity(identity.as_bytes()) 19 | .expect("failed setting client id"); 20 | client 21 | .connect("tcp://localhost:5570") 22 | .expect("failed connecting client"); 23 | let mut request_nbr = 0; 24 | loop { 25 | for _ in 0..100 { 26 | if client.poll(zmq::POLLIN, 10).expect("client failed polling") > 0 { 27 | let msg = client 28 | .recv_multipart(0) 29 | .expect("client failed receivng response"); 30 | println!("{}", str::from_utf8(&msg[msg.len() - 1]).unwrap()); 31 | } 32 | } 33 | request_nbr += 1; 34 | let request = format!("request #{}", request_nbr); 35 | client 36 | .send(&request, 0) 37 | .expect("client failed sending request"); 38 | } 39 | } 40 | 41 | fn server_task() { 42 | let context = zmq::Context::new(); 43 | let frontend = context.socket(zmq::ROUTER).unwrap(); 44 | frontend 45 | .bind("tcp://*:5570") 46 | .expect("server failed binding frontend"); 47 | let backend = context.socket(zmq::DEALER).unwrap(); 48 | backend 49 | .bind("inproc://backend") 50 | .expect("server failed binding backend"); 51 | for _ in 0..5 { 52 | let ctx = context.clone(); 53 | thread::spawn(move || server_worker(&ctx)); 54 | } 55 | zmq::proxy(&frontend, &backend).expect("server failed proxying"); 56 | } 57 | 58 | fn server_worker(context: &zmq::Context) { 59 | let worker = context.socket(zmq::DEALER).unwrap(); 60 | worker 61 | .connect("inproc://backend") 62 | .expect("worker failed to connect to backend"); 63 | let mut rng = thread_rng(); 64 | 65 | loop { 66 | let identity = worker 67 | .recv_string(0) 68 | .expect("worker failed receiving identity") 69 | .unwrap(); 70 | let message = worker 71 | .recv_string(0) 72 | .expect("worker failed receiving message") 73 | .unwrap(); 74 | let replies = rng.gen_range(0..4); 75 | for _ in 0..replies { 76 | thread::sleep(Duration::from_millis(rng.gen_range(0..1000) + 1)); 77 | worker 78 | .send(&identity, zmq::SNDMORE) 79 | .expect("worker failed sending identity"); 80 | worker 81 | .send(&message, 0) 82 | .expect("worker failed sending message"); 83 | } 84 | } 85 | } 86 | 87 | fn main() { 88 | thread::spawn(client_task); 89 | thread::spawn(client_task); 90 | thread::spawn(client_task); 91 | thread::spawn(server_task); 92 | thread::sleep(Duration::from_secs(5)); 93 | } 94 | -------------------------------------------------------------------------------- /examples/zguide/fileio3/main.rs: -------------------------------------------------------------------------------- 1 | #![crate_name = "fileio3"] 2 | 3 | //! File Transfer model #3 4 | //! 5 | //! In which the client requests each chunk individually, using 6 | //! command pipelining to give us a credit-based flow control. 7 | 8 | use rand::distributions::Alphanumeric; 9 | use rand::Rng; 10 | use std::fs::File; 11 | use std::io::{Error, Read, Seek, SeekFrom, Write}; 12 | use std::thread; 13 | use tempfile::tempfile; 14 | use zmq::SNDMORE; 15 | 16 | static CHUNK_SIZE: usize = 250_000; 17 | static CHUNK_SIZE_STR: &str = "250000"; 18 | static PIPELINE: usize = 10; 19 | static PIPELINE_HWM: usize = 20; 20 | 21 | fn random_string(length: usize) -> String { 22 | String::from_utf8( 23 | rand::thread_rng() 24 | .sample_iter(&Alphanumeric) 25 | .take(length) 26 | .collect(), 27 | ) 28 | .unwrap() 29 | } 30 | 31 | fn client_thread(expected_total: usize) { 32 | let context = zmq::Context::new(); 33 | let dealer = context.socket(zmq::DEALER).unwrap(); 34 | let identity: Vec = (0..10).map(|_| rand::random::()).collect(); 35 | dealer.set_identity(&identity).unwrap(); 36 | 37 | assert!(dealer.connect("tcp://localhost:6000").is_ok()); 38 | 39 | // Up to this many chunks in transit 40 | let mut credit = PIPELINE; 41 | 42 | let mut total = 0; // Total bytes received 43 | let mut chunks = 0; // Total chunks received 44 | let mut offset = 0; // Offset of next chunk request 45 | 46 | let mut clean_break = false; 47 | loop { 48 | while (credit > 0) && !clean_break { 49 | // Ask for next chunk 50 | dealer.send("fetch", SNDMORE).unwrap(); 51 | dealer.send(&offset.to_string(), SNDMORE).unwrap(); 52 | dealer.send(CHUNK_SIZE_STR, 0).unwrap(); 53 | offset += CHUNK_SIZE; 54 | credit -= 1; 55 | } 56 | let chunk = dealer.recv_string(0).unwrap().unwrap(); 57 | if chunk.is_empty() { 58 | clean_break = true; // Shutting down, quit 59 | } 60 | chunks += 1; 61 | credit += 1; 62 | let size = chunk.len(); 63 | total += size; 64 | if size < CHUNK_SIZE { 65 | clean_break = true; // Last chunk received; exit 66 | } 67 | if clean_break && (credit == PIPELINE) { 68 | break; // All requests have completed, we can cleanly break. 69 | } 70 | } 71 | println!("{:?} chunks received, {} bytes\n", chunks, total); 72 | assert!(expected_total == total); 73 | } 74 | 75 | // The rest of the code is exactly the same as in model 2, except 76 | // that we set the HWM on the server's ROUTER socket to PIPELINE 77 | // to act as a sanity check. 78 | 79 | // The server thread waits for a chunk request from a client, 80 | // reads that chunk and sends it back to the client: 81 | 82 | fn server_thread(file: &mut File) -> Result<(), Error> { 83 | let context = zmq::Context::new(); 84 | let router = context.socket(zmq::ROUTER).unwrap(); 85 | // We have two parts per message so HWM is PIPELINE * 2 86 | router.set_sndhwm(PIPELINE_HWM as i32).unwrap(); 87 | assert!(router.bind("tcp://*:6000").is_ok()); 88 | 89 | loop { 90 | // First frame in each message is the sender identity 91 | let identity = router.recv_bytes(0).unwrap(); 92 | if identity.is_empty() { 93 | break; // Shutting down, quit 94 | } 95 | 96 | // Second frame is "fetch" command 97 | let command = router.recv_string(0).unwrap().unwrap(); 98 | assert!(command == "fetch"); 99 | 100 | // Third frame is chunk offset in file 101 | let offset = router.recv_string(0).unwrap().unwrap(); 102 | let offset = offset.parse::().unwrap(); 103 | 104 | // Fourth frame is maximum chunk size 105 | let chunk_size = router.recv_string(0).unwrap().unwrap(); 106 | let chunk_size = chunk_size.parse::().unwrap(); 107 | 108 | // Seek to offset 109 | file.seek(SeekFrom::Start(offset)).unwrap(); 110 | // Read chunk of data from file 111 | let mut data = vec![0; chunk_size]; 112 | let size = file.read(&mut data)?; 113 | data.truncate(size); 114 | 115 | // Send resulting chunk to client 116 | router.send(&identity, SNDMORE).unwrap(); 117 | router.send(&data, 0).unwrap(); 118 | } 119 | Ok(()) 120 | } 121 | 122 | // The main task starts the client and server threads; it's easier 123 | // to test this as a single process with threads, than as multiple 124 | // processes: 125 | fn main() { 126 | // Start child threads 127 | thread::spawn(|| { 128 | // Generate test data in a temp directory 129 | println!("Generating temporary data..."); 130 | let mut file = tempfile().unwrap(); 131 | // Prepare some random test data of appropriate size 132 | file.write_all(random_string(10 * CHUNK_SIZE).as_bytes()) 133 | .unwrap(); 134 | 135 | // Start server thread 136 | println!("Emitting file content of {:?} bytes", 10 * CHUNK_SIZE); 137 | server_thread(&mut file).unwrap(); 138 | }); 139 | let client_child = thread::spawn(|| { 140 | // Start client thread 141 | client_thread(10 * CHUNK_SIZE); 142 | }); 143 | // Loop until client tells us it's done 144 | client_child.join().unwrap(); 145 | } 146 | -------------------------------------------------------------------------------- /examples/zguide/helloworld_client/main.rs: -------------------------------------------------------------------------------- 1 | #![crate_name = "helloworld_client"] 2 | 3 | //! Hello World client 4 | 5 | fn main() { 6 | println!("Connecting to hello world server...\n"); 7 | 8 | let context = zmq::Context::new(); 9 | let requester = context.socket(zmq::REQ).unwrap(); 10 | 11 | assert!(requester.connect("tcp://localhost:5555").is_ok()); 12 | 13 | let mut msg = zmq::Message::new(); 14 | 15 | for request_nbr in 0..10 { 16 | println!("Sending Hello {}...", request_nbr); 17 | requester.send("Hello", 0).unwrap(); 18 | 19 | requester.recv(&mut msg, 0).unwrap(); 20 | println!("Received World {}: {}", msg.as_str().unwrap(), request_nbr); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /examples/zguide/helloworld_server/main.rs: -------------------------------------------------------------------------------- 1 | #![crate_name = "helloworld_server"] 2 | 3 | //! Hello World server in Rust 4 | //! Binds REP socket to tcp://*:5555 5 | //! Expects "Hello" from client, replies with "World" 6 | 7 | use std::thread; 8 | use std::time::Duration; 9 | 10 | fn main() { 11 | let context = zmq::Context::new(); 12 | let responder = context.socket(zmq::REP).unwrap(); 13 | 14 | assert!(responder.bind("tcp://*:5555").is_ok()); 15 | 16 | let mut msg = zmq::Message::new(); 17 | loop { 18 | responder.recv(&mut msg, 0).unwrap(); 19 | println!("Received {}", msg.as_str().unwrap()); 20 | thread::sleep(Duration::from_millis(1000)); 21 | responder.send("World", 0).unwrap(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /examples/zguide/lbbroker/main.rs: -------------------------------------------------------------------------------- 1 | #![crate_name = "lbbroker"] 2 | 3 | //! load balancing broker 4 | //! clients and workers here are shown in process 5 | 6 | use zmq::SNDMORE; 7 | //use std::time::; 8 | use std::thread; 9 | 10 | // Basic request-reply client using REQ socket 11 | // Because s_send and s_recv can't handle 0MQ binary identities, we 12 | // set a printable text identity to allow routing. 13 | fn client_task(client_nbr: i32) { 14 | //create context and client socket 15 | let context = zmq::Context::new(); 16 | let client = context.socket(zmq::REQ).unwrap(); 17 | 18 | //set random indentity string and connect 19 | let identity = format!("Client{}", client_nbr); 20 | client.set_identity(identity.as_bytes()).unwrap(); 21 | client 22 | .connect("ipc://frontend.ipc") 23 | .expect("failed connecting client"); 24 | 25 | //send request, get reply 26 | client 27 | .send("HELLO", 0) 28 | .expect("client failed sending request"); 29 | let reply = client 30 | .recv_string(0) 31 | .expect("client failed receiving reply") 32 | .unwrap(); 33 | println!("Client: {}", reply); 34 | } 35 | 36 | fn worker_task(worker_nbr: i32) { 37 | let context = zmq::Context::new(); 38 | let worker = context.socket(zmq::REQ).unwrap(); 39 | let identity = format!("Worker{}", worker_nbr); 40 | worker.set_identity(identity.as_bytes()).unwrap(); 41 | assert!(worker.connect("ipc://backend.ipc").is_ok()); 42 | 43 | // Tell the broker we're ready for work 44 | worker.send("READY", 0).unwrap(); 45 | 46 | loop { 47 | //Read and save all frames until we get an empty frame 48 | //In this example there is only 1 but there could be more 49 | let identity = worker 50 | .recv_string(0) 51 | .expect("worker failed receiving id") 52 | .unwrap(); 53 | let empty = worker 54 | .recv_string(0) 55 | .expect("worker failed receving empty") 56 | .unwrap(); 57 | assert!(empty.is_empty()); 58 | // Get workload from broker, until finished 59 | let request = worker.recv_string(0).unwrap().unwrap(); 60 | println!("Worker: {}", request); 61 | worker 62 | .send(&identity, SNDMORE) 63 | .expect("worker failed sending identity"); 64 | worker 65 | .send("", SNDMORE) 66 | .expect("worker failed sending empty frame"); 67 | worker.send("OK", 0).expect("worker failed sending OK"); 68 | } 69 | } 70 | 71 | fn main() { 72 | let worker_pool_size = 3; 73 | let client_pool_size = 10; 74 | let context = zmq::Context::new(); 75 | let frontend = context.socket(zmq::ROUTER).unwrap(); 76 | let backend = context.socket(zmq::ROUTER).unwrap(); 77 | frontend 78 | .bind("ipc://frontend.ipc") 79 | .expect("failed binding frontend"); 80 | backend 81 | .bind("ipc://backend.ipc") 82 | .expect("failed binding backend"); 83 | // While this example runs in a single process, that is just to make 84 | // it easier to start and stop the example. Each thread has its own 85 | // context and conceptually acts as a separate process. 86 | let mut client_thread_pool = Vec::new(); 87 | for client_nbr in 0..client_pool_size { 88 | let child = thread::spawn(move || { 89 | client_task(client_nbr); 90 | }); 91 | client_thread_pool.push(child); 92 | } 93 | 94 | let mut worker_thread_pool = Vec::new(); 95 | for worker_nbr in 0..worker_pool_size { 96 | let child = thread::spawn(move || { 97 | worker_task(worker_nbr); 98 | }); 99 | worker_thread_pool.push(child); 100 | } 101 | // Here is the main loop for the least-recently-used queue. It has two 102 | // sockets; a frontend for clients and a backend for workers. It polls 103 | // the backend in all cases, and polls the frontend only when there are 104 | // one or more workers ready. This is a neat way to use 0MQ's own queues 105 | // to hold messages we're not ready to process yet. When we get a client 106 | // reply, we pop the next available worker and send the request to it, 107 | // including the originating client identity. When a worker replies, 108 | // we requeue that worker and forward the reply to the original 109 | // client using the reply envelope. 110 | let mut client_nbr = client_pool_size; 111 | let mut worker_queue = Vec::new(); 112 | loop { 113 | let mut items = [ 114 | backend.as_poll_item(zmq::POLLIN), 115 | frontend.as_poll_item(zmq::POLLIN), 116 | ]; 117 | let rc = zmq::poll( 118 | &mut items[0..if worker_queue.is_empty() { 1 } else { 2 }], 119 | -1, 120 | ) 121 | .unwrap(); 122 | 123 | if rc == -1 { 124 | break; 125 | } 126 | 127 | if items[0].is_readable() { 128 | let worker_id = backend 129 | .recv_string(0) 130 | .expect("backend failed receiving worker id") 131 | .unwrap(); 132 | assert!( 133 | backend 134 | .recv_string(0) 135 | .expect("backend failed receiving empty") 136 | .unwrap() 137 | == "" 138 | ); 139 | assert!(worker_queue.len() < (worker_pool_size as usize)); 140 | worker_queue.push(worker_id); 141 | let client_id = backend 142 | .recv_string(0) 143 | .expect("backend failed receiving client id") 144 | .unwrap(); 145 | 146 | //if client reply send rest to front end 147 | if client_id != "READY" { 148 | assert!( 149 | backend 150 | .recv_string(0) 151 | .expect("backend failed receiving second empty") 152 | .unwrap() 153 | == "" 154 | ); 155 | let reply = backend 156 | .recv_string(0) 157 | .expect("backend failed receiving client reply") 158 | .unwrap(); 159 | frontend 160 | .send(&client_id, SNDMORE) 161 | .expect("frontend failed sending client id"); 162 | frontend 163 | .send("", SNDMORE) 164 | .expect("frontend failed sending empty"); 165 | frontend 166 | .send(&reply, 0) 167 | .expect("frontend failed sending reply"); 168 | client_nbr -= 1; 169 | if client_nbr == 0 { 170 | break; 171 | } 172 | } 173 | } 174 | 175 | if items[1].is_readable() { 176 | // Now get next client request, route to last-used worker 177 | // Client request is [identity][empty][request] 178 | let client_id = frontend 179 | .recv_string(0) 180 | .expect("frontend failed receiving client id") 181 | .unwrap(); 182 | assert!( 183 | frontend 184 | .recv_string(0) 185 | .expect("frontend failed receiving empty") 186 | .unwrap() 187 | == "" 188 | ); 189 | let request = frontend 190 | .recv_string(0) 191 | .expect("frontend failed receiving request") 192 | .unwrap(); 193 | 194 | let worker = worker_queue.pop().unwrap(); 195 | backend 196 | .send(&worker, SNDMORE) 197 | .expect("backend failed sending worker_id"); 198 | backend 199 | .send("", SNDMORE) 200 | .expect("backend failed sending empty"); 201 | backend 202 | .send(client_id.as_bytes(), SNDMORE) 203 | .expect("backend failed sending client_id"); 204 | backend 205 | .send("", SNDMORE) 206 | .expect("backend faield sending second empty"); 207 | backend 208 | .send(&request, 0) 209 | .expect("backend failed sending request"); 210 | } 211 | } 212 | } 213 | -------------------------------------------------------------------------------- /examples/zguide/lvcache/main.rs: -------------------------------------------------------------------------------- 1 | #![crate_name = "lvcache"] 2 | 3 | use std::collections::HashMap; 4 | use std::str::from_utf8; 5 | 6 | fn main() { 7 | let context = zmq::Context::new(); 8 | let frontend = context.socket(zmq::SUB).unwrap(); 9 | frontend 10 | .connect("tcp://localhost:5557") 11 | .expect("could not connect to frontend"); 12 | let backend = context.socket(zmq::XPUB).unwrap(); 13 | backend 14 | .bind("tcp://*:5558") 15 | .expect("could not bind backend socket"); 16 | 17 | // Subscribe to every single topic from publisher 18 | frontend.set_subscribe(b"").unwrap(); 19 | 20 | let mut cache = HashMap::new(); 21 | 22 | loop { 23 | let mut items = [ 24 | frontend.as_poll_item(zmq::POLLIN), 25 | backend.as_poll_item(zmq::POLLIN), 26 | ]; 27 | if zmq::poll(&mut items, 1000).is_err() { 28 | break; // Interrupted 29 | } 30 | if items[0].is_readable() { 31 | let topic = frontend.recv_msg(0).unwrap(); 32 | let current = frontend.recv_msg(0).unwrap(); 33 | cache.insert(topic.to_vec(), current.to_vec()); 34 | backend.send(topic, zmq::SNDMORE).unwrap(); 35 | backend.send(current, 0).unwrap(); 36 | } 37 | if items[1].is_readable() { 38 | // Event is one byte 0=unsub or 1=sub, followed by topic 39 | let event = backend.recv_msg(0).unwrap(); 40 | if event[0] == 1 { 41 | let topic = &event[1..]; 42 | println!("Sending cached topic {}", from_utf8(topic).unwrap()); 43 | if let Some(previous) = cache.get(topic) { 44 | backend.send(topic, zmq::SNDMORE).unwrap(); 45 | backend.send(previous, 0).unwrap(); 46 | } 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /examples/zguide/msgqueue/main.rs: -------------------------------------------------------------------------------- 1 | #![crate_name = "msgqueue"] 2 | 3 | fn main() { 4 | let context = zmq::Context::new(); 5 | let frontend = context.socket(zmq::ROUTER).unwrap(); 6 | let backend = context.socket(zmq::DEALER).unwrap(); 7 | 8 | frontend 9 | .bind("tcp://*:5559") 10 | .expect("failed binding frontend"); 11 | backend 12 | .bind("tcp://*:5560") 13 | .expect("failed binding backend"); 14 | 15 | zmq::proxy(&frontend, &backend).expect("failed to proxy"); 16 | } 17 | -------------------------------------------------------------------------------- /examples/zguide/mspoller/main.rs: -------------------------------------------------------------------------------- 1 | // Reading from multiple sockets 2 | // This version uses zmq::poll() 3 | 4 | fn main() { 5 | let context = zmq::Context::new(); 6 | 7 | // Connect to task ventilator 8 | let receiver = context.socket(zmq::PULL).unwrap(); 9 | assert!(receiver.connect("tcp://localhost:5557").is_ok()); 10 | 11 | // Connect to weather server 12 | let subscriber = context.socket(zmq::SUB).unwrap(); 13 | assert!(subscriber.connect("tcp://localhost:5556").is_ok()); 14 | let filter = b"10001"; 15 | assert!(subscriber.set_subscribe(filter).is_ok()); 16 | 17 | // Process messages from both sockets 18 | let mut msg = zmq::Message::new(); 19 | loop { 20 | let mut items = [ 21 | receiver.as_poll_item(zmq::POLLIN), 22 | subscriber.as_poll_item(zmq::POLLIN), 23 | ]; 24 | zmq::poll(&mut items, -1).unwrap(); 25 | if items[0].is_readable() && receiver.recv(&mut msg, 0).is_ok() { 26 | // Process task 27 | } 28 | if items[1].is_readable() && subscriber.recv(&mut msg, 0).is_ok() { 29 | // Process weather update 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /examples/zguide/msreader/main.rs: -------------------------------------------------------------------------------- 1 | #![crate_name = "msreader"] 2 | 3 | //! Reading from multiple sockets 4 | //! This version uses a simple recv loop 5 | 6 | use std::thread; 7 | use std::time::Duration; 8 | 9 | fn main() { 10 | let context = zmq::Context::new(); 11 | 12 | // Connect to task ventilator 13 | let receiver = context.socket(zmq::PULL).unwrap(); 14 | assert!(receiver.connect("tcp://localhost:5557").is_ok()); 15 | 16 | // Connect to weather server 17 | let subscriber = context.socket(zmq::SUB).unwrap(); 18 | assert!(subscriber.connect("tcp://localhost:5556").is_ok()); 19 | let filter = b"10001"; 20 | assert!(subscriber.set_subscribe(filter).is_ok()); 21 | 22 | // Process messages from both sockets 23 | // We prioritize traffic from the task ventilator 24 | let mut msg = zmq::Message::new(); 25 | loop { 26 | loop { 27 | if receiver.recv(&mut msg, zmq::DONTWAIT).is_err() { 28 | break; 29 | } 30 | // Process task 31 | } 32 | 33 | loop { 34 | if subscriber.recv(&mut msg, zmq::DONTWAIT).is_err() { 35 | break; 36 | } 37 | // Process weather update 38 | } 39 | 40 | // No activity, so sleep for 1 msec 41 | thread::sleep(Duration::from_millis(1)) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /examples/zguide/mtrelay/main.rs: -------------------------------------------------------------------------------- 1 | #![crate_name = "mtrelay"] 2 | 3 | use std::thread; 4 | 5 | fn step1(context: &zmq::Context) { 6 | //connect to step 2 and tell it we're ready 7 | let xmitter = context.socket(zmq::PAIR).unwrap(); 8 | xmitter 9 | .connect("inproc://step2") 10 | .expect("step 1 failed connecting"); 11 | println!("Step 1 ready, signalling step 2"); 12 | xmitter.send("READY", 0).expect("step 1 failed sending"); 13 | } 14 | 15 | fn step2(context: &zmq::Context) { 16 | //bind inproc socket before starting step 1 17 | let receiver = context.socket(zmq::PAIR).unwrap(); 18 | receiver 19 | .bind("inproc://step2") 20 | .expect("failed binding step 2"); 21 | let ctx = context.clone(); 22 | thread::spawn(move || step1(&ctx)); 23 | 24 | //wait for signal and pass it on 25 | receiver.recv_msg(0).unwrap(); 26 | 27 | //connect to step 3 and tell it we're ready 28 | let xmitter = context.socket(zmq::PAIR).unwrap(); 29 | xmitter 30 | .connect("inproc://step3") 31 | .expect("step 2 failed connecting"); 32 | println!("Step 2 ready, signalling step 3"); 33 | xmitter.send("READY", 0).expect("step 2 failed sending"); 34 | } 35 | 36 | fn main() { 37 | let context = zmq::Context::new(); 38 | 39 | //bind inproc socket before starting step 2 40 | let receiver = context.socket(zmq::PAIR).unwrap(); 41 | receiver 42 | .bind("inproc://step3") 43 | .expect("failed binding step 3"); 44 | thread::spawn(move || step2(&context)); 45 | //wait for signal and pass it on 46 | receiver.recv_msg(0).unwrap(); 47 | println!("Test successful!"); 48 | } 49 | -------------------------------------------------------------------------------- /examples/zguide/mtserver/main.rs: -------------------------------------------------------------------------------- 1 | #![crate_name = "mtserver"] 2 | 3 | use std::thread; 4 | use std::time::Duration; 5 | 6 | fn worker_routine(context: &zmq::Context) { 7 | let receiver = context.socket(zmq::REP).unwrap(); 8 | receiver 9 | .connect("inproc://workers") 10 | .expect("failed to connect worker"); 11 | loop { 12 | receiver 13 | .recv_string(0) 14 | .expect("worker failed receiving") 15 | .unwrap(); 16 | thread::sleep(Duration::from_millis(1000)); 17 | receiver.send("World", 0).unwrap(); 18 | } 19 | } 20 | 21 | fn main() { 22 | let context = zmq::Context::new(); 23 | let clients = context.socket(zmq::ROUTER).unwrap(); 24 | let workers = context.socket(zmq::DEALER).unwrap(); 25 | 26 | clients 27 | .bind("tcp://*:5555") 28 | .expect("failed to bind client router"); 29 | workers 30 | .bind("inproc://workers") 31 | .expect("failed to bind worker dealer"); 32 | 33 | for _ in 0..5 { 34 | let ctx = context.clone(); 35 | thread::spawn(move || worker_routine(&ctx)); 36 | } 37 | zmq::proxy(&clients, &workers).expect("failed proxying"); 38 | } 39 | -------------------------------------------------------------------------------- /examples/zguide/pathopub/main.rs: -------------------------------------------------------------------------------- 1 | // Pathological publisher 2 | // Sends out 1,000 topics and then one random update per second 3 | 4 | use std::env; 5 | use std::thread::sleep; 6 | use std::time::Duration; 7 | 8 | use rand::distributions::{Distribution, Uniform}; 9 | 10 | fn main() { 11 | let context = zmq::Context::new(); 12 | let publisher = context.socket(zmq::PUB).unwrap(); 13 | let args: Vec<_> = env::args().collect(); 14 | let address = if args.len() == 2 { 15 | args[1].as_str() 16 | } else { 17 | "tcp://*:5556" 18 | }; 19 | publisher 20 | .bind(address) 21 | .expect("could not bind publisher socket"); 22 | 23 | // Ensure subscriber connection has time to complete 24 | sleep(Duration::from_millis(1000)); 25 | 26 | // Send out all 1,000 topic messages 27 | for topic_nbr in 0..1000 { 28 | publisher 29 | .send(&format!("{:03}", topic_nbr), zmq::SNDMORE) 30 | .unwrap(); 31 | publisher.send("Save Roger", 0).unwrap(); 32 | } 33 | // Send one random update per second 34 | let mut rng = rand::thread_rng(); 35 | let topic_range = Uniform::new(0, 1000); 36 | loop { 37 | sleep(Duration::from_millis(1000)); 38 | publisher 39 | .send( 40 | &format!("{:03}", topic_range.sample(&mut rng)), 41 | zmq::SNDMORE, 42 | ) 43 | .unwrap(); 44 | publisher.send("Off with his head!", 0).unwrap(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /examples/zguide/pathosub/main.rs: -------------------------------------------------------------------------------- 1 | //! Pathological subscriber 2 | //! Subscribes to one random topic and prints received messages 3 | 4 | use std::env; 5 | 6 | use rand::distributions::{Distribution, Uniform}; 7 | 8 | fn main() { 9 | let context = zmq::Context::new(); 10 | let subscriber = context.socket(zmq::SUB).unwrap(); 11 | 12 | let args: Vec<_> = env::args().collect(); 13 | let address = if args.len() == 2 { 14 | args[1].as_str() 15 | } else { 16 | "tcp://localhost:5556" 17 | }; 18 | subscriber 19 | .connect(address) 20 | .expect("could not connect to publisher"); 21 | 22 | let mut rng = rand::thread_rng(); 23 | let topic_range = Uniform::new(0, 1000); 24 | let subscription = format!("{:03}", topic_range.sample(&mut rng)).into_bytes(); 25 | subscriber.set_subscribe(&subscription).unwrap(); 26 | 27 | loop { 28 | let topic = subscriber.recv_msg(0).unwrap(); 29 | let data = subscriber.recv_msg(0).unwrap(); 30 | assert_eq!(&topic[..], &subscription[..]); 31 | println!("{}", std::str::from_utf8(&data).unwrap()); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /examples/zguide/psenvpub/main.rs: -------------------------------------------------------------------------------- 1 | #![crate_name = "psenvpub"] 2 | 3 | use std::thread; 4 | use std::time::Duration; 5 | 6 | fn main() { 7 | //prepare context and publisher 8 | let context = zmq::Context::new(); 9 | let publisher = context.socket(zmq::PUB).unwrap(); 10 | publisher 11 | .bind("tcp://*:5563") 12 | .expect("failed binding publisher"); 13 | 14 | loop { 15 | publisher 16 | .send("A", zmq::SNDMORE) 17 | .expect("failed sending first envelope"); 18 | publisher 19 | .send("We don't want to see this", 0) 20 | .expect("failed sending first message"); 21 | publisher 22 | .send("B", zmq::SNDMORE) 23 | .expect("failed sending second envelope"); 24 | publisher 25 | .send("We would like to see this", 0) 26 | .expect("failed sending second message"); 27 | thread::sleep(Duration::from_millis(1)); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /examples/zguide/psenvsub/main.rs: -------------------------------------------------------------------------------- 1 | #![crate_name = "psenvsub"] 2 | 3 | fn main() { 4 | let context = zmq::Context::new(); 5 | let subscriber = context.socket(zmq::SUB).unwrap(); 6 | subscriber 7 | .connect("tcp://localhost:5563") 8 | .expect("failed connecting subscriber"); 9 | subscriber.set_subscribe(b"B").expect("failed subscribing"); 10 | 11 | loop { 12 | let envelope = subscriber 13 | .recv_string(0) 14 | .expect("failed receiving envelope") 15 | .unwrap(); 16 | let message = subscriber 17 | .recv_string(0) 18 | .expect("failed receiving message") 19 | .unwrap(); 20 | println!("[{}] {}", envelope, message); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /examples/zguide/rrbroker/main.rs: -------------------------------------------------------------------------------- 1 | #![crate_name = "rrbroker"] 2 | 3 | fn main() { 4 | let context = zmq::Context::new(); 5 | let frontend = context.socket(zmq::ROUTER).unwrap(); 6 | let backend = context.socket(zmq::DEALER).unwrap(); 7 | 8 | frontend 9 | .bind("tcp://*:5559") 10 | .expect("failed binding frontend"); 11 | backend 12 | .bind("tcp://*:5560") 13 | .expect("failed binding backend"); 14 | 15 | loop { 16 | let mut items = [ 17 | frontend.as_poll_item(zmq::POLLIN), 18 | backend.as_poll_item(zmq::POLLIN), 19 | ]; 20 | zmq::poll(&mut items, -1).unwrap(); 21 | 22 | if items[0].is_readable() { 23 | loop { 24 | let message = frontend.recv_msg(0).unwrap(); 25 | let more = message.get_more(); 26 | backend 27 | .send(message, if more { zmq::SNDMORE } else { 0 }) 28 | .unwrap(); 29 | if !more { 30 | break; 31 | } 32 | } 33 | } 34 | if items[1].is_readable() { 35 | loop { 36 | let message = backend.recv_msg(0).unwrap(); 37 | let more = message.get_more(); 38 | frontend 39 | .send(message, if more { zmq::SNDMORE } else { 0 }) 40 | .unwrap(); 41 | if !more { 42 | break; 43 | } 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /examples/zguide/rrclient/main.rs: -------------------------------------------------------------------------------- 1 | #![crate_name = "rrclient"] 2 | 3 | fn main() { 4 | let context = zmq::Context::new(); 5 | let requester = context.socket(zmq::REQ).unwrap(); 6 | requester 7 | .connect("tcp://localhost:5559") 8 | .expect("failed to connect requester"); 9 | for request_nbr in 0..10 { 10 | requester.send("Hello", 0).unwrap(); 11 | let message = requester.recv_msg(0).unwrap(); 12 | println!( 13 | "Received reply {} {}", 14 | request_nbr, 15 | message.as_str().unwrap() 16 | ); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/zguide/rrworker/main.rs: -------------------------------------------------------------------------------- 1 | #![crate_name = "rrworker"] 2 | 3 | use std::thread; 4 | use std::time::Duration; 5 | 6 | fn main() { 7 | let context = zmq::Context::new(); 8 | let responder = context.socket(zmq::REP).unwrap(); 9 | responder 10 | .connect("tcp://localhost:5560") 11 | .expect("failed connecting responder"); 12 | 13 | loop { 14 | let string = responder.recv_string(0).unwrap().unwrap(); 15 | println!("Received request:{}", string); 16 | thread::sleep(Duration::from_millis(1000)); 17 | responder.send("World", 0).unwrap(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/zguide/rtdealer/main.rs: -------------------------------------------------------------------------------- 1 | #![crate_name = "rtdealer"] 2 | 3 | //! Router-to-dealer example 4 | 5 | use rand::Rng; 6 | use std::thread; 7 | use std::time::{Duration, Instant}; 8 | use zmq::SNDMORE; 9 | 10 | // Inefficient but terse base16 encoder 11 | fn hex(bytes: &[u8]) -> String { 12 | bytes 13 | .iter() 14 | .map(|x| format!("{:02x}", x)) 15 | .collect::>() 16 | .join("") 17 | } 18 | 19 | fn worker_task() { 20 | let context = zmq::Context::new(); 21 | let worker = context.socket(zmq::DEALER).unwrap(); 22 | let mut rng = rand::thread_rng(); 23 | let identity: Vec<_> = (0..10).map(|_| rand::random::()).collect(); 24 | worker.set_identity(&identity).unwrap(); 25 | assert!(worker.connect("tcp://localhost:5671").is_ok()); 26 | 27 | let mut total = 0; 28 | loop { 29 | // Tell the broker we're ready for work 30 | worker.send("", SNDMORE).unwrap(); 31 | worker.send("Hi boss!", 0).unwrap(); 32 | 33 | // Get workload from broker, until finished 34 | worker.recv_bytes(0).unwrap(); // envelope delimiter 35 | let workload = worker.recv_string(0).unwrap().unwrap(); 36 | if workload == "Fired!" { 37 | println!("Worker {} completed {} tasks", hex(&identity), total); 38 | break; 39 | } 40 | total += 1; 41 | 42 | // Do some random work 43 | thread::sleep(Duration::from_millis(rng.gen_range(1..500))); 44 | } 45 | } 46 | 47 | fn main() { 48 | let worker_pool_size = 10; 49 | let allowed_duration = Duration::new(5, 0); 50 | let context = zmq::Context::new(); 51 | let broker = context.socket(zmq::ROUTER).unwrap(); 52 | assert!(broker.bind("tcp://*:5671").is_ok()); 53 | 54 | // While this example runs in a single process, that is just to make 55 | // it easier to start and stop the example. Each thread has its own 56 | // context and conceptually acts as a separate process. 57 | let mut thread_pool = Vec::new(); 58 | for _ in 0..worker_pool_size { 59 | let child = thread::spawn(move || { 60 | worker_task(); 61 | }); 62 | thread_pool.push(child); 63 | } 64 | 65 | // Run for five seconds and then tell workers to end 66 | let start_time = Instant::now(); 67 | let mut workers_fired = 0; 68 | loop { 69 | // Next message gives us least recently used worker 70 | let identity = broker.recv_bytes(0).unwrap(); 71 | broker.send(&identity, SNDMORE).unwrap(); 72 | 73 | broker.recv_bytes(0).unwrap(); // Envelope 74 | broker.recv_bytes(0).unwrap(); // Response from worker 75 | broker.send("", SNDMORE).unwrap(); 76 | 77 | // Encourage workers until it's time to fire them 78 | if start_time.elapsed() < allowed_duration { 79 | broker.send("Work harder", 0).unwrap(); 80 | } else { 81 | broker.send("Fired!", 0).unwrap(); 82 | workers_fired += 1; 83 | if workers_fired >= worker_pool_size { 84 | break; 85 | } 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /examples/zguide/rtreq/main.rs: -------------------------------------------------------------------------------- 1 | #![crate_name = "rtreq"] 2 | 3 | //! Router-to-request example 4 | 5 | use rand::Rng; 6 | use std::thread; 7 | use std::time::{Duration, Instant}; 8 | use zmq::SNDMORE; 9 | 10 | // Inefficient but terse base16 encoder 11 | fn hex(bytes: &[u8]) -> String { 12 | bytes 13 | .iter() 14 | .map(|x| format!("{:02x}", x)) 15 | .collect::>() 16 | .join("") 17 | } 18 | 19 | fn worker_task() { 20 | let context = zmq::Context::new(); 21 | let worker = context.socket(zmq::REQ).unwrap(); 22 | let mut rng = rand::thread_rng(); 23 | let identity: Vec<_> = (0..10).map(|_| rand::random::()).collect(); 24 | worker.set_identity(&identity).unwrap(); 25 | assert!(worker.connect("tcp://localhost:5671").is_ok()); 26 | 27 | let mut total = 0; 28 | loop { 29 | // Tell the broker we're ready for work 30 | worker.send("Hi boss!", 0).unwrap(); 31 | 32 | // Get workload from broker, until finished 33 | let workload = worker.recv_string(0).unwrap().unwrap(); 34 | if workload == "Fired!" { 35 | println!("Worker {} completed {} tasks", hex(&identity), total); 36 | break; 37 | } 38 | total += 1; 39 | 40 | // Do some random work 41 | thread::sleep(Duration::from_millis(rng.gen_range(1..500))); 42 | } 43 | } 44 | 45 | fn main() { 46 | let worker_pool_size = 10; 47 | let allowed_duration = Duration::new(5, 0); 48 | let context = zmq::Context::new(); 49 | let broker = context.socket(zmq::ROUTER).unwrap(); 50 | assert!(broker.bind("tcp://*:5671").is_ok()); 51 | 52 | // While this example runs in a single process, that is just to make 53 | // it easier to start and stop the example. Each thread has its own 54 | // context and conceptually acts as a separate process. 55 | let mut thread_pool = Vec::new(); 56 | for _ in 0..worker_pool_size { 57 | let child = thread::spawn(move || { 58 | worker_task(); 59 | }); 60 | thread_pool.push(child); 61 | } 62 | 63 | // Run for five seconds and then tell workers to end 64 | let start_time = Instant::now(); 65 | let mut workers_fired = 0; 66 | loop { 67 | // Next message gives us least recently used worker 68 | let identity = broker.recv_bytes(0).unwrap(); 69 | broker.send(&identity, SNDMORE).unwrap(); 70 | 71 | broker.recv_bytes(0).unwrap(); // Envelope 72 | broker.recv_bytes(0).unwrap(); // Response from worker 73 | broker.send("", SNDMORE).unwrap(); 74 | 75 | // Encourage workers until it's time to fire them 76 | if start_time.elapsed() < allowed_duration { 77 | broker.send("Work harder", 0).unwrap(); 78 | } else { 79 | broker.send("Fired!", 0).unwrap(); 80 | workers_fired += 1; 81 | if workers_fired >= worker_pool_size { 82 | break; 83 | } 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /examples/zguide/syncpub/main.rs: -------------------------------------------------------------------------------- 1 | #![crate_name = "syncpub"] 2 | 3 | fn main() { 4 | let context = zmq::Context::new(); 5 | 6 | //socket to talk to clients 7 | let publisher = context.socket(zmq::PUB).unwrap(); 8 | publisher.set_sndhwm(1_100_000).expect("failed setting hwm"); 9 | publisher 10 | .bind("tcp://*:5561") 11 | .expect("failed binding publisher"); 12 | 13 | //socket to receive signals 14 | let syncservice = context.socket(zmq::REP).unwrap(); 15 | syncservice 16 | .bind("tcp://*:5562") 17 | .expect("failed binding syncservice"); 18 | 19 | //get syncronization from subscribers 20 | println!("Waiting for subscribers"); 21 | for _ in 0..10 { 22 | syncservice.recv_msg(0).expect("failed receiving sync"); 23 | syncservice.send("", 0).expect("failed sending sync"); 24 | } 25 | //now broadcast 1M updates followed by end 26 | println!("Broadcasting messages"); 27 | for _ in 0..1_000_000 { 28 | publisher.send("Rhubarb", 0).expect("failed broadcasting"); 29 | } 30 | publisher.send("END", 0).expect("failed sending end"); 31 | } 32 | -------------------------------------------------------------------------------- /examples/zguide/syncsub/main.rs: -------------------------------------------------------------------------------- 1 | #![crate_name = "syncsub"] 2 | 3 | use std::thread; 4 | use std::time::Duration; 5 | 6 | fn main() { 7 | let context = zmq::Context::new(); 8 | 9 | //first connect our subscriber 10 | let subscriber = context.socket(zmq::SUB).unwrap(); 11 | subscriber 12 | .connect("tcp://localhost:5561") 13 | .expect("failed connecting subscriber"); 14 | subscriber 15 | .set_subscribe(b"") 16 | .expect("failed setting subscription"); 17 | thread::sleep(Duration::from_millis(1)); 18 | 19 | //second sync with publisher 20 | let syncclient = context.socket(zmq::REQ).unwrap(); 21 | syncclient 22 | .connect("tcp://localhost:5562") 23 | .expect("failed connect syncclient"); 24 | syncclient.send("", 0).expect("failed sending sync request"); 25 | syncclient.recv_msg(0).expect("failed receiving sync reply"); 26 | 27 | //third get our updates and report how many we got 28 | let mut update_nbr = 0; 29 | loop { 30 | let message = subscriber 31 | .recv_string(0) 32 | .expect("failed receiving update") 33 | .unwrap(); 34 | if message == "END" { 35 | break; 36 | } 37 | update_nbr += 1; 38 | } 39 | println!("Received {} updates", update_nbr); 40 | } 41 | -------------------------------------------------------------------------------- /examples/zguide/tasksink/main.rs: -------------------------------------------------------------------------------- 1 | #![crate_name = "tasksink"] 2 | 3 | /// Task sink 4 | /// Binds PULL socket to tcp://localhost:5558 5 | /// Collects results from workers via that socket 6 | use std::io::{self, Write}; 7 | use std::time::Instant; 8 | 9 | fn main() { 10 | // Prepare our context and socket 11 | let context = zmq::Context::new(); 12 | let receiver = context.socket(zmq::PULL).unwrap(); 13 | assert!(receiver.bind("tcp://*:5558").is_ok()); 14 | 15 | // Wait for start of batch 16 | receiver.recv_bytes(0).unwrap(); 17 | 18 | // Start our clock now 19 | let start = Instant::now(); 20 | 21 | for task_nbr in 0..100 { 22 | receiver.recv_bytes(0).unwrap(); 23 | 24 | if task_nbr % 10 == 0 { 25 | print!(":"); 26 | } else { 27 | print!("."); 28 | } 29 | let _ = io::stdout().flush(); 30 | } 31 | 32 | println!("\nTotal elapsed time: {:?}", start.elapsed()); 33 | } 34 | -------------------------------------------------------------------------------- /examples/zguide/tasksink2/main.rs: -------------------------------------------------------------------------------- 1 | #![crate_name = "tasksink2"] 2 | 3 | /// Task sink 4 | /// Binds PULL socket to tcp://localhost:5558 5 | /// Collects results from workers via that socket 6 | use std::io::{self, Write}; 7 | use std::time::Instant; 8 | 9 | fn main() { 10 | // Prepare our context and socket 11 | let context = zmq::Context::new(); 12 | let receiver = context.socket(zmq::PULL).unwrap(); 13 | assert!(receiver.bind("tcp://*:5558").is_ok()); 14 | 15 | let controller = context.socket(zmq::PUB).unwrap(); 16 | controller 17 | .bind("tcp://*:5559") 18 | .expect("failed to bind controller"); 19 | 20 | // Wait for start of batch 21 | receiver.recv_bytes(0).unwrap(); 22 | 23 | // Start our clock now 24 | let start = Instant::now(); 25 | 26 | for task_nbr in 0..100 { 27 | receiver.recv_bytes(0).unwrap(); 28 | 29 | if task_nbr % 10 == 0 { 30 | print!(":"); 31 | } else { 32 | print!("."); 33 | } 34 | let _ = io::stdout().flush(); 35 | } 36 | 37 | println!("\nTotal elapsed time: {:?}", start.elapsed()); 38 | //send kill signal 39 | controller 40 | .send("KILL", 0) 41 | .expect("failed to send kill signal"); 42 | } 43 | -------------------------------------------------------------------------------- /examples/zguide/taskvent/main.rs: -------------------------------------------------------------------------------- 1 | #![crate_name = "taskvent"] 2 | 3 | //! Task ventilator 4 | //! Binds PUSH socket to tcp://localhost:5557 5 | //! Sends batch of tasks to workers via that socket 6 | 7 | use rand::Rng; 8 | use std::io::{self, BufRead}; 9 | 10 | fn main() { 11 | let context = zmq::Context::new(); 12 | 13 | // Socket to send messages on 14 | let sender = context.socket(zmq::PUSH).unwrap(); 15 | assert!(sender.bind("tcp://*:5557").is_ok()); 16 | 17 | // Socket to send start of batch message on 18 | let sink = context.socket(zmq::PUSH).unwrap(); 19 | assert!(sink.connect("tcp://localhost:5558").is_ok()); 20 | 21 | println!("Press Enter when the workers are ready: "); 22 | let stdin = io::stdin(); 23 | stdin.lock().lines().next(); 24 | 25 | println!("Sending tasks to workers..."); 26 | // The first message is "0" and signals start of batch 27 | sink.send("0", 0).unwrap(); 28 | 29 | let mut rng = rand::thread_rng(); 30 | 31 | // Send 100 tasks 32 | let mut total_msec: u32 = 0; 33 | for _ in 0..100 { 34 | // Random workload from 1 to 100 msecs 35 | let workload: u32 = rng.gen_range(1..101); 36 | 37 | total_msec += workload; 38 | 39 | let workload_str = format!("{}", workload); 40 | sender.send(&workload_str, 0).unwrap(); 41 | } 42 | 43 | println!("Total expected cost: {} msec", total_msec) 44 | } 45 | -------------------------------------------------------------------------------- /examples/zguide/taskwork/main.rs: -------------------------------------------------------------------------------- 1 | #![crate_name = "taskwork"] 2 | 3 | /// Task worker 4 | /// Connects PULL socket to tcp://localhost:5557 5 | /// Collects workloads from ventilator via that socket 6 | /// Connects PUSH socket to tcp://localhost:5558 7 | /// Sends results to sink via that socket 8 | use std::io::{self, Write}; 9 | use std::thread; 10 | use std::time::Duration; 11 | 12 | fn atoi(s: &str) -> u64 { 13 | s.parse().unwrap() 14 | } 15 | 16 | fn main() { 17 | let context = zmq::Context::new(); 18 | 19 | // socket to receive messages on 20 | let receiver = context.socket(zmq::PULL).unwrap(); 21 | assert!(receiver.connect("tcp://localhost:5557").is_ok()); 22 | 23 | // Socket to send messages to 24 | let sender = context.socket(zmq::PUSH).unwrap(); 25 | assert!(sender.connect("tcp://localhost:5558").is_ok()); 26 | 27 | loop { 28 | let string = receiver.recv_string(0).unwrap().unwrap(); 29 | 30 | // Show progress 31 | print!("."); 32 | let _ = io::stdout().flush(); 33 | 34 | // Do the work 35 | thread::sleep(Duration::from_millis(atoi(&string))); 36 | 37 | // Send results to sink 38 | sender.send("", 0).unwrap(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /examples/zguide/taskwork2/main.rs: -------------------------------------------------------------------------------- 1 | #![crate_name = "taskwork2"] 2 | 3 | /// Task worker 4 | /// Connects PULL socket to tcp://localhost:5557 5 | /// Collects workloads from ventilator via that socket 6 | /// Connects PUSH socket to tcp://localhost:5558 7 | /// Sends results to sink via that socket 8 | use std::io::{self, Write}; 9 | use std::thread; 10 | use std::time::Duration; 11 | 12 | fn atoi(s: &str) -> u64 { 13 | s.parse().unwrap() 14 | } 15 | 16 | fn main() { 17 | let context = zmq::Context::new(); 18 | 19 | // socket to receive messages on 20 | let receiver = context.socket(zmq::PULL).unwrap(); 21 | assert!(receiver.connect("tcp://localhost:5557").is_ok()); 22 | 23 | // Socket to send messages to 24 | let sender = context.socket(zmq::PUSH).unwrap(); 25 | assert!(sender.connect("tcp://localhost:5558").is_ok()); 26 | 27 | let controller = context.socket(zmq::SUB).unwrap(); 28 | controller 29 | .connect("tcp://localhost:5559") 30 | .expect("failed connecting controller"); 31 | controller.set_subscribe(b"").expect("failed subscribing"); 32 | 33 | loop { 34 | let mut items = [ 35 | receiver.as_poll_item(zmq::POLLIN), 36 | controller.as_poll_item(zmq::POLLIN), 37 | ]; 38 | zmq::poll(&mut items, -1).expect("failed polling"); 39 | if items[0].is_readable() { 40 | let string = receiver.recv_string(0).unwrap().unwrap(); 41 | 42 | // Show progress 43 | print!("."); 44 | let _ = io::stdout().flush(); 45 | 46 | // Do the work 47 | thread::sleep(Duration::from_millis(atoi(&string))); 48 | 49 | // Send results to sink 50 | sender.send("", 0).unwrap(); 51 | } 52 | if items[1].is_readable() { 53 | break; 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /examples/zguide/version/main.rs: -------------------------------------------------------------------------------- 1 | #![crate_name = "version"] 2 | 3 | fn main() { 4 | let (major, minor, patch) = zmq::version(); 5 | println!("Current 0MQ version is {}.{}.{}", major, minor, patch); 6 | } 7 | -------------------------------------------------------------------------------- /examples/zguide/weather_client/main.rs: -------------------------------------------------------------------------------- 1 | #![crate_name = "weather_client"] 2 | 3 | /*! 4 | * Weather update client 5 | * Connects SUB socket to tcp://localhost:5556 6 | * Collects weather updates and find avg temp in zipcode 7 | */ 8 | 9 | use std::env; 10 | 11 | fn atoi(s: &str) -> i64 { 12 | s.parse().unwrap() 13 | } 14 | 15 | fn main() { 16 | println!("Collecting updates from weather server..."); 17 | 18 | let context = zmq::Context::new(); 19 | let subscriber = context.socket(zmq::SUB).unwrap(); 20 | assert!(subscriber.connect("tcp://localhost:5556").is_ok()); 21 | 22 | let args: Vec = env::args().collect(); 23 | let filter = if args.len() > 1 { &args[1] } else { "10001" }; 24 | assert!(subscriber.set_subscribe(filter.as_bytes()).is_ok()); 25 | 26 | let mut total_temp = 0; 27 | 28 | for _ in 0..100 { 29 | let string = subscriber.recv_string(0).unwrap().unwrap(); 30 | let chks: Vec = string.split(' ').map(atoi).collect(); 31 | let (_zipcode, temperature, _relhumidity) = (chks[0], chks[1], chks[2]); 32 | total_temp += temperature; 33 | } 34 | 35 | println!( 36 | "Average temperature for zipcode '{}' was {}F", 37 | filter, 38 | (total_temp / 100) 39 | ); 40 | } 41 | -------------------------------------------------------------------------------- /examples/zguide/weather_server/main.rs: -------------------------------------------------------------------------------- 1 | #![crate_name = "weather_server"] 2 | 3 | //! Weather update server 4 | //! Binds PUB socket to tcp://*:5556 and ipc://weather.ipc 5 | //! Publishes random weather updates 6 | 7 | use rand::Rng; 8 | 9 | fn main() { 10 | let context = zmq::Context::new(); 11 | let publisher = context.socket(zmq::PUB).unwrap(); 12 | 13 | assert!(publisher.bind("tcp://*:5556").is_ok()); 14 | assert!(publisher.bind("ipc://weather.ipc").is_ok()); 15 | 16 | let mut rng = rand::thread_rng(); 17 | 18 | loop { 19 | let zipcode = rng.gen_range(0..100_000); 20 | let temperature = rng.gen_range(-80..135); 21 | let relhumidity = rng.gen_range(10..60); 22 | 23 | // this is slower than C because the current format! implementation is 24 | // very, very slow. Several orders of magnitude slower than glibc's 25 | // sprintf 26 | let update = format!("{:05} {} {}", zipcode, temperature, relhumidity); 27 | publisher.send(&update, 0).unwrap(); 28 | } 29 | 30 | // note: destructors mean no explicit cleanup necessary 31 | } 32 | -------------------------------------------------------------------------------- /examples/zguide/wuproxy/main.rs: -------------------------------------------------------------------------------- 1 | #![crate_name = "wuproxy"] 2 | 3 | fn main() { 4 | let context = zmq::Context::new(); 5 | let frontend = context.socket(zmq::XSUB).unwrap(); 6 | let backend = context.socket(zmq::XPUB).unwrap(); 7 | 8 | frontend 9 | .connect("tcp://192.168.55.210:5556") 10 | .expect("failed connecting frontend"); 11 | backend 12 | .bind("tcp://10.1.1.0:8100") 13 | .expect("failed binding backend"); 14 | zmq::proxy(&frontend, &backend).expect("failed proxying"); 15 | } 16 | -------------------------------------------------------------------------------- /msrv-test/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "msrv-test" 3 | version = "0.0.1" 4 | authors = ["Andreas Rottmann "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | zmq = { path = ".." } 9 | -------------------------------------------------------------------------------- /msrv-test/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let ctx = zmq::Context::new(); 3 | 4 | let socket = ctx.socket(zmq::REQ).unwrap(); 5 | socket.connect("tcp://127.0.0.1:1234").unwrap(); 6 | socket.send("hello world!", 0).unwrap(); 7 | } 8 | -------------------------------------------------------------------------------- /src/message.rs: -------------------------------------------------------------------------------- 1 | use libc::size_t; 2 | 3 | use std::ffi; 4 | use std::fmt; 5 | use std::ops::{Deref, DerefMut}; 6 | use std::os::raw::c_void; 7 | use std::{ptr, slice, str}; 8 | 9 | use super::errno_to_error; 10 | 11 | /// Holds a 0MQ message. 12 | /// 13 | /// A message is a single frame, either received or created locally and then 14 | /// sent over the wire. Multipart messages are transmitted as multiple 15 | /// `Message`s. 16 | /// 17 | /// In rust-zmq, you aren't required to create message objects if you use the 18 | /// convenience APIs provided (e.g. `Socket::recv_bytes()` or 19 | /// `Socket::send()`). However, using message objects can make multiple 20 | /// operations in a loop more efficient, since allocated memory can be reused. 21 | pub struct Message { 22 | msg: zmq_sys::zmq_msg_t, 23 | } 24 | 25 | impl Drop for Message { 26 | fn drop(&mut self) { 27 | unsafe { 28 | let rc = zmq_sys::zmq_msg_close(&mut self.msg); 29 | assert_eq!(rc, 0); 30 | } 31 | } 32 | } 33 | 34 | impl fmt::Debug for Message { 35 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 36 | write!(f, "{:?}", self.deref()) 37 | } 38 | } 39 | 40 | unsafe extern "C" fn drop_msg_data_box(data: *mut c_void, hint: *mut c_void) { 41 | let _ = Box::from_raw(slice::from_raw_parts_mut(data as *mut u8, hint as usize)); 42 | } 43 | 44 | impl Message { 45 | unsafe fn alloc(f: F) -> Message 46 | where 47 | F: FnOnce(&mut zmq_sys::zmq_msg_t) -> i32, 48 | { 49 | let mut msg = zmq_sys::zmq_msg_t::default(); 50 | let rc = f(&mut msg); 51 | if rc == -1 { 52 | panic!("{}", errno_to_error()) 53 | } 54 | Message { msg } 55 | } 56 | 57 | /// Create an empty `Message`. 58 | pub fn new() -> Message { 59 | unsafe { Self::alloc(|msg| zmq_sys::zmq_msg_init(msg)) } 60 | } 61 | 62 | /// Create a `Message` from an initialized `zmq_sys::zmq_msg_t`. 63 | /// 64 | /// # Safety 65 | /// 66 | /// `msg` must be initialized. 67 | pub unsafe fn from_msg(msg: zmq_sys::zmq_msg_t) -> Self { 68 | Message { msg } 69 | } 70 | 71 | /// Create a `Message` preallocated with `len` uninitialized bytes. 72 | /// 73 | /// Since it is very easy to introduce undefined behavior using this 74 | /// function, its use is not recommended, and it will be removed in a future 75 | /// release. If there is a use-case that cannot be handled efficiently by 76 | /// the safe message constructors, please file an issue. 77 | /// 78 | /// # Safety 79 | /// 80 | /// The returned message contains uninitialized memory, and hence the 81 | /// `Deref` and `DerefMut` traits must not be used until the memory has been 82 | /// initialized. Since there is no proper API to do so, this function is 83 | /// basically not usable safely, unless you happen to invoke C code that 84 | /// takes a raw message pointer and initializes its contents. 85 | #[deprecated( 86 | since = "0.9.1", 87 | note = "This method has an unintuitive name, and should not be needed." 88 | )] 89 | pub unsafe fn with_capacity_unallocated(len: usize) -> Message { 90 | Self::alloc(|msg| zmq_sys::zmq_msg_init_size(msg, len as size_t)) 91 | } 92 | 93 | unsafe fn with_size_uninit(len: usize) -> Message { 94 | Self::alloc(|msg| zmq_sys::zmq_msg_init_size(msg, len as size_t)) 95 | } 96 | 97 | /// Create a `Message` with space for `len` bytes that are initialized to 0. 98 | pub fn with_size(len: usize) -> Message { 99 | unsafe { 100 | let mut msg = Message::with_size_uninit(len); 101 | ptr::write_bytes(msg.as_mut_ptr(), 0, len); 102 | msg 103 | } 104 | } 105 | 106 | /// Create a `Message` with space for `len` bytes that are initialized to 0. 107 | #[deprecated( 108 | since = "0.9.1", 109 | note = "This method has a name which does not match its semantics. Use `with_size` instead" 110 | )] 111 | pub fn with_capacity(len: usize) -> Message { 112 | Self::with_size(len) 113 | } 114 | 115 | /// Create a `Message` from a `&[u8]`. This will copy `data` into the message. 116 | /// 117 | /// This is equivalent to using the `From<&[u8]>` trait. 118 | #[deprecated(since = "0.9.1", note = "Use the `From` trait instead.")] 119 | pub fn from_slice(data: &[u8]) -> Message { 120 | Self::from(data) 121 | } 122 | 123 | /// Return the message content as a string slice if it is valid UTF-8. 124 | pub fn as_str(&self) -> Option<&str> { 125 | str::from_utf8(self).ok() 126 | } 127 | 128 | /// Return the `ZMQ_MORE` flag, which indicates if more parts of a multipart 129 | /// message will follow. 130 | pub fn get_more(&self) -> bool { 131 | let rc = unsafe { zmq_sys::zmq_msg_more(&self.msg) }; 132 | rc != 0 133 | } 134 | 135 | /// Query a message metadata property. 136 | /// 137 | /// # Non-UTF8 values 138 | /// 139 | /// The `zmq_msg_gets` man page notes "The encoding of the property and 140 | /// value shall be UTF8". However, this is not actually enforced. For API 141 | /// compatibility reasons, this function will return `None` when 142 | /// encountering a non-UTF8 value; so a missing and a non-UTF8 value cannot 143 | /// currently be distinguished. 144 | /// 145 | /// This is considered a bug in the bindings, and will be fixed with the 146 | /// next API-breaking release. 147 | pub fn gets<'a>(&'a mut self, property: &str) -> Option<&'a str> { 148 | let c_str = ffi::CString::new(property.as_bytes()).unwrap(); 149 | 150 | let value = unsafe { zmq_sys::zmq_msg_gets(&self.msg, c_str.as_ptr()) }; 151 | 152 | if value.is_null() { 153 | None 154 | } else { 155 | str::from_utf8(unsafe { ffi::CStr::from_ptr(value) }.to_bytes()).ok() 156 | } 157 | } 158 | } 159 | 160 | impl Deref for Message { 161 | type Target = [u8]; 162 | 163 | fn deref(&self) -> &[u8] { 164 | // This is safe because we're constraining the slice to the lifetime of 165 | // this message. 166 | unsafe { 167 | let ptr = &self.msg as *const _ as *mut _; 168 | let data = zmq_sys::zmq_msg_data(ptr); 169 | let len = zmq_sys::zmq_msg_size(ptr) as usize; 170 | slice::from_raw_parts(data as *mut u8, len) 171 | } 172 | } 173 | } 174 | 175 | impl PartialEq for Message { 176 | fn eq(&self, other: &Message) -> bool { 177 | self[..] == other[..] 178 | } 179 | } 180 | 181 | impl Eq for Message {} 182 | 183 | impl DerefMut for Message { 184 | fn deref_mut(&mut self) -> &mut [u8] { 185 | // This is safe because we're constraining the slice to the lifetime of 186 | // this message. 187 | unsafe { 188 | let data = zmq_sys::zmq_msg_data(&mut self.msg); 189 | let len = zmq_sys::zmq_msg_size(&self.msg) as usize; 190 | slice::from_raw_parts_mut(data as *mut u8, len) 191 | } 192 | } 193 | } 194 | 195 | impl AsRef<[u8]> for Message { 196 | fn as_ref(&self) -> &[u8] { 197 | self.deref() 198 | } 199 | } 200 | 201 | impl AsMut<[u8]> for Message { 202 | fn as_mut(&mut self) -> &mut [u8] { 203 | self.deref_mut() 204 | } 205 | } 206 | 207 | impl<'a> From<&'a [u8]> for Message { 208 | /// Construct a message from a byte slice by copying the data. 209 | fn from(data: &'a [u8]) -> Self { 210 | unsafe { 211 | let mut msg = Message::with_size_uninit(data.len()); 212 | ptr::copy_nonoverlapping(data.as_ptr(), msg.as_mut_ptr(), data.len()); 213 | msg 214 | } 215 | } 216 | } 217 | 218 | impl From> for Message { 219 | /// Construct a message from a byte vector without copying the data. 220 | fn from(msg: Vec) -> Self { 221 | Message::from(msg.into_boxed_slice()) 222 | } 223 | } 224 | 225 | impl From> for Message { 226 | /// Construct a message from a boxed slice without copying the data. 227 | fn from(data: Box<[u8]>) -> Self { 228 | let len = data.len(); 229 | if len == 0 { 230 | return Message::new(); 231 | } 232 | let raw = Box::into_raw(data); 233 | unsafe { 234 | Self::alloc(|msg| { 235 | zmq_sys::zmq_msg_init_data( 236 | msg, 237 | raw as *mut c_void, 238 | len, 239 | Some(drop_msg_data_box), 240 | len as *mut c_void, 241 | ) 242 | }) 243 | } 244 | } 245 | } 246 | 247 | impl From<&str> for Message { 248 | /// Construct a message from a string slice by copying the UTF-8 data. 249 | fn from(msg: &str) -> Self { 250 | Message::from(msg.as_bytes()) 251 | } 252 | } 253 | 254 | impl From<&String> for Message { 255 | /// Construct a message from a string slice by copying the UTF-8 data. 256 | fn from(msg: &String) -> Self { 257 | Message::from(msg.as_bytes()) 258 | } 259 | } 260 | 261 | impl<'a, T> From<&'a T> for Message 262 | where 263 | T: Into + Clone, 264 | { 265 | fn from(v: &'a T) -> Self { 266 | v.clone().into() 267 | } 268 | } 269 | 270 | /// Get the low-level C pointer. 271 | pub fn msg_ptr(msg: &mut Message) -> *mut zmq_sys::zmq_msg_t { 272 | &mut msg.msg 273 | } 274 | -------------------------------------------------------------------------------- /src/sockopt.rs: -------------------------------------------------------------------------------- 1 | use libc::{c_int, c_uint, size_t}; 2 | use std::os::raw::c_void; 3 | use std::result; 4 | use std::string::FromUtf8Error; 5 | use std::{mem, ptr, str}; 6 | 7 | use super::{PollEvents, Result}; 8 | 9 | pub trait Getter 10 | where 11 | Self: Sized, 12 | { 13 | fn get(sock: *mut c_void, opt: c_int) -> Result; 14 | } 15 | 16 | pub trait Setter 17 | where 18 | Self: Sized, 19 | { 20 | fn set(sock: *mut c_void, opt: c_int, value: Self) -> Result<()>; 21 | } 22 | 23 | macro_rules! getsockopt_num( 24 | ($c_ty:ty, $ty:ty) => ( 25 | impl Getter for $ty { 26 | #[allow(trivial_casts)] 27 | fn get(sock: *mut c_void, opt: c_int) -> Result<$ty> { 28 | let mut value: $c_ty = 0; 29 | let value_ptr = &mut value as *mut $c_ty; 30 | let mut size = mem::size_of::<$c_ty>() as size_t; 31 | 32 | zmq_try!(unsafe { 33 | zmq_sys::zmq_getsockopt( 34 | sock, 35 | opt, 36 | value_ptr as *mut c_void, 37 | &mut size) 38 | }); 39 | Ok(value as $ty) 40 | } 41 | } 42 | ) 43 | ); 44 | 45 | getsockopt_num!(c_int, i32); 46 | getsockopt_num!(c_uint, u32); 47 | getsockopt_num!(i64, i64); 48 | getsockopt_num!(u64, u64); 49 | 50 | pub fn get_bytes(sock: *mut c_void, opt: c_int, size: size_t) -> Result> { 51 | let mut size = size; 52 | let mut value = vec![0u8; size]; 53 | 54 | zmq_try!(unsafe { 55 | zmq_sys::zmq_getsockopt(sock, opt, value.as_mut_ptr() as *mut c_void, &mut size) 56 | }); 57 | value.truncate(size); 58 | Ok(value) 59 | } 60 | 61 | pub fn get_string( 62 | sock: *mut c_void, 63 | opt: c_int, 64 | size: size_t, 65 | remove_nulbyte: bool, 66 | ) -> Result>> { 67 | let mut value = get_bytes(sock, opt, size)?; 68 | 69 | if remove_nulbyte { 70 | value.pop(); 71 | } 72 | Ok(String::from_utf8(value).map_err(FromUtf8Error::into_bytes)) 73 | } 74 | 75 | macro_rules! setsockopt_num( 76 | ($ty:ty) => ( 77 | impl Setter for $ty { 78 | #[allow(trivial_casts)] 79 | fn set(sock: *mut c_void, opt: c_int, value: $ty) -> Result<()> { 80 | let size = mem::size_of::<$ty>() as size_t; 81 | 82 | zmq_try!(unsafe { 83 | zmq_sys::zmq_setsockopt( 84 | sock, 85 | opt, 86 | (&value as *const $ty) as *const c_void, 87 | size) 88 | }); 89 | Ok(()) 90 | } 91 | } 92 | ) 93 | ); 94 | 95 | setsockopt_num!(i32); 96 | setsockopt_num!(i64); 97 | setsockopt_num!(u64); 98 | 99 | fn setsockopt_null(sock: *mut c_void, opt: c_int) -> Result<()> { 100 | zmq_try!(unsafe { zmq_sys::zmq_setsockopt(sock, opt, ptr::null(), 0) }); 101 | Ok(()) 102 | } 103 | 104 | impl Setter for &str { 105 | fn set(sock: *mut c_void, opt: c_int, value: Self) -> Result<()> { 106 | set(sock, opt, value.as_bytes()) 107 | } 108 | } 109 | 110 | impl Setter for Option<&str> { 111 | fn set(sock: *mut c_void, opt: c_int, value: Self) -> Result<()> { 112 | if let Some(s) = value { 113 | set(sock, opt, s.as_bytes()) 114 | } else { 115 | setsockopt_null(sock, opt) 116 | } 117 | } 118 | } 119 | 120 | impl Getter for bool { 121 | fn get(sock: *mut c_void, opt: c_int) -> Result { 122 | let result: i32 = get(sock, opt)?; 123 | Ok(result == 1) 124 | } 125 | } 126 | 127 | impl Setter for bool { 128 | fn set(sock: *mut c_void, opt: c_int, value: Self) -> Result<()> { 129 | set(sock, opt, if value { 1i32 } else { 0i32 }) 130 | } 131 | } 132 | 133 | impl<'a> Setter for &'a [u8] { 134 | fn set(sock: *mut c_void, opt: c_int, value: &'a [u8]) -> Result<()> { 135 | zmq_try!(unsafe { 136 | zmq_sys::zmq_setsockopt( 137 | sock, 138 | opt, 139 | value.as_ptr() as *const c_void, 140 | value.len() as size_t, 141 | ) 142 | }); 143 | Ok(()) 144 | } 145 | } 146 | 147 | impl Getter for PollEvents { 148 | fn get(sock: *mut c_void, opt: c_int) -> Result { 149 | get::(sock, opt).map(|bits| PollEvents::from_bits_truncate(bits as i16)) 150 | } 151 | } 152 | 153 | pub fn get(sock: *mut c_void, opt: c_int) -> Result { 154 | T::get(sock, opt) 155 | } 156 | 157 | pub fn set(sock: *mut c_void, opt: c_int, value: T) -> Result<()> { 158 | T::set(sock, opt, value) 159 | } 160 | -------------------------------------------------------------------------------- /tests/common/mod.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | pub extern crate timebomb; 4 | 5 | use std::sync::Once; 6 | 7 | static LOGGER_INIT: Once = Once::new(); 8 | 9 | #[macro_export] 10 | macro_rules! test { 11 | ($name:ident, $block:block) => { 12 | #[test] 13 | fn $name() { 14 | $crate::common::ensure_env_logger_initialized(); 15 | $crate::common::timebomb::timeout_ms(|| $block, 10000); 16 | } 17 | }; 18 | } 19 | 20 | #[macro_export] 21 | macro_rules! test_capability { 22 | ($name:ident, $capability:literal, $block:block) => { 23 | #[test] 24 | fn $name() { 25 | if zmq::has($capability).unwrap() { 26 | $crate::common::ensure_env_logger_initialized(); 27 | $crate::common::timebomb::timeout_ms(|| $block, 10000); 28 | } 29 | } 30 | }; 31 | } 32 | 33 | pub fn ensure_env_logger_initialized() { 34 | LOGGER_INIT.call_once(env_logger::init); 35 | } 36 | -------------------------------------------------------------------------------- /tests/compile-fail/no-leaking-poll-items.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let context = zmq::Context::new(); 3 | let _poll_item = { 4 | let socket = context.socket(zmq::PAIR).unwrap(); 5 | socket.as_poll_item(zmq::POLLIN) 6 | }; //~^ ERROR `socket` does not live long enough [E0597] 7 | } 8 | -------------------------------------------------------------------------------- /tests/compile-fail/no-leaking-poll-items.stderr: -------------------------------------------------------------------------------- 1 | error[E0597]: `socket` does not live long enough 2 | --> tests/compile-fail/no-leaking-poll-items.rs:5:9 3 | | 4 | 3 | let _poll_item = { 5 | | ---------- borrow later stored here 6 | 4 | let socket = context.socket(zmq::PAIR).unwrap(); 7 | | ------ binding `socket` declared here 8 | 5 | socket.as_poll_item(zmq::POLLIN) 9 | | ^^^^^^ borrowed value does not live long enough 10 | 6 | }; //~^ ERROR `socket` does not live long enough [E0597] 11 | | - `socket` dropped here while still borrowed 12 | -------------------------------------------------------------------------------- /tests/compile-fail/socket-thread-unsafe.rs: -------------------------------------------------------------------------------- 1 | use std::thread; 2 | 3 | macro_rules! t { 4 | ($e:expr) => ( 5 | $e.unwrap_or_else(|e| { panic!("{} failed with {:?}", stringify!($e), e) }) 6 | ) 7 | } 8 | 9 | fn main() { 10 | let mut context = zmq::Context::new(); 11 | let socket = t!(context.socket(zmq::REP)); 12 | let s = &socket; 13 | let t = thread::spawn(move || { 14 | t!(s.bind("tcp://127.0.0.1:12345")) 15 | }); 16 | socket.send("ABC", 0); 17 | t.join().unwrap(); 18 | } 19 | -------------------------------------------------------------------------------- /tests/compile-fail/socket-thread-unsafe.stderr: -------------------------------------------------------------------------------- 1 | error[E0277]: `*mut c_void` cannot be shared between threads safely 2 | --> tests/compile-fail/socket-thread-unsafe.rs:13:27 3 | | 4 | 13 | let t = thread::spawn(move || { 5 | | _____________-------------_^ 6 | | | | 7 | | | required by a bound introduced by this call 8 | 14 | | t!(s.bind("tcp://127.0.0.1:12345")) 9 | 15 | | }); 10 | | |_____^ `*mut c_void` cannot be shared between threads safely 11 | | 12 | = help: within `Socket`, the trait `Sync` is not implemented for `*mut c_void`, which is required by `{closure@$DIR/tests/compile-fail/socket-thread-unsafe.rs:13:27: 13:34}: Send` 13 | note: required because it appears within the type `Socket` 14 | --> src/lib.rs 15 | | 16 | | pub struct Socket { 17 | | ^^^^^^ 18 | = note: required for `&Socket` to implement `Send` 19 | note: required because it's used within this closure 20 | --> tests/compile-fail/socket-thread-unsafe.rs:13:27 21 | | 22 | 13 | let t = thread::spawn(move || { 23 | | ^^^^^^^ 24 | note: required by a bound in `spawn` 25 | --> $RUST/std/src/thread/mod.rs 26 | -------------------------------------------------------------------------------- /tests/compile-tests.rs: -------------------------------------------------------------------------------- 1 | #[test] 2 | fn compile_fail() { 3 | let t = trybuild::TestCases::new(); 4 | t.compile_fail("tests/compile-fail/*.rs"); 5 | } 6 | -------------------------------------------------------------------------------- /tests/connection.rs: -------------------------------------------------------------------------------- 1 | //! These are all tests using PUSH/PULL sockets created from a shared 2 | //! context to connect two threads. As a compile-time test, this 3 | //! creates one socket from a context, and passes this context to the 4 | //! child thread, along with the endpoint address to connect to. The 5 | //! second socket is the created in the child thread. 6 | 7 | #[macro_use] 8 | mod common; 9 | 10 | #[cfg(unix)] 11 | #[path = "unix/connection.rs"] 12 | mod unix; 13 | 14 | use std::str; 15 | use std::thread; 16 | 17 | test!(test_inproc, { 18 | with_connection( 19 | "inproc://pub", 20 | zmq::PUSH, 21 | send_message, 22 | zmq::PULL, 23 | check_recv, 24 | ); 25 | }); 26 | 27 | test!(test_tcp, { 28 | with_connection( 29 | "tcp://127.0.0.1:*", 30 | zmq::PUSH, 31 | send_message, 32 | zmq::PULL, 33 | check_recv, 34 | ); 35 | }); 36 | 37 | test!(test_poll_inproc, { 38 | with_connection( 39 | "inproc://pub", 40 | zmq::PUSH, 41 | send_message, 42 | zmq::PULL, 43 | check_poll, 44 | ); 45 | }); 46 | 47 | test!(test_poll_tcp, { 48 | with_connection( 49 | "tcp://127.0.0.1:*", 50 | zmq::PUSH, 51 | send_message, 52 | zmq::PULL, 53 | check_poll, 54 | ); 55 | }); 56 | 57 | fn send_message(_ctx: &zmq::Context, socket: &zmq::Socket) { 58 | socket.send("Message1", 0).unwrap(); 59 | } 60 | 61 | fn check_poll(_ctx: &zmq::Context, pull_socket: &zmq::Socket) { 62 | { 63 | let mut poll_items = vec![pull_socket.as_poll_item(zmq::POLLIN)]; 64 | assert_eq!(zmq::poll(&mut poll_items, 1000).unwrap(), 1); 65 | assert_eq!(poll_items[0].get_revents(), zmq::POLLIN); 66 | } 67 | 68 | let msg = pull_socket.recv_msg(zmq::DONTWAIT).unwrap(); 69 | assert_eq!(&msg[..], b"Message1"); 70 | } 71 | 72 | fn check_recv(_ctx: &zmq::Context, pull_socket: &zmq::Socket) { 73 | let msg = pull_socket.recv_msg(0).unwrap(); 74 | assert_eq!(&msg[..], b"Message1"); 75 | } 76 | 77 | // 78 | // Utilities 79 | // 80 | 81 | pub fn with_connection( 82 | address: &str, 83 | parent_type: zmq::SocketType, 84 | parent: F, 85 | child_type: zmq::SocketType, 86 | child: G, 87 | ) where 88 | F: for<'r> Fn(&'r zmq::Context, &zmq::Socket) + Send + 'static, 89 | G: for<'r> Fn(&'r zmq::Context, &zmq::Socket) + Send + 'static, 90 | { 91 | let ctx = zmq::Context::new(); 92 | 93 | let push_socket = ctx.socket(parent_type).unwrap(); 94 | push_socket.bind(address).unwrap(); 95 | let endpoint = push_socket.get_last_endpoint().unwrap().unwrap(); 96 | 97 | let thread = { 98 | let w_ctx = ctx.clone(); 99 | thread::spawn(move || { 100 | let pull_socket = connect_socket(&w_ctx, child_type, &endpoint).unwrap(); 101 | child(&w_ctx, &pull_socket); 102 | }) 103 | }; 104 | 105 | parent(&ctx, &push_socket); 106 | 107 | thread.join().unwrap(); 108 | } 109 | 110 | fn connect_socket( 111 | ctx: &zmq::Context, 112 | typ: zmq::SocketType, 113 | address: &str, 114 | ) -> Result { 115 | ctx.socket(typ) 116 | .and_then(|socket| socket.connect(address).map(|_| socket)) 117 | } 118 | -------------------------------------------------------------------------------- /tests/context.rs: -------------------------------------------------------------------------------- 1 | #[test] 2 | fn context_io_threads() { 3 | let ctx = zmq::Context::new(); 4 | 5 | assert_eq!( 6 | ctx.get_io_threads().unwrap(), 7 | zmq_sys::ZMQ_IO_THREADS_DFLT as i32 8 | ); 9 | 10 | ctx.set_io_threads(0).unwrap(); 11 | assert_eq!(ctx.get_io_threads().unwrap(), 0); 12 | 13 | ctx.set_io_threads(7).unwrap(); 14 | assert_eq!(ctx.get_io_threads().unwrap(), 7); 15 | 16 | assert!(ctx.set_io_threads(-1).is_err()); 17 | } 18 | -------------------------------------------------------------------------------- /tests/curve.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | mod common; 3 | 4 | use zmq::{z85_decode, Context, CurveKeyPair, Socket}; 5 | 6 | fn create_socketpair() -> (Socket, Socket) { 7 | let ctx = Context::default(); 8 | let sender = ctx.socket(zmq::REQ).unwrap(); 9 | let receiver = ctx.socket(zmq::REP).unwrap(); 10 | let server_pair = CurveKeyPair::new().unwrap(); 11 | let client_pair = CurveKeyPair::new().unwrap(); 12 | 13 | // receiver socket acts as server, will accept connections 14 | receiver.set_curve_server(true).unwrap(); 15 | receiver 16 | .set_curve_secretkey(&server_pair.secret_key) 17 | .unwrap(); 18 | 19 | // sender socket, acts as client 20 | sender.set_curve_serverkey(&server_pair.public_key).unwrap(); 21 | sender.set_curve_publickey(&client_pair.public_key).unwrap(); 22 | sender.set_curve_secretkey(&client_pair.secret_key).unwrap(); 23 | 24 | receiver.bind("tcp://127.0.0.1:*").unwrap(); 25 | let ep = receiver.get_last_endpoint().unwrap().unwrap(); 26 | sender.connect(&ep).unwrap(); 27 | (sender, receiver) 28 | } 29 | 30 | test_capability!(test_curve_messages, "curve", { 31 | let (sender, receiver) = create_socketpair(); 32 | sender.send("foo", 0).unwrap(); 33 | let msg = receiver.recv_msg(0).unwrap(); 34 | assert_eq!(&msg[..], b"foo"); 35 | assert_eq!(msg.as_str(), Some("foo")); 36 | println!("this is it {0}", msg.as_str().unwrap()); 37 | assert_eq!(format!("{:?}", msg), "[102, 111, 111]"); 38 | receiver.send("bar", 0).unwrap(); 39 | let msg = sender.recv_msg(0).unwrap(); 40 | assert_eq!(&msg[..], b"bar"); 41 | }); 42 | 43 | test_capability!(test_curve_keypair, "curve", { 44 | let keypair = CurveKeyPair::new().unwrap(); 45 | assert!(keypair.public_key.len() == 32); 46 | assert!(keypair.secret_key.len() == 32); 47 | }); 48 | 49 | test_capability!(test_getset_curve_server, "curve", { 50 | let ctx = Context::new(); 51 | let sock = ctx.socket(zmq::REQ).unwrap(); 52 | sock.set_curve_server(true).unwrap(); 53 | assert!(sock.is_curve_server().unwrap()); 54 | }); 55 | 56 | test_capability!(test_getset_curve_publickey, "curve", { 57 | let ctx = Context::new(); 58 | let sock = ctx.socket(zmq::REQ).unwrap(); 59 | let key = z85_decode("FX5b8g5ZnOk7$Q}^)Y&?.v3&MIe+]OU7DTKynkUL").unwrap(); 60 | sock.set_curve_publickey(&key).unwrap(); 61 | assert_eq!(sock.get_curve_publickey().unwrap(), key); 62 | }); 63 | 64 | test_capability!(test_getset_curve_secretkey, "curve", { 65 | let ctx = Context::new(); 66 | let sock = ctx.socket(zmq::REQ).unwrap(); 67 | let key = z85_decode("s9N%S3*NKSU$6pUnpBI&K5HBd[]G$Y3yrK?mhdbS").unwrap(); 68 | sock.set_curve_secretkey(&key).unwrap(); 69 | assert_eq!(sock.get_curve_secretkey().unwrap(), key); 70 | }); 71 | 72 | test_capability!(test_getset_curve_serverkey, "curve", { 73 | let ctx = Context::new(); 74 | let sock = ctx.socket(zmq::REQ).unwrap(); 75 | let key = z85_decode("FX5b8g5ZnOk7$Q}^)Y&?.v3&MIe+]OU7DTKynkUL").unwrap(); 76 | sock.set_curve_serverkey(&key).unwrap(); 77 | assert_eq!(sock.get_curve_serverkey().unwrap(), key); 78 | }); 79 | -------------------------------------------------------------------------------- /tests/error.rs: -------------------------------------------------------------------------------- 1 | use zmq::*; 2 | use zmq_sys::errno; 3 | 4 | #[test] 5 | fn from_raw_eintr() { 6 | let error = Error::from_raw(errno::EINTR); 7 | assert_eq!(error, Error::EINTR); 8 | } 9 | -------------------------------------------------------------------------------- /tests/gssapi.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | mod common; 3 | 4 | use zmq::Context; 5 | 6 | test_capability!(test_getset_gssapi_server, "gssapi", { 7 | let ctx = Context::new(); 8 | let sock = ctx.socket(zmq::REQ).unwrap(); 9 | sock.set_gssapi_server(true).unwrap(); 10 | assert!(sock.is_gssapi_server().unwrap()); 11 | }); 12 | 13 | test_capability!(test_getset_gssapi_principal, "gssapi", { 14 | let ctx = Context::new(); 15 | let sock = ctx.socket(zmq::REQ).unwrap(); 16 | sock.set_gssapi_principal("principal").unwrap(); 17 | assert_eq!(sock.get_gssapi_principal().unwrap().unwrap(), "principal"); 18 | }); 19 | 20 | test_capability!(test_getset_gssapi_service_principal, "gssapi", { 21 | let ctx = Context::new(); 22 | let sock = ctx.socket(zmq::REQ).unwrap(); 23 | sock.set_gssapi_service_principal("principal").unwrap(); 24 | assert_eq!( 25 | sock.get_gssapi_service_principal().unwrap().unwrap(), 26 | "principal" 27 | ); 28 | }); 29 | 30 | test_capability!(test_getset_gssapi_plaintext, "gssapi", { 31 | let ctx = Context::new(); 32 | let sock = ctx.socket(zmq::REQ).unwrap(); 33 | sock.set_gssapi_plaintext(true).unwrap(); 34 | assert!(sock.is_gssapi_plaintext().unwrap()); 35 | }); 36 | -------------------------------------------------------------------------------- /tests/has.rs: -------------------------------------------------------------------------------- 1 | #[test] 2 | fn test_has() { 3 | // Until we can clean up the API `has` must return Some(_), not matter 4 | // wether the capability is actually supported or not. 5 | assert!(zmq::has("ipc").is_some()); 6 | } 7 | -------------------------------------------------------------------------------- /tests/message.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | mod common; 3 | 4 | use quickcheck::{quickcheck, Arbitrary, Gen}; 5 | use zmq::Message; 6 | 7 | // A pair which contains two non-equal values 8 | #[derive(Clone, Debug)] 9 | struct NePair(T, T); 10 | 11 | impl Arbitrary for NePair 12 | where 13 | T: Eq + Arbitrary, 14 | { 15 | fn arbitrary(g: &mut Gen) -> Self { 16 | let v1 = T::arbitrary(g); 17 | let v2 = (0..).map(|_| T::arbitrary(g)).find(|v| *v != v1).unwrap(); 18 | NePair(v1, v2) 19 | } 20 | } 21 | 22 | quickcheck! { 23 | fn msg_cmp_eq(input: Vec) -> bool { 24 | Message::from(&input) == Message::from(&input) 25 | } 26 | 27 | fn msg_cmp_ne(input: NePair>) -> bool { 28 | Message::from(&input.0) != Message::from(&input.1) 29 | } 30 | 31 | fn msg_vec_roundtrip(input: Vec) -> bool { 32 | let original = Message::from(&input); 33 | Message::from(input) == original 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests/message_from_boxed_slice.rs: -------------------------------------------------------------------------------- 1 | use std::alloc::{GlobalAlloc, Layout, System}; 2 | use std::ptr; 3 | use std::sync::atomic::{AtomicPtr, Ordering}; 4 | 5 | struct Allocator; 6 | 7 | static CHECK_PTR: AtomicPtr = AtomicPtr::new(ptr::null_mut()); 8 | 9 | unsafe impl GlobalAlloc for Allocator { 10 | unsafe fn alloc(&self, layout: Layout) -> *mut u8 { 11 | System.alloc(layout) 12 | } 13 | 14 | unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { 15 | if ptr == CHECK_PTR.load(Ordering::SeqCst) { 16 | assert_eq!(layout, Layout::new::<[u8; 42]>()); 17 | CHECK_PTR.store(ptr::null_mut(), Ordering::SeqCst); 18 | } 19 | System.dealloc(ptr, layout); 20 | } 21 | } 22 | 23 | #[global_allocator] 24 | static A: Allocator = Allocator; 25 | 26 | #[test] 27 | fn message_from_boxed_slice() { 28 | let mut b: Box<[u8]> = Box::new([0u8; 42]); 29 | CHECK_PTR.store(b.as_mut_ptr(), Ordering::SeqCst); 30 | let _ = zmq::Message::from(b); 31 | assert_eq!(CHECK_PTR.load(Ordering::SeqCst), ptr::null_mut()); 32 | } 33 | -------------------------------------------------------------------------------- /tests/monitor.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | mod common; 3 | 4 | use std::str; 5 | 6 | fn version_ge_4_3() -> bool { 7 | let (major, minor, _) = zmq::version(); 8 | (major > 4) || (major == 4 && minor >= 3) 9 | } 10 | 11 | /// Read one event off the monitor socket; return the SocketEvent value. 12 | fn get_monitor_event(monitor: &mut zmq::Socket) -> zmq::Result { 13 | let msg = monitor.recv_msg(0)?; 14 | // TODO: could be simplified by using `TryInto` (since 1.34) 15 | let event = u16::from_ne_bytes([msg[0], msg[1]]); 16 | 17 | assert!( 18 | monitor.get_rcvmore()?, 19 | "Monitor socket should have two messages per event" 20 | ); 21 | 22 | // the address, we'll ignore it 23 | let _ = monitor.recv_msg(0)?; 24 | 25 | Ok(zmq::SocketEvent::from_raw(event)) 26 | } 27 | 28 | fn expect_event(mon: &mut zmq::Socket, expected: zmq::SocketEvent) { 29 | let event = get_monitor_event(mon).unwrap(); 30 | assert_eq!(expected, event); 31 | } 32 | 33 | /// Send a series of pings between the client and the server. 34 | /// The messages should round trip from the client to the server 35 | /// and back again. 36 | fn bounce(client: &mut zmq::Socket, server: &mut zmq::Socket) { 37 | let data = "12345678ABCDEFGH12345678abcdefgh"; 38 | 39 | // Send message from client to server 40 | client.send(data.as_bytes(), zmq::SNDMORE).unwrap(); 41 | client.send(data.as_bytes(), 0).unwrap(); 42 | 43 | // Receive message at server side 44 | let mut recv_data = server.recv_bytes(0).unwrap(); 45 | assert_eq!(str::from_utf8(&recv_data).unwrap(), data); 46 | assert!(server.get_rcvmore().unwrap()); 47 | 48 | recv_data = server.recv_bytes(0).unwrap(); 49 | assert_eq!(str::from_utf8(&recv_data).unwrap(), data); 50 | assert!(!server.get_rcvmore().unwrap()); 51 | 52 | // Send message from client to server 53 | server.send(&recv_data, zmq::SNDMORE).unwrap(); 54 | server.send(&recv_data, 0).unwrap(); 55 | 56 | // Receive the two parts at the client side 57 | recv_data = client.recv_bytes(0).unwrap(); 58 | assert_eq!(str::from_utf8(&recv_data).unwrap(), data); 59 | assert!(client.get_rcvmore().unwrap()); 60 | 61 | recv_data = client.recv_bytes(0).unwrap(); 62 | assert_eq!(str::from_utf8(&recv_data).unwrap(), data); 63 | assert!(!client.get_rcvmore().unwrap()); 64 | } 65 | 66 | /// Close the given socket with LINGER set to 0 67 | fn close_zero_linger(socket: zmq::Socket) { 68 | socket.set_linger(0).unwrap(); 69 | drop(socket); 70 | } 71 | 72 | test!(test_monitor_events, { 73 | let ctx = zmq::Context::new(); 74 | 75 | let mut client = ctx.socket(zmq::DEALER).unwrap(); 76 | let mut server = ctx.socket(zmq::DEALER).unwrap(); 77 | 78 | let err = client 79 | .monitor("tcp://127.0.0.1:9999", 0) 80 | .expect_err("Socket monitoring only works over inproc://"); 81 | assert_eq!(zmq::Error::EPROTONOSUPPORT, err); 82 | 83 | assert!(client 84 | .monitor("inproc://monitor-client", zmq::SocketEvent::ALL as i32) 85 | .is_ok()); 86 | assert!(server 87 | .monitor("inproc://monitor-server", zmq::SocketEvent::ALL as i32) 88 | .is_ok()); 89 | 90 | let mut client_mon = ctx.socket(zmq::PAIR).unwrap(); 91 | let mut server_mon = ctx.socket(zmq::PAIR).unwrap(); 92 | 93 | // Connect these to the inproc endpoints so they'll get events 94 | client_mon.connect("inproc://monitor-client").unwrap(); 95 | server_mon.connect("inproc://monitor-server").unwrap(); 96 | 97 | // Now do a basic ping test 98 | server.bind("tcp://127.0.0.1:9998").unwrap(); 99 | client.connect("tcp://127.0.0.1:9998").unwrap(); 100 | bounce(&mut client, &mut server); 101 | 102 | close_zero_linger(client); 103 | 104 | // Now collect and check events from both sockets 105 | let mut event = get_monitor_event(&mut client_mon).unwrap(); 106 | if event == zmq::SocketEvent::CONNECT_DELAYED { 107 | event = get_monitor_event(&mut client_mon).unwrap(); 108 | } 109 | assert_eq!(zmq::SocketEvent::CONNECTED, event); 110 | 111 | if version_ge_4_3() { 112 | expect_event(&mut client_mon, zmq::SocketEvent::HANDSHAKE_SUCCEEDED); 113 | } 114 | expect_event(&mut client_mon, zmq::SocketEvent::MONITOR_STOPPED); 115 | 116 | // This is the flow of server events 117 | expect_event(&mut server_mon, zmq::SocketEvent::LISTENING); 118 | expect_event(&mut server_mon, zmq::SocketEvent::ACCEPTED); 119 | 120 | if version_ge_4_3() { 121 | expect_event(&mut server_mon, zmq::SocketEvent::HANDSHAKE_SUCCEEDED); 122 | } 123 | expect_event(&mut server_mon, zmq::SocketEvent::DISCONNECTED); 124 | 125 | close_zero_linger(server); 126 | 127 | expect_event(&mut server_mon, zmq::SocketEvent::CLOSED); 128 | expect_event(&mut server_mon, zmq::SocketEvent::MONITOR_STOPPED); 129 | 130 | // Close down the sockets 131 | close_zero_linger(client_mon); 132 | close_zero_linger(server_mon); 133 | }); 134 | -------------------------------------------------------------------------------- /tests/poll.rs: -------------------------------------------------------------------------------- 1 | #[cfg(unix)] 2 | #[path = "poll/unix.rs"] 3 | mod unix; 4 | -------------------------------------------------------------------------------- /tests/poll/unix.rs: -------------------------------------------------------------------------------- 1 | // Test whether `zmq::poll()` works with `PollItem`s constructed from 2 | // arbitrary FDs. 3 | 4 | use nix::unistd; 5 | use std::os::unix::io::RawFd; 6 | use std::thread; 7 | 8 | #[test] 9 | fn test_pipe_poll() { 10 | let (pipe_read, pipe_write) = unistd::pipe().expect("pipe creation failed"); 11 | let writer_thread = thread::spawn(move || { 12 | pipe_writer(pipe_write); 13 | }); 14 | let pipe_item = zmq::PollItem::from_fd(pipe_read, zmq::POLLIN); 15 | assert!(pipe_item.has_fd(pipe_read)); 16 | 17 | let mut poll_items = [pipe_item]; 18 | assert_eq!(zmq::poll(&mut poll_items, 1000).unwrap(), 1); 19 | assert_eq!(poll_items[0].get_revents(), zmq::POLLIN); 20 | 21 | let mut buf = vec![0]; 22 | assert_eq!(unistd::read(pipe_read, &mut buf).unwrap(), 1); 23 | assert_eq!(buf, b"X"); 24 | 25 | writer_thread.join().unwrap(); 26 | } 27 | 28 | fn pipe_writer(fd: RawFd) { 29 | unistd::write(fd, b"X").expect("pipe write failed"); 30 | } 31 | -------------------------------------------------------------------------------- /tests/test.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | mod common; 3 | 4 | use std::io; 5 | use std::net::TcpStream; 6 | use zmq::*; 7 | 8 | fn version_ge_4_2() -> bool { 9 | let (major, minor, _) = version(); 10 | (major > 4) || (major == 4 && minor >= 2) 11 | } 12 | 13 | fn create_socketpair() -> (Socket, Socket) { 14 | let ctx = Context::default(); 15 | 16 | let sender = ctx.socket(zmq::REQ).unwrap(); 17 | let receiver = ctx.socket(zmq::REP).unwrap(); 18 | 19 | // Don't block forever 20 | sender.set_sndtimeo(1000).unwrap(); 21 | sender.set_rcvtimeo(1000).unwrap(); 22 | if version_ge_4_2() { 23 | sender.set_connect_timeout(1000).unwrap(); 24 | } 25 | receiver.set_sndtimeo(1000).unwrap(); 26 | receiver.set_rcvtimeo(1000).unwrap(); 27 | 28 | receiver.bind("tcp://127.0.0.1:*").unwrap(); 29 | let ep = receiver.get_last_endpoint().unwrap().unwrap(); 30 | sender.connect(&ep).unwrap(); 31 | 32 | (sender, receiver) 33 | } 34 | 35 | test!(test_exchanging_messages, { 36 | let (sender, receiver) = create_socketpair(); 37 | sender.send("foo", 0).unwrap(); 38 | let msg = receiver.recv_msg(0).unwrap(); 39 | assert_eq!(&msg[..], b"foo"); 40 | assert_eq!(msg.as_str(), Some("foo")); 41 | assert_eq!(format!("{:?}", msg), "[102, 111, 111]"); 42 | 43 | receiver.send("bar", 0).unwrap(); 44 | let msg = sender.recv_msg(0).unwrap(); 45 | assert_eq!(&msg[..], b"bar"); 46 | }); 47 | 48 | test!(test_exchanging_bytes, { 49 | let (sender, receiver) = create_socketpair(); 50 | sender.send("bar", 0).unwrap(); 51 | assert_eq!(receiver.recv_bytes(0).unwrap(), b"bar"); 52 | 53 | receiver.send("a quite long string", 0).unwrap(); 54 | let mut buf = [0_u8; 10]; 55 | sender.recv_into(&mut buf, 0).unwrap(); // this should truncate the message 56 | assert_eq!(&buf[..], b"a quite lo"); 57 | }); 58 | 59 | test!(test_exchanging_strings, { 60 | let (sender, receiver) = create_socketpair(); 61 | sender.send("bäz", 0).unwrap(); 62 | assert_eq!(receiver.recv_string(0).unwrap().unwrap(), "bäz"); 63 | 64 | // non-UTF8 strings -> get an Err with bytes when receiving 65 | receiver.send(b"\xff\xb7".as_ref(), 0).unwrap(); 66 | let result = sender.recv_string(0).unwrap(); 67 | assert_eq!(result, Err(vec![0xff, 0xb7])); 68 | }); 69 | 70 | test!(test_exchanging_multipart, { 71 | let (sender, receiver) = create_socketpair(); 72 | 73 | // convenience API 74 | sender.send_multipart(["foo", "bar"], 0).unwrap(); 75 | assert_eq!(receiver.recv_multipart(0).unwrap(), vec![b"foo", b"bar"]); 76 | 77 | // manually 78 | receiver.send("foo", SNDMORE).unwrap(); 79 | receiver.send("bar", 0).unwrap(); 80 | let msg1 = sender.recv_msg(0).unwrap(); 81 | assert!(msg1.get_more()); 82 | assert!(sender.get_rcvmore().unwrap()); 83 | assert_eq!(&msg1[..], b"foo"); 84 | let msg2 = sender.recv_msg(0).unwrap(); 85 | assert!(!msg2.get_more()); 86 | assert!(!sender.get_rcvmore().unwrap()); 87 | assert_eq!(&msg2[..], b"bar"); 88 | }); 89 | 90 | test!(test_polling, { 91 | let (sender, receiver) = create_socketpair(); 92 | 93 | // no message yet 94 | assert_eq!(receiver.poll(POLLIN, 1000).unwrap(), 0); 95 | 96 | // send message 97 | sender.send("Hello!", 0).unwrap(); 98 | let mut poll_items = vec![receiver.as_poll_item(POLLIN)]; 99 | assert_eq!(poll(&mut poll_items, 1000).unwrap(), 1); 100 | assert_eq!(poll_items[0].get_revents(), POLLIN); 101 | assert!(poll_items[0].is_readable()); 102 | assert!(!poll_items[0].is_writable()); 103 | assert!(!poll_items[0].is_error()); 104 | assert!(poll_items[0].has_socket(&receiver)); 105 | assert!(!poll_items[0].has_fd(0)); 106 | }); 107 | 108 | test!(test_raw_roundtrip, { 109 | let ctx = Context::new(); 110 | let mut sock = ctx.socket(SocketType::REQ).unwrap(); 111 | 112 | let ptr = sock.as_mut_ptr(); // doesn't consume the socket 113 | // NOTE: the socket will give up its context referecnce, but because we 114 | // still hold a reference in `ctx`, we won't get a deadlock. 115 | let raw = sock.into_raw(); // consumes the socket 116 | assert_eq!(ptr, raw); 117 | let _ = unsafe { Socket::from_raw(raw) }; 118 | }); 119 | 120 | // The `conflate` option limits the buffer size to one; let's see if we can get 121 | // messages (unreliably) across the connection. 122 | test!(test_conflating_receiver, { 123 | use std::sync::{ 124 | atomic::{AtomicBool, Ordering}, 125 | Arc, 126 | }; 127 | 128 | let ctx = zmq::Context::new(); 129 | let receiver = ctx.socket(zmq::PULL).unwrap(); 130 | receiver.bind("tcp://127.0.0.1:*").unwrap(); 131 | let receiver_endpoint = receiver.get_last_endpoint().unwrap().unwrap(); 132 | 133 | let stop = Arc::new(AtomicBool::new(false)); 134 | let sender_thread = { 135 | let stop = Arc::clone(&stop); 136 | std::thread::spawn(move || { 137 | let sender = ctx.socket(zmq::PUSH).unwrap(); 138 | sender.connect(&receiver_endpoint).unwrap(); 139 | while !stop.load(Ordering::SeqCst) { 140 | sender.send("bar", 0).expect("send failed"); 141 | } 142 | }) 143 | }; 144 | 145 | receiver 146 | .set_conflate(true) 147 | .expect("could not set conflate option"); 148 | for _ in 0..100 { 149 | let msg = receiver.recv_bytes(0).unwrap(); 150 | assert_eq!(&msg[..], b"bar"); 151 | } 152 | stop.store(true, Ordering::SeqCst); 153 | sender_thread.join().expect("could not join sender thread"); 154 | }); 155 | 156 | test!(test_version, { 157 | let (major, _, _) = version(); 158 | assert!(major == 3 || major == 4); 159 | }); 160 | 161 | test!(test_zmq_error, { 162 | let ctx = Context::new(); 163 | let sock = ctx.socket(SocketType::REP).unwrap(); 164 | 165 | // cannot send from REP unless we received a message first 166 | let err = sock.send("...", 0).unwrap_err(); 167 | assert_eq!(err, Error::EFSM); 168 | 169 | // ZMQ error strings might not be guaranteed, so we'll not check 170 | // against specific messages, but still check that formatting does 171 | // not segfault, for example, and gives the same strings. 172 | let desc = err.message(); 173 | let display = format!("{}", err); 174 | let debug = format!("{:?}", err); 175 | assert_eq!(desc, display); 176 | assert_eq!(desc, debug); 177 | }); 178 | 179 | test!(test_into_io_error, { 180 | let e: io::Error = Error::ENOENT.into(); 181 | assert!(e.kind() == io::ErrorKind::NotFound); 182 | }); 183 | 184 | test!(test_get_socket_type, { 185 | let ctx = Context::new(); 186 | 187 | let mut socket_types = vec![ 188 | SocketType::PAIR, 189 | SocketType::PUB, 190 | SocketType::SUB, 191 | SocketType::REQ, 192 | SocketType::REP, 193 | SocketType::DEALER, 194 | SocketType::ROUTER, 195 | SocketType::PULL, 196 | SocketType::PUSH, 197 | SocketType::XPUB, 198 | SocketType::XSUB, 199 | SocketType::STREAM, 200 | ]; 201 | for sock_type in socket_types.drain(..) { 202 | let sock = ctx.socket(sock_type).unwrap(); 203 | assert_eq!(sock.get_socket_type().unwrap(), sock_type); 204 | } 205 | }); 206 | 207 | test!(test_create_stream_socket, { 208 | let ctx = Context::new(); 209 | let sock = ctx.socket(STREAM).unwrap(); 210 | assert!(sock.bind("tcp://127.0.0.1:*").is_ok()); 211 | let ep = sock.get_last_endpoint().unwrap().unwrap(); 212 | let tcp = "tcp://"; 213 | assert!(ep.starts_with(tcp)); 214 | assert!(TcpStream::connect(&ep[tcp.len()..]).is_ok()); 215 | }); 216 | 217 | test!(test_getset_maxmsgsize, { 218 | let ctx = Context::new(); 219 | let sock = ctx.socket(REQ).unwrap(); 220 | sock.set_maxmsgsize(512_000).unwrap(); 221 | assert_eq!(sock.get_maxmsgsize().unwrap(), 512_000); 222 | }); 223 | 224 | test!(test_getset_sndhwm, { 225 | let ctx = Context::new(); 226 | let sock = ctx.socket(REQ).unwrap(); 227 | sock.set_sndhwm(500).unwrap(); 228 | assert_eq!(sock.get_sndhwm().unwrap(), 500); 229 | }); 230 | 231 | test!(test_getset_rcvhwm, { 232 | let ctx = Context::new(); 233 | let sock = ctx.socket(REQ).unwrap(); 234 | sock.set_rcvhwm(500).unwrap(); 235 | assert_eq!(sock.get_rcvhwm().unwrap(), 500); 236 | }); 237 | 238 | test!(test_getset_affinity, { 239 | let ctx = Context::new(); 240 | let sock = ctx.socket(REQ).unwrap(); 241 | sock.set_affinity(1024).unwrap(); 242 | assert_eq!(sock.get_affinity().unwrap(), 1024); 243 | }); 244 | 245 | test!(test_getset_identity, { 246 | let ctx = Context::new(); 247 | let sock = ctx.socket(REQ).unwrap(); 248 | sock.set_identity(b"moo").unwrap(); 249 | assert_eq!(sock.get_identity().unwrap(), b"moo"); 250 | }); 251 | 252 | test!(test_subscription, { 253 | let ctx = Context::new(); 254 | let sock = ctx.socket(SUB).unwrap(); 255 | assert!(sock.set_subscribe(b"/channel").is_ok()); 256 | assert!(sock.set_unsubscribe(b"/channel").is_ok()); 257 | }); 258 | 259 | test!(test_set_req_relaxed, { 260 | let ctx = Context::new(); 261 | let sock = ctx.socket(REQ).unwrap(); 262 | assert!(sock.set_req_relaxed(true).is_ok()); 263 | assert!(sock.set_req_relaxed(false).is_ok()); 264 | }); 265 | 266 | test!(test_set_req_correlate, { 267 | let ctx = Context::new(); 268 | let sock = ctx.socket(REQ).unwrap(); 269 | assert!(sock.set_req_correlate(true).is_ok()); 270 | assert!(sock.set_req_correlate(false).is_ok()); 271 | }); 272 | 273 | test!(test_getset_rate, { 274 | let ctx = Context::new(); 275 | let sock = ctx.socket(REQ).unwrap(); 276 | sock.set_rate(200).unwrap(); 277 | assert_eq!(sock.get_rate().unwrap(), 200); 278 | }); 279 | 280 | test!(test_getset_recovery_ivl, { 281 | let ctx = Context::new(); 282 | let sock = ctx.socket(REQ).unwrap(); 283 | sock.set_recovery_ivl(100).unwrap(); 284 | assert_eq!(sock.get_recovery_ivl().unwrap(), 100); 285 | }); 286 | 287 | test!(test_getset_sndbuf, { 288 | let ctx = Context::new(); 289 | let sock = ctx.socket(REQ).unwrap(); 290 | sock.set_sndbuf(100).unwrap(); 291 | assert_eq!(sock.get_sndbuf().unwrap(), 100); 292 | }); 293 | 294 | test!(test_getset_rcvbuf, { 295 | let ctx = Context::new(); 296 | let sock = ctx.socket(REQ).unwrap(); 297 | sock.set_rcvbuf(100).unwrap(); 298 | assert_eq!(sock.get_rcvbuf().unwrap(), 100); 299 | }); 300 | 301 | test!(test_getset_tos, { 302 | let ctx = Context::new(); 303 | let sock = ctx.socket(REQ).unwrap(); 304 | sock.set_tos(100).unwrap(); 305 | assert_eq!(sock.get_tos().unwrap(), 100); 306 | }); 307 | 308 | test!(test_getset_linger, { 309 | let ctx = Context::new(); 310 | let sock = ctx.socket(REQ).unwrap(); 311 | sock.set_linger(100).unwrap(); 312 | assert_eq!(sock.get_linger().unwrap(), 100); 313 | }); 314 | 315 | test!(test_getset_reconnect_ivl, { 316 | let ctx = Context::new(); 317 | let sock = ctx.socket(REQ).unwrap(); 318 | sock.set_reconnect_ivl(100).unwrap(); 319 | assert_eq!(sock.get_reconnect_ivl().unwrap(), 100); 320 | }); 321 | 322 | test!(test_getset_reconnect_ivl_max, { 323 | let ctx = Context::new(); 324 | let sock = ctx.socket(REQ).unwrap(); 325 | sock.set_reconnect_ivl_max(100).unwrap(); 326 | assert_eq!(sock.get_reconnect_ivl_max().unwrap(), 100); 327 | }); 328 | 329 | test!(test_getset_backlog, { 330 | let ctx = Context::new(); 331 | let sock = ctx.socket(REQ).unwrap(); 332 | sock.set_backlog(50).unwrap(); 333 | assert_eq!(sock.get_backlog().unwrap(), 50); 334 | }); 335 | 336 | test!(test_getset_multicast_hops, { 337 | let ctx = Context::new(); 338 | let sock = ctx.socket(REQ).unwrap(); 339 | sock.set_multicast_hops(20).unwrap(); 340 | assert_eq!(sock.get_multicast_hops().unwrap(), 20); 341 | }); 342 | 343 | test!(test_getset_rcvtimeo, { 344 | let ctx = Context::new(); 345 | let sock = ctx.socket(REQ).unwrap(); 346 | sock.set_rcvtimeo(5000).unwrap(); 347 | assert_eq!(sock.get_rcvtimeo().unwrap(), 5000); 348 | }); 349 | 350 | test!(test_getset_sndtimeo, { 351 | let ctx = Context::new(); 352 | let sock = ctx.socket(REQ).unwrap(); 353 | sock.set_sndtimeo(5000).unwrap(); 354 | assert_eq!(sock.get_sndtimeo().unwrap(), 5000); 355 | }); 356 | 357 | test!(test_getset_ipv6, { 358 | let ctx = Context::new(); 359 | let sock = ctx.socket(REQ).unwrap(); 360 | 361 | sock.set_ipv6(true).unwrap(); 362 | assert!(sock.is_ipv6().unwrap()); 363 | 364 | sock.set_ipv6(false).unwrap(); 365 | assert!(!sock.is_ipv6().unwrap()); 366 | }); 367 | 368 | test!(test_getset_socks_proxy, { 369 | let ctx = Context::new(); 370 | let sock = ctx.socket(REQ).unwrap(); 371 | 372 | sock.set_socks_proxy(Some("my_socks_server.com:10080")) 373 | .unwrap(); 374 | assert_eq!( 375 | sock.get_socks_proxy().unwrap().unwrap(), 376 | "my_socks_server.com:10080" 377 | ); 378 | 379 | sock.set_socks_proxy(None).unwrap(); 380 | assert_eq!(sock.get_socks_proxy().unwrap().unwrap(), ""); 381 | }); 382 | 383 | test!(test_getset_keepalive, { 384 | let ctx = Context::new(); 385 | let sock = ctx.socket(REQ).unwrap(); 386 | 387 | sock.set_tcp_keepalive(-1).unwrap(); 388 | assert_eq!(sock.get_tcp_keepalive().unwrap(), -1); 389 | 390 | sock.set_tcp_keepalive(0).unwrap(); 391 | assert_eq!(sock.get_tcp_keepalive().unwrap(), 0); 392 | 393 | sock.set_tcp_keepalive(1).unwrap(); 394 | assert_eq!(sock.get_tcp_keepalive().unwrap(), 1); 395 | }); 396 | 397 | test!(test_getset_keepalive_cnt, { 398 | let ctx = Context::new(); 399 | let sock = ctx.socket(REQ).unwrap(); 400 | 401 | sock.set_tcp_keepalive_cnt(-1).unwrap(); 402 | assert_eq!(sock.get_tcp_keepalive_cnt().unwrap(), -1); 403 | 404 | sock.set_tcp_keepalive_cnt(500).unwrap(); 405 | assert_eq!(sock.get_tcp_keepalive_cnt().unwrap(), 500); 406 | }); 407 | 408 | test!(test_getset_keepalive_idle, { 409 | let ctx = Context::new(); 410 | let sock = ctx.socket(REQ).unwrap(); 411 | 412 | sock.set_tcp_keepalive_idle(-1).unwrap(); 413 | assert_eq!(sock.get_tcp_keepalive_idle().unwrap(), -1); 414 | 415 | sock.set_tcp_keepalive_idle(500).unwrap(); 416 | assert_eq!(sock.get_tcp_keepalive_idle().unwrap(), 500); 417 | }); 418 | 419 | test!(test_getset_tcp_keepalive_intvl, { 420 | let ctx = Context::new(); 421 | let sock = ctx.socket(REQ).unwrap(); 422 | 423 | sock.set_tcp_keepalive_intvl(-1).unwrap(); 424 | assert_eq!(sock.get_tcp_keepalive_intvl().unwrap(), -1); 425 | 426 | sock.set_tcp_keepalive_intvl(500).unwrap(); 427 | assert_eq!(sock.get_tcp_keepalive_intvl().unwrap(), 500); 428 | }); 429 | 430 | test!(test_getset_immediate, { 431 | let ctx = Context::new(); 432 | let sock = ctx.socket(REQ).unwrap(); 433 | 434 | sock.set_immediate(true).unwrap(); 435 | assert!(sock.is_immediate().unwrap()); 436 | 437 | sock.set_immediate(false).unwrap(); 438 | assert!(!sock.is_immediate().unwrap()); 439 | }); 440 | 441 | test!(test_getset_plain_server, { 442 | let ctx = Context::new(); 443 | let sock = ctx.socket(REQ).unwrap(); 444 | 445 | sock.set_plain_server(true).unwrap(); 446 | assert!(sock.is_plain_server().unwrap()); 447 | 448 | sock.set_plain_server(false).unwrap(); 449 | assert!(!sock.is_plain_server().unwrap()); 450 | }); 451 | 452 | test!(test_getset_plain_username, { 453 | let ctx = Context::new(); 454 | let sock = ctx.socket(REQ).unwrap(); 455 | 456 | sock.set_plain_username(Some("billybob")).unwrap(); 457 | assert_eq!(sock.get_plain_username().unwrap().unwrap(), "billybob"); 458 | assert_eq!(sock.get_mechanism().unwrap(), Mechanism::ZMQ_PLAIN); 459 | 460 | sock.set_plain_username(None).unwrap(); 461 | assert!(sock.get_mechanism().unwrap() == Mechanism::ZMQ_NULL); 462 | }); 463 | 464 | test!(test_getset_plain_password, { 465 | let ctx = Context::new(); 466 | let sock = ctx.socket(REQ).unwrap(); 467 | 468 | sock.set_plain_password(Some("m00c0w")).unwrap(); 469 | assert_eq!(sock.get_plain_password().unwrap().unwrap(), "m00c0w"); 470 | assert_eq!(sock.get_mechanism().unwrap(), Mechanism::ZMQ_PLAIN); 471 | 472 | sock.set_plain_password(None).unwrap(); 473 | assert!(sock.get_mechanism().unwrap() == Mechanism::ZMQ_NULL); 474 | }); 475 | 476 | test!(test_zmq_set_xpub_verbose, { 477 | let ctx = Context::new(); 478 | let xpub = ctx.socket(XPUB).unwrap(); 479 | let sub = ctx.socket(SUB).unwrap(); 480 | 481 | xpub.bind("inproc://set_xpub_verbose").unwrap(); 482 | xpub.set_xpub_verbose(true).unwrap(); 483 | 484 | sub.connect("inproc://set_xpub_verbose").unwrap(); 485 | for _ in 0..2 { 486 | sub.set_subscribe(b"topic").unwrap(); 487 | 488 | let event = xpub.recv_msg(0).unwrap(); 489 | assert_eq!(event[0], 1); 490 | assert_eq!(&event[1..], b"topic"); 491 | } 492 | }); 493 | 494 | test!(test_zmq_xpub_welcome_msg, { 495 | let ctx = Context::new(); 496 | let xpub = ctx.socket(XPUB).unwrap(); 497 | 498 | xpub.bind("inproc://xpub_welcome_msg").unwrap(); 499 | xpub.set_xpub_welcome_msg(Some("welcome")).unwrap(); 500 | 501 | let sub = ctx.socket(SUB).unwrap(); 502 | sub.set_subscribe(b"").unwrap(); 503 | sub.connect("inproc://xpub_welcome_msg").unwrap(); 504 | 505 | let from_pub = xpub.recv_bytes(0).unwrap(); 506 | assert_eq!(from_pub, b"\x01"); 507 | 508 | let from_xsub = sub.recv_bytes(0).unwrap(); 509 | assert_eq!(from_xsub, b"welcome"); 510 | }); 511 | 512 | test!(test_getset_zap_domain, { 513 | let ctx = Context::new(); 514 | let sock = ctx.socket(REQ).unwrap(); 515 | sock.set_zap_domain("test_domain").unwrap(); 516 | assert_eq!(sock.get_zap_domain().unwrap().unwrap(), "test_domain"); 517 | }); 518 | 519 | test!(test_get_fd, { 520 | let ctx = Context::new(); 521 | let sock_a = ctx.socket(REQ).unwrap(); 522 | let sock_b = ctx.socket(REQ).unwrap(); 523 | 524 | let mut fds_a: Vec<_> = (0..10).map(|_| sock_a.get_fd()).collect(); 525 | fds_a.dedup(); 526 | assert_eq!(fds_a.len(), 1); 527 | 528 | let mut fds_b: Vec<_> = (0..10).map(|_| sock_b.get_fd()).collect(); 529 | fds_b.dedup(); 530 | assert_eq!(fds_b.len(), 1); 531 | 532 | assert_ne!(fds_a[0], fds_b[0]); 533 | }); 534 | 535 | test!(test_ctx_nohang, { 536 | // Test that holding on to a socket keeps the context it was 537 | // created from from being destroyed. Destroying the context while 538 | // a socket is still open would block, thus hanging this test in 539 | // the failing case. 540 | let sock = { 541 | let ctx = Context::new(); 542 | ctx.socket(REQ).unwrap() 543 | }; 544 | assert_eq!(sock.get_socket_type(), Ok(REQ)); 545 | }); 546 | 547 | test!(test_getset_conflate, { 548 | let ctx = Context::new(); 549 | let sock = ctx.socket(REQ).unwrap(); 550 | sock.set_conflate(true).unwrap(); 551 | assert!(sock.is_conflate().unwrap()); 552 | }); 553 | 554 | test!(test_disconnect, { 555 | // Make a connected socket pair 556 | let (sender, receiver) = create_socketpair(); 557 | // Now disconnect them 558 | let ep = receiver.get_last_endpoint().unwrap().unwrap(); 559 | sender.disconnect(&ep).unwrap(); 560 | // And check that the message can no longer be sent 561 | assert_eq!(Error::EAGAIN, sender.send("foo", DONTWAIT).unwrap_err()); 562 | }); 563 | 564 | test!(test_disconnect_err, { 565 | let (sender, _) = create_socketpair(); 566 | // Check that disconnect propagates errors. The endpoint is not connected. 567 | assert_eq!( 568 | Error::ENOENT, 569 | sender.disconnect("tcp://192.0.2.1:2233").unwrap_err() 570 | ); 571 | }); 572 | 573 | test!(test_getset_handshake_ivl, { 574 | let ctx = Context::new(); 575 | let sock = ctx.socket(REQ).unwrap(); 576 | sock.set_handshake_ivl(50000).unwrap(); 577 | assert_eq!(sock.get_handshake_ivl().unwrap(), 50000); 578 | }); 579 | 580 | test!(test_getset_connect_timeout, { 581 | if version_ge_4_2() { 582 | let ctx = Context::new(); 583 | let sock = ctx.socket(REQ).unwrap(); 584 | sock.set_connect_timeout(5000).unwrap(); 585 | assert_eq!(sock.get_connect_timeout().unwrap(), 5000); 586 | } 587 | }); 588 | -------------------------------------------------------------------------------- /tests/unix/connection.rs: -------------------------------------------------------------------------------- 1 | // Test integration of zmq with a simple external event loop 2 | // 3 | // This excercises the `Socket::get_fd()` method in combination with 4 | // `Socket::get_events()` to integrate with Unix `poll(2)` to check 5 | // the basis for integration with external event loops works. 6 | 7 | use log::debug; 8 | use nix::poll::{self, PollFlags}; 9 | 10 | use super::with_connection; 11 | 12 | test!(test_external_poll_inproc, { 13 | with_connection( 14 | "inproc://test-poll", 15 | zmq::REQ, 16 | poll_client, 17 | zmq::REP, 18 | poll_worker, 19 | ); 20 | }); 21 | 22 | test!(test_external_poll_ipc, { 23 | with_connection( 24 | "ipc:///tmp/zmq-tokio-test", 25 | zmq::REQ, 26 | poll_client, 27 | zmq::REP, 28 | poll_worker, 29 | ); 30 | }); 31 | 32 | test!(test_external_poll_tcp, { 33 | with_connection( 34 | "tcp://127.0.0.1:*", 35 | zmq::REQ, 36 | poll_client, 37 | zmq::REP, 38 | poll_worker, 39 | ); 40 | }); 41 | 42 | fn poll_client(_ctx: &zmq::Context, socket: &zmq::Socket) { 43 | // TODO: we should use `poll::poll()` here as well. 44 | for i in 0..10 { 45 | let payload = format!("message {}", i); 46 | socket.send(&payload, 0).unwrap(); 47 | let reply = socket.recv_msg(0).unwrap(); 48 | assert_eq!(payload.as_bytes(), &reply[..]); 49 | } 50 | socket.send("", 0).unwrap(); 51 | let last = socket.recv_msg(0).unwrap(); 52 | assert_eq!(b"", &last[..]); 53 | } 54 | 55 | /// Keeps track of the polling state for the event signalling FD of a 56 | /// single socket. 57 | struct PollState<'a> { 58 | socket: &'a zmq::Socket, 59 | fds: [poll::PollFd; 1], 60 | } 61 | 62 | impl<'a> PollState<'a> { 63 | fn new(socket: &'a zmq::Socket) -> Self { 64 | let fd = socket.get_fd().unwrap(); 65 | PollState { 66 | socket, 67 | fds: [poll::PollFd::new(fd, PollFlags::POLLIN)], 68 | } 69 | } 70 | 71 | /// Wait for one of `events` to happen. 72 | fn wait(&mut self, events: zmq::PollEvents) { 73 | while !(self.events().intersects(events)) { 74 | debug!("polling"); 75 | let fds = &mut self.fds; 76 | poll::poll(fds, -1).unwrap(); 77 | debug!("poll done, events: {:?}", fds[0].revents()); 78 | match fds[0].revents() { 79 | Some(events) => { 80 | if !events.contains(PollFlags::POLLIN) { 81 | continue; 82 | } 83 | } 84 | _ => continue, 85 | } 86 | } 87 | } 88 | 89 | fn events(&self) -> zmq::PollEvents { 90 | self.socket.get_events().unwrap() as zmq::PollEvents 91 | } 92 | } 93 | 94 | fn poll_worker(_ctx: &zmq::Context, socket: &zmq::Socket) { 95 | let mut reply = None; 96 | let mut state = PollState::new(socket); 97 | loop { 98 | match reply.take() { 99 | None => { 100 | state.wait(zmq::POLLIN); 101 | let msg = socket.recv_msg(zmq::DONTWAIT).unwrap(); 102 | reply = Some(msg); 103 | } 104 | Some(msg) => { 105 | state.wait(zmq::POLLOUT); 106 | let done = msg.len() == 0; 107 | socket.send(msg, zmq::DONTWAIT).unwrap(); 108 | if done { 109 | break; 110 | } 111 | } 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /tests/z85.rs: -------------------------------------------------------------------------------- 1 | //use quickcheck::{quickcheck, Arbitrary, Gen}; 2 | //use rand::Rng; 3 | //use std::iter; 4 | 5 | use zmq::{z85_decode, z85_encode, DecodeError, EncodeError}; 6 | 7 | #[test] 8 | fn test_z85() { 9 | let test_str = "/AB8cGJ*-$lEbr2=TW$Q?i7:) (), 20 | _ => panic!("expected bad length error"), 21 | } 22 | 23 | let bad_str = "/AB\x008"; 24 | match z85_decode(bad_str) { 25 | Err(DecodeError::NulError(_)) => (), 26 | _ => panic!("expected nul error"), 27 | } 28 | 29 | let bad_bytes = b"\x01\x01\x01\x01\x01"; 30 | match z85_encode(bad_bytes) { 31 | Err(EncodeError::BadLength) => (), 32 | _ => panic!("expected bad length error"), 33 | } 34 | } 35 | 36 | /* 37 | // Valid input for z85 encoding (i.e. a slice of bytes with its length 38 | // being a multiple of 4) 39 | #[derive(Clone, Debug)] 40 | struct Input(Vec); 41 | 42 | // Disabled because quickcheck doesn't expose gen_range and gen anymore 43 | 44 | impl Arbitrary for Input { 45 | fn arbitrary(g: &mut Gen) -> Self { 46 | let len = g.gen_range(0..256) * 4; 47 | Input(iter::repeat(()).map(|_| g.gen()).take(len).collect()) 48 | } 49 | } 50 | 51 | quickcheck! { 52 | fn z85_roundtrip(input: Input) -> bool { 53 | let encoded = z85_encode(&input.0).unwrap(); 54 | let decoded = z85_decode(&encoded).unwrap(); 55 | input.0 == decoded 56 | } 57 | } 58 | */ 59 | -------------------------------------------------------------------------------- /zmq-sys/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | -------------------------------------------------------------------------------- /zmq-sys/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "zmq-sys" 3 | version = "0.12.0" 4 | authors = [ 5 | "a.rottmann@gmx.at", 6 | "erick.tryzelaar@gmail.com", 7 | ] 8 | license = "MIT/Apache-2.0" 9 | description = "Low-level bindings to the zeromq library" 10 | keywords = ["ffi", "bindings"] 11 | categories = ["external-ffi-bindings"] 12 | repository = "https://github.com/erickt/rust-zmq" 13 | build = "build/main.rs" 14 | links = "zmq" 15 | 16 | [features] 17 | 18 | [dependencies] 19 | libc = "0.2.15" 20 | 21 | [build-dependencies] 22 | system-deps = "6" 23 | zeromq-src = "0.3" 24 | 25 | [package.metadata.system-deps] 26 | libzmq = "4.1" 27 | -------------------------------------------------------------------------------- /zmq-sys/build/main.rs: -------------------------------------------------------------------------------- 1 | pub fn configure() { 2 | println!("cargo:rerun-if-changed=build/main.rs"); 3 | println!("cargo:rerun-if-env-changed=PROFILE"); 4 | 5 | // Note that by default `libzmq` builds without `libsodium` by instead 6 | // relying on `tweetnacl`. However since this `tweetnacl` [has never been 7 | // audited nor is ready for production](https://github.com/zeromq/libzmq/issues/3006), 8 | // we link against `libsodium` to enable `ZMQ_CURVE`. 9 | zeromq_src::Build::new() 10 | .with_libsodium(None) 11 | .build(); 12 | } 13 | 14 | fn main() { 15 | configure() 16 | } 17 | -------------------------------------------------------------------------------- /zmq-sys/src/errno.rs: -------------------------------------------------------------------------------- 1 | #[cfg(unix)] 2 | use libc as errno; 3 | #[cfg(windows)] 4 | use windows::errno; 5 | 6 | const ZMQ_HAUSNUMERO: i32 = 156_384_712; 7 | 8 | pub const EACCES: i32 = errno::EACCES; 9 | pub const EADDRINUSE: i32 = errno::EADDRINUSE; 10 | pub const EAGAIN: i32 = errno::EAGAIN; 11 | pub const EBUSY: i32 = errno::EBUSY; 12 | pub const ECONNREFUSED: i32 = errno::ECONNREFUSED; 13 | pub const EFAULT: i32 = errno::EFAULT; 14 | pub const EINTR: i32 = errno::EINTR; 15 | pub const EHOSTUNREACH: i32 = errno::EHOSTUNREACH; 16 | pub const EINPROGRESS: i32 = errno::EINPROGRESS; 17 | pub const EINVAL: i32 = errno::EINVAL; 18 | pub const EMFILE: i32 = errno::EMFILE; 19 | pub const EMSGSIZE: i32 = errno::EMSGSIZE; 20 | pub const ENAMETOOLONG: i32 = errno::ENAMETOOLONG; 21 | pub const ENODEV: i32 = errno::ENODEV; 22 | pub const ENOENT: i32 = errno::ENOENT; 23 | pub const ENOMEM: i32 = errno::ENOMEM; 24 | pub const ENOTCONN: i32 = errno::ENOTCONN; 25 | pub const ENOTSOCK: i32 = errno::ENOTSOCK; 26 | pub const EPROTO: i32 = errno::EPROTO; 27 | pub const EPROTONOSUPPORT: i32 = errno::EPROTONOSUPPORT; 28 | pub const ENOTSUP: i32 = errno::ENOTSUP; 29 | pub const ENOBUFS: i32 = errno::ENOBUFS; 30 | pub const ENETDOWN: i32 = errno::ENETDOWN; 31 | pub const EADDRNOTAVAIL: i32 = errno::EADDRNOTAVAIL; 32 | 33 | // native zmq error codes 34 | pub const EFSM: i32 = ZMQ_HAUSNUMERO + 51; 35 | pub const ENOCOMPATPROTO: i32 = ZMQ_HAUSNUMERO + 52; 36 | pub const ETERM: i32 = ZMQ_HAUSNUMERO + 53; 37 | pub const EMTHREAD: i32 = ZMQ_HAUSNUMERO + 54; 38 | 39 | // These may be returned by libzmq if the target platform does not define these 40 | // errno codes. 41 | pub const ENOTSUP_ALT: i32 = ZMQ_HAUSNUMERO + 1; 42 | pub const EPROTONOSUPPORT_ALT: i32 = ZMQ_HAUSNUMERO + 2; 43 | pub const ENOBUFS_ALT: i32 = ZMQ_HAUSNUMERO + 3; 44 | pub const ENETDOWN_ALT: i32 = ZMQ_HAUSNUMERO + 4; 45 | pub const EADDRINUSE_ALT: i32 = ZMQ_HAUSNUMERO + 5; 46 | pub const EADDRNOTAVAIL_ALT: i32 = ZMQ_HAUSNUMERO + 6; 47 | pub const ECONNREFUSED_ALT: i32 = ZMQ_HAUSNUMERO + 7; 48 | pub const EINPROGRESS_ALT: i32 = ZMQ_HAUSNUMERO + 8; 49 | pub const ENOTSOCK_ALT: i32 = ZMQ_HAUSNUMERO + 9; 50 | pub const EMSGSIZE_ALT: i32 = ZMQ_HAUSNUMERO + 10; 51 | pub const EAFNOSUPPORT_ALT: i32 = ZMQ_HAUSNUMERO + 11; 52 | pub const ENETUNREACH_ALT: i32 = ZMQ_HAUSNUMERO + 12; 53 | pub const ECONNABORTED_ALT: i32 = ZMQ_HAUSNUMERO + 13; 54 | pub const ECONNRESET_ALT: i32 = ZMQ_HAUSNUMERO + 14; 55 | pub const ENOTCONN_ALT: i32 = ZMQ_HAUSNUMERO + 15; 56 | pub const ETIMEDOUT_ALT: i32 = ZMQ_HAUSNUMERO + 16; 57 | pub const EHOSTUNREACH_ALT: i32 = ZMQ_HAUSNUMERO + 17; 58 | pub const ENETRESET_ALT: i32 = ZMQ_HAUSNUMERO + 18; 59 | -------------------------------------------------------------------------------- /zmq-sys/src/ffi.rs: -------------------------------------------------------------------------------- 1 | /* automatically generated by rust-bindgen */ 2 | 3 | pub const ZMQ_VERSION_MAJOR: u32 = 4; 4 | pub const ZMQ_VERSION_MINOR: u32 = 3; 5 | pub const ZMQ_VERSION_PATCH: u32 = 1; 6 | pub const ZMQ_DEFINED_STDINT: u32 = 1; 7 | pub const ZMQ_HAUSNUMERO: u32 = 156384712; 8 | pub const ZMQ_IO_THREADS: u32 = 1; 9 | pub const ZMQ_MAX_SOCKETS: u32 = 2; 10 | pub const ZMQ_SOCKET_LIMIT: u32 = 3; 11 | pub const ZMQ_THREAD_PRIORITY: u32 = 3; 12 | pub const ZMQ_THREAD_SCHED_POLICY: u32 = 4; 13 | pub const ZMQ_MAX_MSGSZ: u32 = 5; 14 | pub const ZMQ_MSG_T_SIZE: u32 = 6; 15 | pub const ZMQ_THREAD_AFFINITY_CPU_ADD: u32 = 7; 16 | pub const ZMQ_THREAD_AFFINITY_CPU_REMOVE: u32 = 8; 17 | pub const ZMQ_THREAD_NAME_PREFIX: u32 = 9; 18 | pub const ZMQ_IO_THREADS_DFLT: u32 = 1; 19 | pub const ZMQ_MAX_SOCKETS_DFLT: u32 = 1023; 20 | pub const ZMQ_THREAD_PRIORITY_DFLT: i32 = -1; 21 | pub const ZMQ_THREAD_SCHED_POLICY_DFLT: i32 = -1; 22 | pub const ZMQ_PAIR: u32 = 0; 23 | pub const ZMQ_PUB: u32 = 1; 24 | pub const ZMQ_SUB: u32 = 2; 25 | pub const ZMQ_REQ: u32 = 3; 26 | pub const ZMQ_REP: u32 = 4; 27 | pub const ZMQ_DEALER: u32 = 5; 28 | pub const ZMQ_ROUTER: u32 = 6; 29 | pub const ZMQ_PULL: u32 = 7; 30 | pub const ZMQ_PUSH: u32 = 8; 31 | pub const ZMQ_XPUB: u32 = 9; 32 | pub const ZMQ_XSUB: u32 = 10; 33 | pub const ZMQ_STREAM: u32 = 11; 34 | pub const ZMQ_XREQ: u32 = 5; 35 | pub const ZMQ_XREP: u32 = 6; 36 | pub const ZMQ_AFFINITY: u32 = 4; 37 | pub const ZMQ_ROUTING_ID: u32 = 5; 38 | pub const ZMQ_SUBSCRIBE: u32 = 6; 39 | pub const ZMQ_UNSUBSCRIBE: u32 = 7; 40 | pub const ZMQ_RATE: u32 = 8; 41 | pub const ZMQ_RECOVERY_IVL: u32 = 9; 42 | pub const ZMQ_SNDBUF: u32 = 11; 43 | pub const ZMQ_RCVBUF: u32 = 12; 44 | pub const ZMQ_RCVMORE: u32 = 13; 45 | pub const ZMQ_FD: u32 = 14; 46 | pub const ZMQ_EVENTS: u32 = 15; 47 | pub const ZMQ_TYPE: u32 = 16; 48 | pub const ZMQ_LINGER: u32 = 17; 49 | pub const ZMQ_RECONNECT_IVL: u32 = 18; 50 | pub const ZMQ_BACKLOG: u32 = 19; 51 | pub const ZMQ_RECONNECT_IVL_MAX: u32 = 21; 52 | pub const ZMQ_MAXMSGSIZE: u32 = 22; 53 | pub const ZMQ_SNDHWM: u32 = 23; 54 | pub const ZMQ_RCVHWM: u32 = 24; 55 | pub const ZMQ_MULTICAST_HOPS: u32 = 25; 56 | pub const ZMQ_RCVTIMEO: u32 = 27; 57 | pub const ZMQ_SNDTIMEO: u32 = 28; 58 | pub const ZMQ_LAST_ENDPOINT: u32 = 32; 59 | pub const ZMQ_ROUTER_MANDATORY: u32 = 33; 60 | pub const ZMQ_TCP_KEEPALIVE: u32 = 34; 61 | pub const ZMQ_TCP_KEEPALIVE_CNT: u32 = 35; 62 | pub const ZMQ_TCP_KEEPALIVE_IDLE: u32 = 36; 63 | pub const ZMQ_TCP_KEEPALIVE_INTVL: u32 = 37; 64 | pub const ZMQ_IMMEDIATE: u32 = 39; 65 | pub const ZMQ_XPUB_VERBOSE: u32 = 40; 66 | pub const ZMQ_ROUTER_RAW: u32 = 41; 67 | pub const ZMQ_IPV6: u32 = 42; 68 | pub const ZMQ_MECHANISM: u32 = 43; 69 | pub const ZMQ_PLAIN_SERVER: u32 = 44; 70 | pub const ZMQ_PLAIN_USERNAME: u32 = 45; 71 | pub const ZMQ_PLAIN_PASSWORD: u32 = 46; 72 | pub const ZMQ_CURVE_SERVER: u32 = 47; 73 | pub const ZMQ_CURVE_PUBLICKEY: u32 = 48; 74 | pub const ZMQ_CURVE_SECRETKEY: u32 = 49; 75 | pub const ZMQ_CURVE_SERVERKEY: u32 = 50; 76 | pub const ZMQ_PROBE_ROUTER: u32 = 51; 77 | pub const ZMQ_REQ_CORRELATE: u32 = 52; 78 | pub const ZMQ_REQ_RELAXED: u32 = 53; 79 | pub const ZMQ_CONFLATE: u32 = 54; 80 | pub const ZMQ_ZAP_DOMAIN: u32 = 55; 81 | pub const ZMQ_ROUTER_HANDOVER: u32 = 56; 82 | pub const ZMQ_TOS: u32 = 57; 83 | pub const ZMQ_CONNECT_ROUTING_ID: u32 = 61; 84 | pub const ZMQ_GSSAPI_SERVER: u32 = 62; 85 | pub const ZMQ_GSSAPI_PRINCIPAL: u32 = 63; 86 | pub const ZMQ_GSSAPI_SERVICE_PRINCIPAL: u32 = 64; 87 | pub const ZMQ_GSSAPI_PLAINTEXT: u32 = 65; 88 | pub const ZMQ_HANDSHAKE_IVL: u32 = 66; 89 | pub const ZMQ_SOCKS_PROXY: u32 = 68; 90 | pub const ZMQ_XPUB_NODROP: u32 = 69; 91 | pub const ZMQ_BLOCKY: u32 = 70; 92 | pub const ZMQ_XPUB_MANUAL: u32 = 71; 93 | pub const ZMQ_XPUB_WELCOME_MSG: u32 = 72; 94 | pub const ZMQ_STREAM_NOTIFY: u32 = 73; 95 | pub const ZMQ_INVERT_MATCHING: u32 = 74; 96 | pub const ZMQ_HEARTBEAT_IVL: u32 = 75; 97 | pub const ZMQ_HEARTBEAT_TTL: u32 = 76; 98 | pub const ZMQ_HEARTBEAT_TIMEOUT: u32 = 77; 99 | pub const ZMQ_XPUB_VERBOSER: u32 = 78; 100 | pub const ZMQ_CONNECT_TIMEOUT: u32 = 79; 101 | pub const ZMQ_TCP_MAXRT: u32 = 80; 102 | pub const ZMQ_THREAD_SAFE: u32 = 81; 103 | pub const ZMQ_MULTICAST_MAXTPDU: u32 = 84; 104 | pub const ZMQ_VMCI_BUFFER_SIZE: u32 = 85; 105 | pub const ZMQ_VMCI_BUFFER_MIN_SIZE: u32 = 86; 106 | pub const ZMQ_VMCI_BUFFER_MAX_SIZE: u32 = 87; 107 | pub const ZMQ_VMCI_CONNECT_TIMEOUT: u32 = 88; 108 | pub const ZMQ_USE_FD: u32 = 89; 109 | pub const ZMQ_GSSAPI_PRINCIPAL_NAMETYPE: u32 = 90; 110 | pub const ZMQ_GSSAPI_SERVICE_PRINCIPAL_NAMETYPE: u32 = 91; 111 | pub const ZMQ_BINDTODEVICE: u32 = 92; 112 | pub const ZMQ_MORE: u32 = 1; 113 | pub const ZMQ_SHARED: u32 = 3; 114 | pub const ZMQ_DONTWAIT: u32 = 1; 115 | pub const ZMQ_SNDMORE: u32 = 2; 116 | pub const ZMQ_NULL: u32 = 0; 117 | pub const ZMQ_PLAIN: u32 = 1; 118 | pub const ZMQ_CURVE: u32 = 2; 119 | pub const ZMQ_GSSAPI: u32 = 3; 120 | pub const ZMQ_GROUP_MAX_LENGTH: u32 = 15; 121 | pub const ZMQ_IDENTITY: u32 = 5; 122 | pub const ZMQ_CONNECT_RID: u32 = 61; 123 | pub const ZMQ_TCP_ACCEPT_FILTER: u32 = 38; 124 | pub const ZMQ_IPC_FILTER_PID: u32 = 58; 125 | pub const ZMQ_IPC_FILTER_UID: u32 = 59; 126 | pub const ZMQ_IPC_FILTER_GID: u32 = 60; 127 | pub const ZMQ_IPV4ONLY: u32 = 31; 128 | pub const ZMQ_DELAY_ATTACH_ON_CONNECT: u32 = 39; 129 | pub const ZMQ_NOBLOCK: u32 = 1; 130 | pub const ZMQ_FAIL_UNROUTABLE: u32 = 33; 131 | pub const ZMQ_ROUTER_BEHAVIOR: u32 = 33; 132 | pub const ZMQ_SRCFD: u32 = 2; 133 | pub const ZMQ_GSSAPI_NT_HOSTBASED: u32 = 0; 134 | pub const ZMQ_GSSAPI_NT_USER_NAME: u32 = 1; 135 | pub const ZMQ_GSSAPI_NT_KRB5_PRINCIPAL: u32 = 2; 136 | pub const ZMQ_EVENT_CONNECTED: u32 = 1; 137 | pub const ZMQ_EVENT_CONNECT_DELAYED: u32 = 2; 138 | pub const ZMQ_EVENT_CONNECT_RETRIED: u32 = 4; 139 | pub const ZMQ_EVENT_LISTENING: u32 = 8; 140 | pub const ZMQ_EVENT_BIND_FAILED: u32 = 16; 141 | pub const ZMQ_EVENT_ACCEPTED: u32 = 32; 142 | pub const ZMQ_EVENT_ACCEPT_FAILED: u32 = 64; 143 | pub const ZMQ_EVENT_CLOSED: u32 = 128; 144 | pub const ZMQ_EVENT_CLOSE_FAILED: u32 = 256; 145 | pub const ZMQ_EVENT_DISCONNECTED: u32 = 512; 146 | pub const ZMQ_EVENT_MONITOR_STOPPED: u32 = 1024; 147 | pub const ZMQ_EVENT_ALL: u32 = 65535; 148 | pub const ZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL: u32 = 2048; 149 | pub const ZMQ_EVENT_HANDSHAKE_SUCCEEDED: u32 = 4096; 150 | pub const ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL: u32 = 8192; 151 | pub const ZMQ_EVENT_HANDSHAKE_FAILED_AUTH: u32 = 16384; 152 | pub const ZMQ_PROTOCOL_ERROR_ZMTP_UNSPECIFIED: u32 = 268435456; 153 | pub const ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND: u32 = 268435457; 154 | pub const ZMQ_PROTOCOL_ERROR_ZMTP_INVALID_SEQUENCE: u32 = 268435458; 155 | pub const ZMQ_PROTOCOL_ERROR_ZMTP_KEY_EXCHANGE: u32 = 268435459; 156 | pub const ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_UNSPECIFIED: u32 = 268435473; 157 | pub const ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_MESSAGE: u32 = 268435474; 158 | pub const ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO: u32 = 268435475; 159 | pub const ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_INITIATE: u32 = 268435476; 160 | pub const ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_ERROR: u32 = 268435477; 161 | pub const ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_READY: u32 = 268435478; 162 | pub const ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_WELCOME: u32 = 268435479; 163 | pub const ZMQ_PROTOCOL_ERROR_ZMTP_INVALID_METADATA: u32 = 268435480; 164 | pub const ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC: u32 = 285212673; 165 | pub const ZMQ_PROTOCOL_ERROR_ZMTP_MECHANISM_MISMATCH: u32 = 285212674; 166 | pub const ZMQ_PROTOCOL_ERROR_ZAP_UNSPECIFIED: u32 = 536870912; 167 | pub const ZMQ_PROTOCOL_ERROR_ZAP_MALFORMED_REPLY: u32 = 536870913; 168 | pub const ZMQ_PROTOCOL_ERROR_ZAP_BAD_REQUEST_ID: u32 = 536870914; 169 | pub const ZMQ_PROTOCOL_ERROR_ZAP_BAD_VERSION: u32 = 536870915; 170 | pub const ZMQ_PROTOCOL_ERROR_ZAP_INVALID_STATUS_CODE: u32 = 536870916; 171 | pub const ZMQ_PROTOCOL_ERROR_ZAP_INVALID_METADATA: u32 = 536870917; 172 | pub const ZMQ_POLLIN: u32 = 1; 173 | pub const ZMQ_POLLOUT: u32 = 2; 174 | pub const ZMQ_POLLERR: u32 = 4; 175 | pub const ZMQ_POLLPRI: u32 = 8; 176 | pub const ZMQ_POLLITEMS_DFLT: u32 = 16; 177 | pub const ZMQ_HAS_CAPABILITIES: u32 = 1; 178 | pub const ZMQ_STREAMER: u32 = 1; 179 | pub const ZMQ_FORWARDER: u32 = 2; 180 | pub const ZMQ_QUEUE: u32 = 3; 181 | pub type __uint8_t = ::std::os::raw::c_uchar; 182 | extern "C" { 183 | pub fn zmq_errno() -> ::std::os::raw::c_int; 184 | } 185 | extern "C" { 186 | pub fn zmq_strerror(errnum_: ::std::os::raw::c_int) -> *const ::std::os::raw::c_char; 187 | } 188 | extern "C" { 189 | pub fn zmq_version( 190 | major_: *mut ::std::os::raw::c_int, 191 | minor_: *mut ::std::os::raw::c_int, 192 | patch_: *mut ::std::os::raw::c_int, 193 | ); 194 | } 195 | extern "C" { 196 | pub fn zmq_ctx_new() -> *mut ::std::os::raw::c_void; 197 | } 198 | extern "C" { 199 | pub fn zmq_ctx_term(context_: *mut ::std::os::raw::c_void) -> ::std::os::raw::c_int; 200 | } 201 | extern "C" { 202 | pub fn zmq_ctx_shutdown(context_: *mut ::std::os::raw::c_void) -> ::std::os::raw::c_int; 203 | } 204 | extern "C" { 205 | pub fn zmq_ctx_set( 206 | context_: *mut ::std::os::raw::c_void, 207 | option_: ::std::os::raw::c_int, 208 | optval_: ::std::os::raw::c_int, 209 | ) -> ::std::os::raw::c_int; 210 | } 211 | extern "C" { 212 | pub fn zmq_ctx_get( 213 | context_: *mut ::std::os::raw::c_void, 214 | option_: ::std::os::raw::c_int, 215 | ) -> ::std::os::raw::c_int; 216 | } 217 | extern "C" { 218 | pub fn zmq_init(io_threads_: ::std::os::raw::c_int) -> *mut ::std::os::raw::c_void; 219 | } 220 | extern "C" { 221 | pub fn zmq_term(context_: *mut ::std::os::raw::c_void) -> ::std::os::raw::c_int; 222 | } 223 | extern "C" { 224 | pub fn zmq_ctx_destroy(context_: *mut ::std::os::raw::c_void) -> ::std::os::raw::c_int; 225 | } 226 | #[repr(C)] 227 | #[repr(align(8))] 228 | #[derive(Copy, Clone)] 229 | pub struct zmq_msg_t { 230 | pub __: [::std::os::raw::c_uchar; 64usize], 231 | } 232 | #[test] 233 | fn bindgen_test_layout_zmq_msg_t() { 234 | assert_eq!( 235 | ::std::mem::size_of::(), 236 | 64usize, 237 | concat!("Size of: ", stringify!(zmq_msg_t)) 238 | ); 239 | assert_eq!( 240 | ::std::mem::align_of::(), 241 | 8usize, 242 | concat!("Alignment of ", stringify!(zmq_msg_t)) 243 | ); 244 | assert_eq!( 245 | unsafe { &(*(::std::ptr::null::())).__ as *const _ as usize }, 246 | 0usize, 247 | concat!( 248 | "Offset of field: ", 249 | stringify!(zmq_msg_t), 250 | "::", 251 | stringify!(__) 252 | ) 253 | ); 254 | } 255 | impl Default for zmq_msg_t { 256 | fn default() -> Self { 257 | unsafe { ::std::mem::zeroed() } 258 | } 259 | } 260 | pub type zmq_free_fn = ::std::option::Option< 261 | unsafe extern "C" fn(data_: *mut ::std::os::raw::c_void, hint_: *mut ::std::os::raw::c_void), 262 | >; 263 | extern "C" { 264 | pub fn zmq_msg_init(msg_: *mut zmq_msg_t) -> ::std::os::raw::c_int; 265 | } 266 | extern "C" { 267 | pub fn zmq_msg_init_size(msg_: *mut zmq_msg_t, size_: usize) -> ::std::os::raw::c_int; 268 | } 269 | extern "C" { 270 | pub fn zmq_msg_init_data( 271 | msg_: *mut zmq_msg_t, 272 | data_: *mut ::std::os::raw::c_void, 273 | size_: usize, 274 | ffn_: zmq_free_fn, 275 | hint_: *mut ::std::os::raw::c_void, 276 | ) -> ::std::os::raw::c_int; 277 | } 278 | extern "C" { 279 | pub fn zmq_msg_send( 280 | msg_: *mut zmq_msg_t, 281 | s_: *mut ::std::os::raw::c_void, 282 | flags_: ::std::os::raw::c_int, 283 | ) -> ::std::os::raw::c_int; 284 | } 285 | extern "C" { 286 | pub fn zmq_msg_recv( 287 | msg_: *mut zmq_msg_t, 288 | s_: *mut ::std::os::raw::c_void, 289 | flags_: ::std::os::raw::c_int, 290 | ) -> ::std::os::raw::c_int; 291 | } 292 | extern "C" { 293 | pub fn zmq_msg_close(msg_: *mut zmq_msg_t) -> ::std::os::raw::c_int; 294 | } 295 | extern "C" { 296 | pub fn zmq_msg_move(dest_: *mut zmq_msg_t, src_: *mut zmq_msg_t) -> ::std::os::raw::c_int; 297 | } 298 | extern "C" { 299 | pub fn zmq_msg_copy(dest_: *mut zmq_msg_t, src_: *mut zmq_msg_t) -> ::std::os::raw::c_int; 300 | } 301 | extern "C" { 302 | pub fn zmq_msg_data(msg_: *mut zmq_msg_t) -> *mut ::std::os::raw::c_void; 303 | } 304 | extern "C" { 305 | pub fn zmq_msg_size(msg_: *const zmq_msg_t) -> usize; 306 | } 307 | extern "C" { 308 | pub fn zmq_msg_more(msg_: *const zmq_msg_t) -> ::std::os::raw::c_int; 309 | } 310 | extern "C" { 311 | pub fn zmq_msg_get( 312 | msg_: *const zmq_msg_t, 313 | property_: ::std::os::raw::c_int, 314 | ) -> ::std::os::raw::c_int; 315 | } 316 | extern "C" { 317 | pub fn zmq_msg_set( 318 | msg_: *mut zmq_msg_t, 319 | property_: ::std::os::raw::c_int, 320 | optval_: ::std::os::raw::c_int, 321 | ) -> ::std::os::raw::c_int; 322 | } 323 | extern "C" { 324 | pub fn zmq_msg_gets( 325 | msg_: *const zmq_msg_t, 326 | property_: *const ::std::os::raw::c_char, 327 | ) -> *const ::std::os::raw::c_char; 328 | } 329 | extern "C" { 330 | pub fn zmq_socket( 331 | arg1: *mut ::std::os::raw::c_void, 332 | type_: ::std::os::raw::c_int, 333 | ) -> *mut ::std::os::raw::c_void; 334 | } 335 | extern "C" { 336 | pub fn zmq_close(s_: *mut ::std::os::raw::c_void) -> ::std::os::raw::c_int; 337 | } 338 | extern "C" { 339 | pub fn zmq_setsockopt( 340 | s_: *mut ::std::os::raw::c_void, 341 | option_: ::std::os::raw::c_int, 342 | optval_: *const ::std::os::raw::c_void, 343 | optvallen_: usize, 344 | ) -> ::std::os::raw::c_int; 345 | } 346 | extern "C" { 347 | pub fn zmq_getsockopt( 348 | s_: *mut ::std::os::raw::c_void, 349 | option_: ::std::os::raw::c_int, 350 | optval_: *mut ::std::os::raw::c_void, 351 | optvallen_: *mut usize, 352 | ) -> ::std::os::raw::c_int; 353 | } 354 | extern "C" { 355 | pub fn zmq_bind( 356 | s_: *mut ::std::os::raw::c_void, 357 | addr_: *const ::std::os::raw::c_char, 358 | ) -> ::std::os::raw::c_int; 359 | } 360 | extern "C" { 361 | pub fn zmq_connect( 362 | s_: *mut ::std::os::raw::c_void, 363 | addr_: *const ::std::os::raw::c_char, 364 | ) -> ::std::os::raw::c_int; 365 | } 366 | extern "C" { 367 | pub fn zmq_unbind( 368 | s_: *mut ::std::os::raw::c_void, 369 | addr_: *const ::std::os::raw::c_char, 370 | ) -> ::std::os::raw::c_int; 371 | } 372 | extern "C" { 373 | pub fn zmq_disconnect( 374 | s_: *mut ::std::os::raw::c_void, 375 | addr_: *const ::std::os::raw::c_char, 376 | ) -> ::std::os::raw::c_int; 377 | } 378 | extern "C" { 379 | pub fn zmq_send( 380 | s_: *mut ::std::os::raw::c_void, 381 | buf_: *const ::std::os::raw::c_void, 382 | len_: usize, 383 | flags_: ::std::os::raw::c_int, 384 | ) -> ::std::os::raw::c_int; 385 | } 386 | extern "C" { 387 | pub fn zmq_send_const( 388 | s_: *mut ::std::os::raw::c_void, 389 | buf_: *const ::std::os::raw::c_void, 390 | len_: usize, 391 | flags_: ::std::os::raw::c_int, 392 | ) -> ::std::os::raw::c_int; 393 | } 394 | extern "C" { 395 | pub fn zmq_recv( 396 | s_: *mut ::std::os::raw::c_void, 397 | buf_: *mut ::std::os::raw::c_void, 398 | len_: usize, 399 | flags_: ::std::os::raw::c_int, 400 | ) -> ::std::os::raw::c_int; 401 | } 402 | extern "C" { 403 | pub fn zmq_socket_monitor( 404 | s_: *mut ::std::os::raw::c_void, 405 | addr_: *const ::std::os::raw::c_char, 406 | events_: ::std::os::raw::c_int, 407 | ) -> ::std::os::raw::c_int; 408 | } 409 | #[repr(C)] 410 | #[derive(Debug, Copy, Clone)] 411 | pub struct zmq_pollitem_t { 412 | pub socket: *mut ::std::os::raw::c_void, 413 | pub fd: ::std::os::raw::c_int, 414 | pub events: ::std::os::raw::c_short, 415 | pub revents: ::std::os::raw::c_short, 416 | } 417 | #[test] 418 | fn bindgen_test_layout_zmq_pollitem_t() { 419 | assert_eq!( 420 | ::std::mem::size_of::(), 421 | 16usize, 422 | concat!("Size of: ", stringify!(zmq_pollitem_t)) 423 | ); 424 | assert_eq!( 425 | ::std::mem::align_of::(), 426 | 8usize, 427 | concat!("Alignment of ", stringify!(zmq_pollitem_t)) 428 | ); 429 | assert_eq!( 430 | unsafe { &(*(::std::ptr::null::())).socket as *const _ as usize }, 431 | 0usize, 432 | concat!( 433 | "Offset of field: ", 434 | stringify!(zmq_pollitem_t), 435 | "::", 436 | stringify!(socket) 437 | ) 438 | ); 439 | assert_eq!( 440 | unsafe { &(*(::std::ptr::null::())).fd as *const _ as usize }, 441 | 8usize, 442 | concat!( 443 | "Offset of field: ", 444 | stringify!(zmq_pollitem_t), 445 | "::", 446 | stringify!(fd) 447 | ) 448 | ); 449 | assert_eq!( 450 | unsafe { &(*(::std::ptr::null::())).events as *const _ as usize }, 451 | 12usize, 452 | concat!( 453 | "Offset of field: ", 454 | stringify!(zmq_pollitem_t), 455 | "::", 456 | stringify!(events) 457 | ) 458 | ); 459 | assert_eq!( 460 | unsafe { &(*(::std::ptr::null::())).revents as *const _ as usize }, 461 | 14usize, 462 | concat!( 463 | "Offset of field: ", 464 | stringify!(zmq_pollitem_t), 465 | "::", 466 | stringify!(revents) 467 | ) 468 | ); 469 | } 470 | impl Default for zmq_pollitem_t { 471 | fn default() -> Self { 472 | unsafe { ::std::mem::zeroed() } 473 | } 474 | } 475 | extern "C" { 476 | pub fn zmq_poll( 477 | items_: *mut zmq_pollitem_t, 478 | nitems_: ::std::os::raw::c_int, 479 | timeout_: ::std::os::raw::c_long, 480 | ) -> ::std::os::raw::c_int; 481 | } 482 | extern "C" { 483 | pub fn zmq_proxy( 484 | frontend_: *mut ::std::os::raw::c_void, 485 | backend_: *mut ::std::os::raw::c_void, 486 | capture_: *mut ::std::os::raw::c_void, 487 | ) -> ::std::os::raw::c_int; 488 | } 489 | extern "C" { 490 | pub fn zmq_proxy_steerable( 491 | frontend_: *mut ::std::os::raw::c_void, 492 | backend_: *mut ::std::os::raw::c_void, 493 | capture_: *mut ::std::os::raw::c_void, 494 | control_: *mut ::std::os::raw::c_void, 495 | ) -> ::std::os::raw::c_int; 496 | } 497 | extern "C" { 498 | pub fn zmq_has(capability_: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int; 499 | } 500 | extern "C" { 501 | pub fn zmq_device( 502 | type_: ::std::os::raw::c_int, 503 | frontend_: *mut ::std::os::raw::c_void, 504 | backend_: *mut ::std::os::raw::c_void, 505 | ) -> ::std::os::raw::c_int; 506 | } 507 | extern "C" { 508 | pub fn zmq_sendmsg( 509 | s_: *mut ::std::os::raw::c_void, 510 | msg_: *mut zmq_msg_t, 511 | flags_: ::std::os::raw::c_int, 512 | ) -> ::std::os::raw::c_int; 513 | } 514 | extern "C" { 515 | pub fn zmq_recvmsg( 516 | s_: *mut ::std::os::raw::c_void, 517 | msg_: *mut zmq_msg_t, 518 | flags_: ::std::os::raw::c_int, 519 | ) -> ::std::os::raw::c_int; 520 | } 521 | #[repr(C)] 522 | #[derive(Debug, Copy, Clone)] 523 | pub struct iovec { 524 | _unused: [u8; 0], 525 | } 526 | extern "C" { 527 | pub fn zmq_sendiov( 528 | s_: *mut ::std::os::raw::c_void, 529 | iov_: *mut iovec, 530 | count_: usize, 531 | flags_: ::std::os::raw::c_int, 532 | ) -> ::std::os::raw::c_int; 533 | } 534 | extern "C" { 535 | pub fn zmq_recviov( 536 | s_: *mut ::std::os::raw::c_void, 537 | iov_: *mut iovec, 538 | count_: *mut usize, 539 | flags_: ::std::os::raw::c_int, 540 | ) -> ::std::os::raw::c_int; 541 | } 542 | extern "C" { 543 | pub fn zmq_z85_encode( 544 | dest_: *mut ::std::os::raw::c_char, 545 | data_: *const u8, 546 | size_: usize, 547 | ) -> *mut ::std::os::raw::c_char; 548 | } 549 | extern "C" { 550 | pub fn zmq_z85_decode(dest_: *mut u8, string_: *const ::std::os::raw::c_char) -> *mut u8; 551 | } 552 | extern "C" { 553 | pub fn zmq_curve_keypair( 554 | z85_public_key_: *mut ::std::os::raw::c_char, 555 | z85_secret_key_: *mut ::std::os::raw::c_char, 556 | ) -> ::std::os::raw::c_int; 557 | } 558 | extern "C" { 559 | pub fn zmq_curve_public( 560 | z85_public_key_: *mut ::std::os::raw::c_char, 561 | z85_secret_key_: *const ::std::os::raw::c_char, 562 | ) -> ::std::os::raw::c_int; 563 | } 564 | extern "C" { 565 | pub fn zmq_atomic_counter_new() -> *mut ::std::os::raw::c_void; 566 | } 567 | extern "C" { 568 | pub fn zmq_atomic_counter_set( 569 | counter_: *mut ::std::os::raw::c_void, 570 | value_: ::std::os::raw::c_int, 571 | ); 572 | } 573 | extern "C" { 574 | pub fn zmq_atomic_counter_inc(counter_: *mut ::std::os::raw::c_void) -> ::std::os::raw::c_int; 575 | } 576 | extern "C" { 577 | pub fn zmq_atomic_counter_dec(counter_: *mut ::std::os::raw::c_void) -> ::std::os::raw::c_int; 578 | } 579 | extern "C" { 580 | pub fn zmq_atomic_counter_value(counter_: *mut ::std::os::raw::c_void) 581 | -> ::std::os::raw::c_int; 582 | } 583 | extern "C" { 584 | pub fn zmq_atomic_counter_destroy(counter_p_: *mut *mut ::std::os::raw::c_void); 585 | } 586 | pub type zmq_timer_fn = ::std::option::Option< 587 | unsafe extern "C" fn(timer_id: ::std::os::raw::c_int, arg: *mut ::std::os::raw::c_void), 588 | >; 589 | extern "C" { 590 | pub fn zmq_timers_new() -> *mut ::std::os::raw::c_void; 591 | } 592 | extern "C" { 593 | pub fn zmq_timers_destroy(timers_p: *mut *mut ::std::os::raw::c_void) -> ::std::os::raw::c_int; 594 | } 595 | extern "C" { 596 | pub fn zmq_timers_add( 597 | timers: *mut ::std::os::raw::c_void, 598 | interval: usize, 599 | handler: zmq_timer_fn, 600 | arg: *mut ::std::os::raw::c_void, 601 | ) -> ::std::os::raw::c_int; 602 | } 603 | extern "C" { 604 | pub fn zmq_timers_cancel( 605 | timers: *mut ::std::os::raw::c_void, 606 | timer_id: ::std::os::raw::c_int, 607 | ) -> ::std::os::raw::c_int; 608 | } 609 | extern "C" { 610 | pub fn zmq_timers_set_interval( 611 | timers: *mut ::std::os::raw::c_void, 612 | timer_id: ::std::os::raw::c_int, 613 | interval: usize, 614 | ) -> ::std::os::raw::c_int; 615 | } 616 | extern "C" { 617 | pub fn zmq_timers_reset( 618 | timers: *mut ::std::os::raw::c_void, 619 | timer_id: ::std::os::raw::c_int, 620 | ) -> ::std::os::raw::c_int; 621 | } 622 | extern "C" { 623 | pub fn zmq_timers_timeout(timers: *mut ::std::os::raw::c_void) -> ::std::os::raw::c_long; 624 | } 625 | extern "C" { 626 | pub fn zmq_timers_execute(timers: *mut ::std::os::raw::c_void) -> ::std::os::raw::c_int; 627 | } 628 | extern "C" { 629 | pub fn zmq_stopwatch_start() -> *mut ::std::os::raw::c_void; 630 | } 631 | extern "C" { 632 | pub fn zmq_stopwatch_intermediate( 633 | watch_: *mut ::std::os::raw::c_void, 634 | ) -> ::std::os::raw::c_ulong; 635 | } 636 | extern "C" { 637 | pub fn zmq_stopwatch_stop(watch_: *mut ::std::os::raw::c_void) -> ::std::os::raw::c_ulong; 638 | } 639 | extern "C" { 640 | pub fn zmq_sleep(seconds_: ::std::os::raw::c_int); 641 | } 642 | pub type zmq_thread_fn = 643 | ::std::option::Option; 644 | extern "C" { 645 | pub fn zmq_threadstart( 646 | func_: zmq_thread_fn, 647 | arg_: *mut ::std::os::raw::c_void, 648 | ) -> *mut ::std::os::raw::c_void; 649 | } 650 | extern "C" { 651 | pub fn zmq_threadclose(thread_: *mut ::std::os::raw::c_void); 652 | } 653 | -------------------------------------------------------------------------------- /zmq-sys/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate libc; 2 | 3 | #[cfg(unix)] 4 | mod unix; 5 | #[cfg(unix)] 6 | pub use crate::unix::RawFd; 7 | 8 | #[cfg(windows)] 9 | mod windows; 10 | #[cfg(windows)] 11 | pub use windows::RawFd; 12 | 13 | pub mod errno; 14 | 15 | pub use crate::ffi::{ 16 | // These are the non-deprecated constants defined in zmq.h. Note that this 17 | // list exceeds what is defined by the current minimum required version of 18 | // libzmq, but is instead based on the latest stable release. The idea here 19 | // is to expose newer API, when it is still compatible with the ABI defined 20 | // by the libzmq library. For example, using new socket options will just 21 | // result in a runtime error when used with an older libzmq, but 22 | // ABI-compatible libzmq, which does not know about them. 23 | ZMQ_HAUSNUMERO, 24 | ZMQ_IO_THREADS, 25 | ZMQ_MAX_SOCKETS, 26 | ZMQ_SOCKET_LIMIT, 27 | ZMQ_THREAD_PRIORITY, 28 | ZMQ_THREAD_SCHED_POLICY, 29 | ZMQ_MAX_MSGSZ, 30 | ZMQ_MSG_T_SIZE, 31 | ZMQ_THREAD_AFFINITY_CPU_ADD, 32 | ZMQ_THREAD_AFFINITY_CPU_REMOVE, 33 | ZMQ_THREAD_NAME_PREFIX, 34 | ZMQ_IO_THREADS_DFLT, 35 | ZMQ_MAX_SOCKETS_DFLT, 36 | ZMQ_THREAD_PRIORITY_DFLT, 37 | ZMQ_THREAD_SCHED_POLICY_DFLT, 38 | ZMQ_PAIR, 39 | ZMQ_PUB, 40 | ZMQ_SUB, 41 | ZMQ_REQ, 42 | ZMQ_REP, 43 | ZMQ_DEALER, 44 | ZMQ_ROUTER, 45 | ZMQ_PULL, 46 | ZMQ_PUSH, 47 | ZMQ_XPUB, 48 | ZMQ_XSUB, 49 | ZMQ_STREAM, 50 | ZMQ_AFFINITY, 51 | ZMQ_ROUTING_ID, 52 | ZMQ_SUBSCRIBE, 53 | ZMQ_UNSUBSCRIBE, 54 | ZMQ_RATE, 55 | ZMQ_RECOVERY_IVL, 56 | ZMQ_SNDBUF, 57 | ZMQ_RCVBUF, 58 | ZMQ_RCVMORE, 59 | ZMQ_FD, 60 | ZMQ_EVENTS, 61 | ZMQ_TYPE, 62 | ZMQ_LINGER, 63 | ZMQ_RECONNECT_IVL, 64 | ZMQ_BACKLOG, 65 | ZMQ_RECONNECT_IVL_MAX, 66 | ZMQ_MAXMSGSIZE, 67 | ZMQ_SNDHWM, 68 | ZMQ_RCVHWM, 69 | ZMQ_MULTICAST_HOPS, 70 | ZMQ_RCVTIMEO, 71 | ZMQ_SNDTIMEO, 72 | ZMQ_LAST_ENDPOINT, 73 | ZMQ_ROUTER_MANDATORY, 74 | ZMQ_TCP_KEEPALIVE, 75 | ZMQ_TCP_KEEPALIVE_CNT, 76 | ZMQ_TCP_KEEPALIVE_IDLE, 77 | ZMQ_TCP_KEEPALIVE_INTVL, 78 | ZMQ_IMMEDIATE, 79 | ZMQ_XPUB_VERBOSE, 80 | ZMQ_ROUTER_RAW, 81 | ZMQ_IPV6, 82 | ZMQ_MECHANISM, 83 | ZMQ_PLAIN_SERVER, 84 | ZMQ_PLAIN_USERNAME, 85 | ZMQ_PLAIN_PASSWORD, 86 | ZMQ_CURVE_SERVER, 87 | ZMQ_CURVE_PUBLICKEY, 88 | ZMQ_CURVE_SECRETKEY, 89 | ZMQ_CURVE_SERVERKEY, 90 | ZMQ_PROBE_ROUTER, 91 | ZMQ_REQ_CORRELATE, 92 | ZMQ_REQ_RELAXED, 93 | ZMQ_CONFLATE, 94 | ZMQ_ZAP_DOMAIN, 95 | ZMQ_ROUTER_HANDOVER, 96 | ZMQ_TOS, 97 | ZMQ_CONNECT_ROUTING_ID, 98 | ZMQ_GSSAPI_SERVER, 99 | ZMQ_GSSAPI_PRINCIPAL, 100 | ZMQ_GSSAPI_SERVICE_PRINCIPAL, 101 | ZMQ_GSSAPI_PLAINTEXT, 102 | ZMQ_HANDSHAKE_IVL, 103 | ZMQ_SOCKS_PROXY, 104 | ZMQ_XPUB_NODROP, 105 | ZMQ_BLOCKY, 106 | ZMQ_XPUB_MANUAL, 107 | ZMQ_XPUB_WELCOME_MSG, 108 | ZMQ_STREAM_NOTIFY, 109 | ZMQ_INVERT_MATCHING, 110 | ZMQ_HEARTBEAT_IVL, 111 | ZMQ_HEARTBEAT_TTL, 112 | ZMQ_HEARTBEAT_TIMEOUT, 113 | ZMQ_XPUB_VERBOSER, 114 | ZMQ_CONNECT_TIMEOUT, 115 | ZMQ_TCP_MAXRT, 116 | ZMQ_THREAD_SAFE, 117 | ZMQ_MULTICAST_MAXTPDU, 118 | ZMQ_VMCI_BUFFER_SIZE, 119 | ZMQ_VMCI_BUFFER_MIN_SIZE, 120 | ZMQ_VMCI_BUFFER_MAX_SIZE, 121 | ZMQ_VMCI_CONNECT_TIMEOUT, 122 | ZMQ_USE_FD, 123 | ZMQ_GSSAPI_PRINCIPAL_NAMETYPE, 124 | ZMQ_GSSAPI_SERVICE_PRINCIPAL_NAMETYPE, 125 | ZMQ_BINDTODEVICE, 126 | ZMQ_MORE, 127 | ZMQ_SHARED, 128 | ZMQ_DONTWAIT, 129 | ZMQ_SNDMORE, 130 | ZMQ_NULL, 131 | ZMQ_PLAIN, 132 | ZMQ_CURVE, 133 | ZMQ_GSSAPI, 134 | ZMQ_GROUP_MAX_LENGTH, 135 | ZMQ_EVENT_CONNECTED, 136 | ZMQ_EVENT_CONNECT_DELAYED, 137 | ZMQ_EVENT_CONNECT_RETRIED, 138 | ZMQ_EVENT_LISTENING, 139 | ZMQ_EVENT_BIND_FAILED, 140 | ZMQ_EVENT_ACCEPTED, 141 | ZMQ_EVENT_ACCEPT_FAILED, 142 | ZMQ_EVENT_CLOSED, 143 | ZMQ_EVENT_CLOSE_FAILED, 144 | ZMQ_EVENT_DISCONNECTED, 145 | ZMQ_EVENT_MONITOR_STOPPED, 146 | ZMQ_EVENT_ALL, 147 | ZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL, 148 | ZMQ_EVENT_HANDSHAKE_SUCCEEDED, 149 | ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL, 150 | ZMQ_EVENT_HANDSHAKE_FAILED_AUTH, 151 | ZMQ_PROTOCOL_ERROR_ZMTP_UNSPECIFIED, 152 | ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND, 153 | ZMQ_PROTOCOL_ERROR_ZMTP_INVALID_SEQUENCE, 154 | ZMQ_PROTOCOL_ERROR_ZMTP_KEY_EXCHANGE, 155 | ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_UNSPECIFIED, 156 | ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_MESSAGE, 157 | ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO, 158 | ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_INITIATE, 159 | ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_ERROR, 160 | ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_READY, 161 | ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_WELCOME, 162 | ZMQ_PROTOCOL_ERROR_ZMTP_INVALID_METADATA, 163 | ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC, 164 | ZMQ_PROTOCOL_ERROR_ZMTP_MECHANISM_MISMATCH, 165 | ZMQ_PROTOCOL_ERROR_ZAP_UNSPECIFIED, 166 | ZMQ_PROTOCOL_ERROR_ZAP_MALFORMED_REPLY, 167 | ZMQ_PROTOCOL_ERROR_ZAP_BAD_REQUEST_ID, 168 | ZMQ_PROTOCOL_ERROR_ZAP_BAD_VERSION, 169 | ZMQ_PROTOCOL_ERROR_ZAP_INVALID_STATUS_CODE, 170 | ZMQ_PROTOCOL_ERROR_ZAP_INVALID_METADATA, 171 | 172 | // These are "deprecated" in favor of the `zmq_poller` API, but are still 173 | // used by `zmq`, and the `zmq_poller` API has been introduced only in 174 | // 4.2.0, and have not been stabilized at least up until 4.3.1. 175 | ZMQ_POLLIN, 176 | ZMQ_POLLOUT, 177 | ZMQ_POLLERR, 178 | ZMQ_POLLPRI, 179 | 180 | ZMQ_POLLITEMS_DFLT, 181 | 182 | // Undeprecated types. 183 | zmq_msg_t, 184 | zmq_free_fn, 185 | 186 | // Undeprecated and documented functions (or more generally, symbols). These 187 | // must exist in the ABI of the oldest supported libzmq version, so 188 | // extending this list requires bumping that. 189 | zmq_pollitem_t, 190 | zmq_version, 191 | zmq_errno, 192 | zmq_strerror, 193 | zmq_ctx_new, 194 | zmq_ctx_term, 195 | zmq_ctx_shutdown, 196 | zmq_ctx_set, 197 | zmq_ctx_get, 198 | zmq_msg_init, 199 | zmq_msg_init_size, 200 | zmq_msg_init_data, 201 | zmq_msg_send, 202 | zmq_msg_recv, 203 | zmq_msg_close, 204 | zmq_msg_move, 205 | zmq_msg_copy, 206 | zmq_msg_data, 207 | zmq_msg_size, 208 | zmq_msg_more, 209 | zmq_msg_get, 210 | zmq_msg_set, 211 | zmq_msg_gets, 212 | zmq_socket, 213 | zmq_close, 214 | zmq_setsockopt, 215 | zmq_getsockopt, 216 | zmq_bind, 217 | zmq_connect, 218 | zmq_unbind, 219 | zmq_disconnect, 220 | zmq_send, 221 | zmq_send_const, 222 | zmq_recv, 223 | zmq_socket_monitor, 224 | zmq_sendmsg, 225 | zmq_recvmsg, 226 | zmq_sendiov, 227 | zmq_recviov, 228 | zmq_poll, 229 | zmq_proxy, 230 | zmq_proxy_steerable, 231 | zmq_has, 232 | zmq_device, 233 | zmq_z85_encode, 234 | zmq_z85_decode, 235 | zmq_curve_keypair, 236 | }; 237 | 238 | #[allow(non_camel_case_types)] 239 | #[allow(dead_code)] 240 | #[allow(clippy::unreadable_literal)] 241 | mod ffi; 242 | -------------------------------------------------------------------------------- /zmq-sys/src/unix.rs: -------------------------------------------------------------------------------- 1 | pub use std::os::unix::io::RawFd; 2 | -------------------------------------------------------------------------------- /zmq-sys/src/windows.rs: -------------------------------------------------------------------------------- 1 | pub use std::os::windows::io::RawSocket as RawFd; 2 | 3 | pub mod errno { 4 | use libc::c_int; 5 | 6 | // Use constants as defined in the windows header errno.h 7 | // libzmq should be compiled with VS2010 SDK headers or newer 8 | pub const EACCES: c_int = 13; 9 | pub const EADDRINUSE: c_int = 100; 10 | pub const EADDRNOTAVAIL: c_int = 101; 11 | pub const EAGAIN: c_int = 11; 12 | pub const EBUSY: c_int = 16; 13 | pub const ECONNREFUSED: c_int = 107; 14 | pub const EFAULT: c_int = 14; 15 | pub const EINTR: c_int = 4; 16 | pub const EHOSTUNREACH: c_int = 110; 17 | pub const EINPROGRESS: c_int = 112; 18 | pub const EINVAL: c_int = 22; 19 | pub const EMFILE: c_int = 24; 20 | pub const EMSGSIZE: c_int = 115; 21 | pub const ENAMETOOLONG: c_int = 38; 22 | pub const ENETDOWN: c_int = 116; 23 | pub const ENOBUFS: c_int = 119; 24 | pub const ENODEV: c_int = 19; 25 | pub const ENOENT: c_int = 2; 26 | pub const ENOMEM: c_int = 12; 27 | pub const ENOTCONN: c_int = 126; 28 | pub const ENOTSOCK: c_int = 128; 29 | pub const ENOTSUP: c_int = 129; 30 | pub const EPROTO: c_int = 134; 31 | pub const EPROTONOSUPPORT: c_int = 135; 32 | } 33 | --------------------------------------------------------------------------------