├── .circleci └── config.yml ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── bundle.json ├── examples ├── echo-rep │ └── main.pony └── echo-req │ └── main.pony └── zmq ├── LICENSE ├── _handle_incoming.pony ├── _handle_outgoing.pony ├── _message_queue.pony ├── _observe_incoming.pony ├── _observe_outgoing.pony ├── _reconnect_timer.pony ├── _session_keeper.pony ├── _socket_bind_inproc.pony ├── _socket_bind_tcp.pony ├── _socket_peer_inproc.pony ├── _socket_peer_tcp.pony ├── _socket_tcp_notify.pony ├── _zap.pony ├── bind.pony ├── connect.pony ├── context.pony ├── message.pony ├── socket.pony ├── socket_notify.pony ├── socket_options.pony ├── socket_type.pony ├── test ├── main.pony ├── message_test.pony ├── socket_options_test.pony ├── socket_transport_tests.pony ├── socket_type_tests.pony ├── util.pony └── z85_test.pony ├── z85 ├── LICENSE └── z85.pony └── zmtp ├── LICENSE ├── _buffer.pony ├── _curve_message_writer.pony ├── _curve_nonce_generator.pony ├── command.pony ├── command_auth_curve.pony ├── command_auth_null.pony ├── command_parser.pony ├── greeting.pony ├── mechanism.pony ├── mechanism_auth_curve_client.pony ├── mechanism_auth_curve_server.pony ├── mechanism_auth_null.pony ├── message.pony ├── message_parser.pony ├── session.pony ├── util.pony └── zap.pony /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | vs-ponyc-release: 4 | docker: 5 | - image: ponylang/ponyc:release 6 | steps: 7 | - checkout 8 | - run: make ci-setup 9 | - run: make ci 10 | vs-ponyc-master: 11 | docker: 12 | - image: ponylang/ponyc:latest 13 | steps: 14 | - checkout 15 | - run: make ci-setup 16 | - run: make ci 17 | 18 | workflows: 19 | version: 2 20 | commit: 21 | jobs: 22 | - vs-ponyc-release 23 | nightly: 24 | triggers: 25 | - schedule: 26 | cron: "0 0 * * *" 27 | filters: 28 | branches: 29 | only: master 30 | jobs: 31 | - vs-ponyc-master 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | .deps 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Mozilla Public License Version 2.0 2 | ================================== 3 | 4 | 1. Definitions 5 | -------------- 6 | 7 | 1.1. "Contributor" 8 | means each individual or legal entity that creates, contributes to 9 | the creation of, or owns Covered Software. 10 | 11 | 1.2. "Contributor Version" 12 | means the combination of the Contributions of others (if any) used 13 | by a Contributor and that particular Contributor's Contribution. 14 | 15 | 1.3. "Contribution" 16 | means Covered Software of a particular Contributor. 17 | 18 | 1.4. "Covered Software" 19 | means Source Code Form to which the initial Contributor has attached 20 | the notice in Exhibit A, the Executable Form of such Source Code 21 | Form, and Modifications of such Source Code Form, in each case 22 | including portions thereof. 23 | 24 | 1.5. "Incompatible With Secondary Licenses" 25 | means 26 | 27 | (a) that the initial Contributor has attached the notice described 28 | in Exhibit B to the Covered Software; or 29 | 30 | (b) that the Covered Software was made available under the terms of 31 | version 1.1 or earlier of the License, but not also under the 32 | terms of a Secondary License. 33 | 34 | 1.6. "Executable Form" 35 | means any form of the work other than Source Code Form. 36 | 37 | 1.7. "Larger Work" 38 | means a work that combines Covered Software with other material, in 39 | a separate file or files, that is not Covered Software. 40 | 41 | 1.8. "License" 42 | means this document. 43 | 44 | 1.9. "Licensable" 45 | means having the right to grant, to the maximum extent possible, 46 | whether at the time of the initial grant or subsequently, any and 47 | all of the rights conveyed by this License. 48 | 49 | 1.10. "Modifications" 50 | means any of the following: 51 | 52 | (a) any file in Source Code Form that results from an addition to, 53 | deletion from, or modification of the contents of Covered 54 | Software; or 55 | 56 | (b) any new file in Source Code Form that contains any Covered 57 | Software. 58 | 59 | 1.11. "Patent Claims" of a Contributor 60 | means any patent claim(s), including without limitation, method, 61 | process, and apparatus claims, in any patent Licensable by such 62 | Contributor that would be infringed, but for the grant of the 63 | License, by the making, using, selling, offering for sale, having 64 | made, import, or transfer of either its Contributions or its 65 | Contributor Version. 66 | 67 | 1.12. "Secondary License" 68 | means either the GNU General Public License, Version 2.0, the GNU 69 | Lesser General Public License, Version 2.1, the GNU Affero General 70 | Public License, Version 3.0, or any later versions of those 71 | licenses. 72 | 73 | 1.13. "Source Code Form" 74 | means the form of the work preferred for making modifications. 75 | 76 | 1.14. "You" (or "Your") 77 | means an individual or a legal entity exercising rights under this 78 | License. For legal entities, "You" includes any entity that 79 | controls, is controlled by, or is under common control with You. For 80 | purposes of this definition, "control" means (a) the power, direct 81 | or indirect, to cause the direction or management of such entity, 82 | whether by contract or otherwise, or (b) ownership of more than 83 | fifty percent (50%) of the outstanding shares or beneficial 84 | ownership of such entity. 85 | 86 | 2. License Grants and Conditions 87 | -------------------------------- 88 | 89 | 2.1. Grants 90 | 91 | Each Contributor hereby grants You a world-wide, royalty-free, 92 | non-exclusive license: 93 | 94 | (a) under intellectual property rights (other than patent or trademark) 95 | Licensable by such Contributor to use, reproduce, make available, 96 | modify, display, perform, distribute, and otherwise exploit its 97 | Contributions, either on an unmodified basis, with Modifications, or 98 | as part of a Larger Work; and 99 | 100 | (b) under Patent Claims of such Contributor to make, use, sell, offer 101 | for sale, have made, import, and otherwise transfer either its 102 | Contributions or its Contributor Version. 103 | 104 | 2.2. Effective Date 105 | 106 | The licenses granted in Section 2.1 with respect to any Contribution 107 | become effective for each Contribution on the date the Contributor first 108 | distributes such Contribution. 109 | 110 | 2.3. Limitations on Grant Scope 111 | 112 | The licenses granted in this Section 2 are the only rights granted under 113 | this License. No additional rights or licenses will be implied from the 114 | distribution or licensing of Covered Software under this License. 115 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 116 | Contributor: 117 | 118 | (a) for any code that a Contributor has removed from Covered Software; 119 | or 120 | 121 | (b) for infringements caused by: (i) Your and any other third party's 122 | modifications of Covered Software, or (ii) the combination of its 123 | Contributions with other software (except as part of its Contributor 124 | Version); or 125 | 126 | (c) under Patent Claims infringed by Covered Software in the absence of 127 | its Contributions. 128 | 129 | This License does not grant any rights in the trademarks, service marks, 130 | or logos of any Contributor (except as may be necessary to comply with 131 | the notice requirements in Section 3.4). 132 | 133 | 2.4. Subsequent Licenses 134 | 135 | No Contributor makes additional grants as a result of Your choice to 136 | distribute the Covered Software under a subsequent version of this 137 | License (see Section 10.2) or under the terms of a Secondary License (if 138 | permitted under the terms of Section 3.3). 139 | 140 | 2.5. Representation 141 | 142 | Each Contributor represents that the Contributor believes its 143 | Contributions are its original creation(s) or it has sufficient rights 144 | to grant the rights to its Contributions conveyed by this License. 145 | 146 | 2.6. Fair Use 147 | 148 | This License is not intended to limit any rights You have under 149 | applicable copyright doctrines of fair use, fair dealing, or other 150 | equivalents. 151 | 152 | 2.7. Conditions 153 | 154 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 155 | in Section 2.1. 156 | 157 | 3. Responsibilities 158 | ------------------- 159 | 160 | 3.1. Distribution of Source Form 161 | 162 | All distribution of Covered Software in Source Code Form, including any 163 | Modifications that You create or to which You contribute, must be under 164 | the terms of this License. You must inform recipients that the Source 165 | Code Form of the Covered Software is governed by the terms of this 166 | License, and how they can obtain a copy of this License. You may not 167 | attempt to alter or restrict the recipients' rights in the Source Code 168 | Form. 169 | 170 | 3.2. Distribution of Executable Form 171 | 172 | If You distribute Covered Software in Executable Form then: 173 | 174 | (a) such Covered Software must also be made available in Source Code 175 | Form, as described in Section 3.1, and You must inform recipients of 176 | the Executable Form how they can obtain a copy of such Source Code 177 | Form by reasonable means in a timely manner, at a charge no more 178 | than the cost of distribution to the recipient; and 179 | 180 | (b) You may distribute such Executable Form under the terms of this 181 | License, or sublicense it under different terms, provided that the 182 | license for the Executable Form does not attempt to limit or alter 183 | the recipients' rights in the Source Code Form under this License. 184 | 185 | 3.3. Distribution of a Larger Work 186 | 187 | You may create and distribute a Larger Work under terms of Your choice, 188 | provided that You also comply with the requirements of this License for 189 | the Covered Software. If the Larger Work is a combination of Covered 190 | Software with a work governed by one or more Secondary Licenses, and the 191 | Covered Software is not Incompatible With Secondary Licenses, this 192 | License permits You to additionally distribute such Covered Software 193 | under the terms of such Secondary License(s), so that the recipient of 194 | the Larger Work may, at their option, further distribute the Covered 195 | Software under the terms of either this License or such Secondary 196 | License(s). 197 | 198 | 3.4. Notices 199 | 200 | You may not remove or alter the substance of any license notices 201 | (including copyright notices, patent notices, disclaimers of warranty, 202 | or limitations of liability) contained within the Source Code Form of 203 | the Covered Software, except that You may alter any license notices to 204 | the extent required to remedy known factual inaccuracies. 205 | 206 | 3.5. Application of Additional Terms 207 | 208 | You may choose to offer, and to charge a fee for, warranty, support, 209 | indemnity or liability obligations to one or more recipients of Covered 210 | Software. However, You may do so only on Your own behalf, and not on 211 | behalf of any Contributor. You must make it absolutely clear that any 212 | such warranty, support, indemnity, or liability obligation is offered by 213 | You alone, and You hereby agree to indemnify every Contributor for any 214 | liability incurred by such Contributor as a result of warranty, support, 215 | indemnity or liability terms You offer. You may include additional 216 | disclaimers of warranty and limitations of liability specific to any 217 | jurisdiction. 218 | 219 | 4. Inability to Comply Due to Statute or Regulation 220 | --------------------------------------------------- 221 | 222 | If it is impossible for You to comply with any of the terms of this 223 | License with respect to some or all of the Covered Software due to 224 | statute, judicial order, or regulation then You must: (a) comply with 225 | the terms of this License to the maximum extent possible; and (b) 226 | describe the limitations and the code they affect. Such description must 227 | be placed in a text file included with all distributions of the Covered 228 | Software under this License. Except to the extent prohibited by statute 229 | or regulation, such description must be sufficiently detailed for a 230 | recipient of ordinary skill to be able to understand it. 231 | 232 | 5. Termination 233 | -------------- 234 | 235 | 5.1. The rights granted under this License will terminate automatically 236 | if You fail to comply with any of its terms. However, if You become 237 | compliant, then the rights granted under this License from a particular 238 | Contributor are reinstated (a) provisionally, unless and until such 239 | Contributor explicitly and finally terminates Your grants, and (b) on an 240 | ongoing basis, if such Contributor fails to notify You of the 241 | non-compliance by some reasonable means prior to 60 days after You have 242 | come back into compliance. Moreover, Your grants from a particular 243 | Contributor are reinstated on an ongoing basis if such Contributor 244 | notifies You of the non-compliance by some reasonable means, this is the 245 | first time You have received notice of non-compliance with this License 246 | from such Contributor, and You become compliant prior to 30 days after 247 | Your receipt of the notice. 248 | 249 | 5.2. If You initiate litigation against any entity by asserting a patent 250 | infringement claim (excluding declaratory judgment actions, 251 | counter-claims, and cross-claims) alleging that a Contributor Version 252 | directly or indirectly infringes any patent, then the rights granted to 253 | You by any and all Contributors for the Covered Software under Section 254 | 2.1 of this License shall terminate. 255 | 256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 257 | end user license agreements (excluding distributors and resellers) which 258 | have been validly granted by You or Your distributors under this License 259 | prior to termination shall survive termination. 260 | 261 | ************************************************************************ 262 | * * 263 | * 6. Disclaimer of Warranty * 264 | * ------------------------- * 265 | * * 266 | * Covered Software is provided under this License on an "as is" * 267 | * basis, without warranty of any kind, either expressed, implied, or * 268 | * statutory, including, without limitation, warranties that the * 269 | * Covered Software is free of defects, merchantable, fit for a * 270 | * particular purpose or non-infringing. The entire risk as to the * 271 | * quality and performance of the Covered Software is with You. * 272 | * Should any Covered Software prove defective in any respect, You * 273 | * (not any Contributor) assume the cost of any necessary servicing, * 274 | * repair, or correction. This disclaimer of warranty constitutes an * 275 | * essential part of this License. No use of any Covered Software is * 276 | * authorized under this License except under this disclaimer. * 277 | * * 278 | ************************************************************************ 279 | 280 | ************************************************************************ 281 | * * 282 | * 7. Limitation of Liability * 283 | * -------------------------- * 284 | * * 285 | * Under no circumstances and under no legal theory, whether tort * 286 | * (including negligence), contract, or otherwise, shall any * 287 | * Contributor, or anyone who distributes Covered Software as * 288 | * permitted above, be liable to You for any direct, indirect, * 289 | * special, incidental, or consequential damages of any character * 290 | * including, without limitation, damages for lost profits, loss of * 291 | * goodwill, work stoppage, computer failure or malfunction, or any * 292 | * and all other commercial damages or losses, even if such party * 293 | * shall have been informed of the possibility of such damages. This * 294 | * limitation of liability shall not apply to liability for death or * 295 | * personal injury resulting from such party's negligence to the * 296 | * extent applicable law prohibits such limitation. Some * 297 | * jurisdictions do not allow the exclusion or limitation of * 298 | * incidental or consequential damages, so this exclusion and * 299 | * limitation may not apply to You. * 300 | * * 301 | ************************************************************************ 302 | 303 | 8. Litigation 304 | ------------- 305 | 306 | Any litigation relating to this License may be brought only in the 307 | courts of a jurisdiction where the defendant maintains its principal 308 | place of business and such litigation shall be governed by laws of that 309 | jurisdiction, without reference to its conflict-of-law provisions. 310 | Nothing in this Section shall prevent a party's ability to bring 311 | cross-claims or counter-claims. 312 | 313 | 9. Miscellaneous 314 | ---------------- 315 | 316 | This License represents the complete agreement concerning the subject 317 | matter hereof. If any provision of this License is held to be 318 | unenforceable, such provision shall be reformed only to the extent 319 | necessary to make it enforceable. Any law or regulation which provides 320 | that the language of a contract shall be construed against the drafter 321 | shall not be used to construe this License against a Contributor. 322 | 323 | 10. Versions of the License 324 | --------------------------- 325 | 326 | 10.1. New Versions 327 | 328 | Mozilla Foundation is the license steward. Except as provided in Section 329 | 10.3, no one other than the license steward has the right to modify or 330 | publish new versions of this License. Each version will be given a 331 | distinguishing version number. 332 | 333 | 10.2. Effect of New Versions 334 | 335 | You may distribute the Covered Software under the terms of the version 336 | of the License under which You originally received the Covered Software, 337 | or under the terms of any subsequent version published by the license 338 | steward. 339 | 340 | 10.3. Modified Versions 341 | 342 | If you create software not governed by this License, and you want to 343 | create a new license for such software, you may create and use a 344 | modified version of this License if you rename the license and remove 345 | any references to the name of the license steward (except to note that 346 | such modified license differs from this License). 347 | 348 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 349 | Licenses 350 | 351 | If You choose to distribute Source Code Form that is Incompatible With 352 | Secondary Licenses under the terms of this version of the License, the 353 | notice described in Exhibit B of this License must be attached. 354 | 355 | Exhibit A - Source Code Form License Notice 356 | ------------------------------------------- 357 | 358 | This Source Code Form is subject to the terms of the Mozilla Public 359 | License, v. 2.0. If a copy of the MPL was not distributed with this 360 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 361 | 362 | If it is not possible or desirable to put the notice in a particular 363 | file, then You may include the notice in a location (such as a LICENSE 364 | file in a relevant directory) where a recipient would be likely to look 365 | for such a notice. 366 | 367 | You may add additional accurate notices of copyright ownership. 368 | 369 | Exhibit B - "Incompatible With Secondary Licenses" Notice 370 | --------------------------------------------------------- 371 | 372 | This Source Code Form is "Incompatible With Secondary Licenses", as 373 | defined by the Mozilla Public License, v. 2.0. 374 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: test 2 | .PHONY: all test clean lldb lldb-test ci ci-setup 3 | 4 | PKG=zmq 5 | 6 | bin/test: $(shell find ${PKG} .deps -name *.pony) 7 | mkdir -p bin 8 | stable env ponyc --debug -o bin ${PKG}/test 9 | 10 | test: bin/test 11 | $^ 12 | 13 | clean: 14 | rm -rf .deps bin 15 | 16 | lldb: 17 | stable env lldb -o run -- $(shell which ponyc) --debug -o /tmp ${PKG}/test 18 | 19 | lldb-test: bin/test 20 | lldb -o run -- bin/test 21 | 22 | ci: test 23 | 24 | ci-setup: 25 | apt-get update && apt-get install -y libsodium-dev 26 | stable fetch 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pony-zmq [![CircleCI](https://circleci.com/gh/jemc/pony-zmq.svg?style=shield)](https://circleci.com/gh/jemc/pony-zmq) 2 | 3 | Pure Pony implementation of the ZeroMQ messaging library. 4 | 5 | ## Testing 6 | 7 | 1. Get [stable](https://github.com/jemc/pony-stable) (to manage dependencies). 8 | 2. Get 9 | [libsodium](https://download.libsodium.org/doc/installation/index.html) 10 | (required for [pony-sodium](https://github.com/jemc/pony-sodium)). 11 | On OSX just to `brew install libsodium'. 12 | 3. Fetch dependencies: `stable fetch` 13 | 3. `stable env ponyc --debug zmq/test` 14 | 4. `./test` 15 | -------------------------------------------------------------------------------- /bundle.json: -------------------------------------------------------------------------------- 1 | { 2 | "deps": [ 3 | { "type": "github", "repo": "jemc/pony-inspect" }, 4 | { "type": "github", "repo": "jemc/pony-sodium" } 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /examples/echo-rep/main.pony: -------------------------------------------------------------------------------- 1 | use zmq = "../../zmq" 2 | use net = "net" 3 | 4 | actor Main is zmq.SocketNotifiableActor 5 | """ 6 | This program will create a ZeroMQ REP socket bound to localhost on port 9999. 7 | It will act as a simple echo server, accepting messages from connecting REQs, 8 | replying with the exact message that it received, and printing it to STDOUT. 9 | 10 | Run this example, then run the echo-req example to send it a message. 11 | """ 12 | let _env: Env 13 | 14 | new create(env: Env) => 15 | _env = env 16 | 17 | match _env.root | let root: AmbientAuth => 18 | let socket = zmq.Socket(zmq.REP, zmq.SocketNotifyActor(this)) 19 | 20 | socket(zmq.BindTCP(net.NetAuth(root), "localhost", "9999")) 21 | else 22 | _env.out.print("REP error: couldn't create NetAuth") 23 | end 24 | 25 | be received(socket: zmq.Socket, peer: zmq.SocketPeer, message: zmq.Message) => 26 | """ 27 | When we receive a request, we want to send the same message back to the peer 28 | unchanged (echo it) then print it to STDOUT for posterity. 29 | """ 30 | peer.send(message) 31 | 32 | _env.out.print("REP received/sent: " + message.string()) 33 | -------------------------------------------------------------------------------- /examples/echo-req/main.pony: -------------------------------------------------------------------------------- 1 | use zmq = "../../zmq" 2 | use net = "net" 3 | 4 | actor Main is zmq.SocketNotifiableActor 5 | """ 6 | This program will create a ZeroMQ REQ socket, and expect to connect to another 7 | ZeroMQ REP socket running on localhost on port 9999. 8 | 9 | It will send a single message composed of the command-line arguments to the 10 | program. If no arguments were provided, an empty message will be sent. 11 | 12 | When a response to the request is received from the other socket, the message 13 | will be printed and this program will be terminated. 14 | 15 | Run the echo-rep example, then run this example to send it a message. 16 | """ 17 | let _env: Env 18 | 19 | new create(env: Env) => 20 | _env = env 21 | 22 | match _env.root | let root: AmbientAuth => 23 | let socket = zmq.Socket(zmq.REQ, zmq.SocketNotifyActor(this)) 24 | 25 | socket(zmq.ConnectTCP(net.NetAuth(root), "localhost", "9999")) 26 | 27 | let message = recover val 28 | zmq.Message .> concat(_env.args.slice(1).values()) 29 | end 30 | 31 | socket.send(message) 32 | 33 | _env.out.print("REQ sent: " + message.string()) 34 | else 35 | _env.out.print("REQ error: couldn't create NetAuth") 36 | end 37 | 38 | be received(socket: zmq.Socket, peer: zmq.SocketPeer, message: zmq.Message) => 39 | """ 40 | When we receive a response to our request, we want to print it and then 41 | dispose of the socket, which will terminate the program because no other 42 | actor is left active (Pony programs terminate after reaching quiesence). 43 | """ 44 | _env.out.print("REQ received: " + message.string()) 45 | 46 | socket.dispose() 47 | -------------------------------------------------------------------------------- /zmq/LICENSE: -------------------------------------------------------------------------------- 1 | Mozilla Public License Version 2.0 2 | ================================== 3 | 4 | 1. Definitions 5 | -------------- 6 | 7 | 1.1. "Contributor" 8 | means each individual or legal entity that creates, contributes to 9 | the creation of, or owns Covered Software. 10 | 11 | 1.2. "Contributor Version" 12 | means the combination of the Contributions of others (if any) used 13 | by a Contributor and that particular Contributor's Contribution. 14 | 15 | 1.3. "Contribution" 16 | means Covered Software of a particular Contributor. 17 | 18 | 1.4. "Covered Software" 19 | means Source Code Form to which the initial Contributor has attached 20 | the notice in Exhibit A, the Executable Form of such Source Code 21 | Form, and Modifications of such Source Code Form, in each case 22 | including portions thereof. 23 | 24 | 1.5. "Incompatible With Secondary Licenses" 25 | means 26 | 27 | (a) that the initial Contributor has attached the notice described 28 | in Exhibit B to the Covered Software; or 29 | 30 | (b) that the Covered Software was made available under the terms of 31 | version 1.1 or earlier of the License, but not also under the 32 | terms of a Secondary License. 33 | 34 | 1.6. "Executable Form" 35 | means any form of the work other than Source Code Form. 36 | 37 | 1.7. "Larger Work" 38 | means a work that combines Covered Software with other material, in 39 | a separate file or files, that is not Covered Software. 40 | 41 | 1.8. "License" 42 | means this document. 43 | 44 | 1.9. "Licensable" 45 | means having the right to grant, to the maximum extent possible, 46 | whether at the time of the initial grant or subsequently, any and 47 | all of the rights conveyed by this License. 48 | 49 | 1.10. "Modifications" 50 | means any of the following: 51 | 52 | (a) any file in Source Code Form that results from an addition to, 53 | deletion from, or modification of the contents of Covered 54 | Software; or 55 | 56 | (b) any new file in Source Code Form that contains any Covered 57 | Software. 58 | 59 | 1.11. "Patent Claims" of a Contributor 60 | means any patent claim(s), including without limitation, method, 61 | process, and apparatus claims, in any patent Licensable by such 62 | Contributor that would be infringed, but for the grant of the 63 | License, by the making, using, selling, offering for sale, having 64 | made, import, or transfer of either its Contributions or its 65 | Contributor Version. 66 | 67 | 1.12. "Secondary License" 68 | means either the GNU General Public License, Version 2.0, the GNU 69 | Lesser General Public License, Version 2.1, the GNU Affero General 70 | Public License, Version 3.0, or any later versions of those 71 | licenses. 72 | 73 | 1.13. "Source Code Form" 74 | means the form of the work preferred for making modifications. 75 | 76 | 1.14. "You" (or "Your") 77 | means an individual or a legal entity exercising rights under this 78 | License. For legal entities, "You" includes any entity that 79 | controls, is controlled by, or is under common control with You. For 80 | purposes of this definition, "control" means (a) the power, direct 81 | or indirect, to cause the direction or management of such entity, 82 | whether by contract or otherwise, or (b) ownership of more than 83 | fifty percent (50%) of the outstanding shares or beneficial 84 | ownership of such entity. 85 | 86 | 2. License Grants and Conditions 87 | -------------------------------- 88 | 89 | 2.1. Grants 90 | 91 | Each Contributor hereby grants You a world-wide, royalty-free, 92 | non-exclusive license: 93 | 94 | (a) under intellectual property rights (other than patent or trademark) 95 | Licensable by such Contributor to use, reproduce, make available, 96 | modify, display, perform, distribute, and otherwise exploit its 97 | Contributions, either on an unmodified basis, with Modifications, or 98 | as part of a Larger Work; and 99 | 100 | (b) under Patent Claims of such Contributor to make, use, sell, offer 101 | for sale, have made, import, and otherwise transfer either its 102 | Contributions or its Contributor Version. 103 | 104 | 2.2. Effective Date 105 | 106 | The licenses granted in Section 2.1 with respect to any Contribution 107 | become effective for each Contribution on the date the Contributor first 108 | distributes such Contribution. 109 | 110 | 2.3. Limitations on Grant Scope 111 | 112 | The licenses granted in this Section 2 are the only rights granted under 113 | this License. No additional rights or licenses will be implied from the 114 | distribution or licensing of Covered Software under this License. 115 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 116 | Contributor: 117 | 118 | (a) for any code that a Contributor has removed from Covered Software; 119 | or 120 | 121 | (b) for infringements caused by: (i) Your and any other third party's 122 | modifications of Covered Software, or (ii) the combination of its 123 | Contributions with other software (except as part of its Contributor 124 | Version); or 125 | 126 | (c) under Patent Claims infringed by Covered Software in the absence of 127 | its Contributions. 128 | 129 | This License does not grant any rights in the trademarks, service marks, 130 | or logos of any Contributor (except as may be necessary to comply with 131 | the notice requirements in Section 3.4). 132 | 133 | 2.4. Subsequent Licenses 134 | 135 | No Contributor makes additional grants as a result of Your choice to 136 | distribute the Covered Software under a subsequent version of this 137 | License (see Section 10.2) or under the terms of a Secondary License (if 138 | permitted under the terms of Section 3.3). 139 | 140 | 2.5. Representation 141 | 142 | Each Contributor represents that the Contributor believes its 143 | Contributions are its original creation(s) or it has sufficient rights 144 | to grant the rights to its Contributions conveyed by this License. 145 | 146 | 2.6. Fair Use 147 | 148 | This License is not intended to limit any rights You have under 149 | applicable copyright doctrines of fair use, fair dealing, or other 150 | equivalents. 151 | 152 | 2.7. Conditions 153 | 154 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 155 | in Section 2.1. 156 | 157 | 3. Responsibilities 158 | ------------------- 159 | 160 | 3.1. Distribution of Source Form 161 | 162 | All distribution of Covered Software in Source Code Form, including any 163 | Modifications that You create or to which You contribute, must be under 164 | the terms of this License. You must inform recipients that the Source 165 | Code Form of the Covered Software is governed by the terms of this 166 | License, and how they can obtain a copy of this License. You may not 167 | attempt to alter or restrict the recipients' rights in the Source Code 168 | Form. 169 | 170 | 3.2. Distribution of Executable Form 171 | 172 | If You distribute Covered Software in Executable Form then: 173 | 174 | (a) such Covered Software must also be made available in Source Code 175 | Form, as described in Section 3.1, and You must inform recipients of 176 | the Executable Form how they can obtain a copy of such Source Code 177 | Form by reasonable means in a timely manner, at a charge no more 178 | than the cost of distribution to the recipient; and 179 | 180 | (b) You may distribute such Executable Form under the terms of this 181 | License, or sublicense it under different terms, provided that the 182 | license for the Executable Form does not attempt to limit or alter 183 | the recipients' rights in the Source Code Form under this License. 184 | 185 | 3.3. Distribution of a Larger Work 186 | 187 | You may create and distribute a Larger Work under terms of Your choice, 188 | provided that You also comply with the requirements of this License for 189 | the Covered Software. If the Larger Work is a combination of Covered 190 | Software with a work governed by one or more Secondary Licenses, and the 191 | Covered Software is not Incompatible With Secondary Licenses, this 192 | License permits You to additionally distribute such Covered Software 193 | under the terms of such Secondary License(s), so that the recipient of 194 | the Larger Work may, at their option, further distribute the Covered 195 | Software under the terms of either this License or such Secondary 196 | License(s). 197 | 198 | 3.4. Notices 199 | 200 | You may not remove or alter the substance of any license notices 201 | (including copyright notices, patent notices, disclaimers of warranty, 202 | or limitations of liability) contained within the Source Code Form of 203 | the Covered Software, except that You may alter any license notices to 204 | the extent required to remedy known factual inaccuracies. 205 | 206 | 3.5. Application of Additional Terms 207 | 208 | You may choose to offer, and to charge a fee for, warranty, support, 209 | indemnity or liability obligations to one or more recipients of Covered 210 | Software. However, You may do so only on Your own behalf, and not on 211 | behalf of any Contributor. You must make it absolutely clear that any 212 | such warranty, support, indemnity, or liability obligation is offered by 213 | You alone, and You hereby agree to indemnify every Contributor for any 214 | liability incurred by such Contributor as a result of warranty, support, 215 | indemnity or liability terms You offer. You may include additional 216 | disclaimers of warranty and limitations of liability specific to any 217 | jurisdiction. 218 | 219 | 4. Inability to Comply Due to Statute or Regulation 220 | --------------------------------------------------- 221 | 222 | If it is impossible for You to comply with any of the terms of this 223 | License with respect to some or all of the Covered Software due to 224 | statute, judicial order, or regulation then You must: (a) comply with 225 | the terms of this License to the maximum extent possible; and (b) 226 | describe the limitations and the code they affect. Such description must 227 | be placed in a text file included with all distributions of the Covered 228 | Software under this License. Except to the extent prohibited by statute 229 | or regulation, such description must be sufficiently detailed for a 230 | recipient of ordinary skill to be able to understand it. 231 | 232 | 5. Termination 233 | -------------- 234 | 235 | 5.1. The rights granted under this License will terminate automatically 236 | if You fail to comply with any of its terms. However, if You become 237 | compliant, then the rights granted under this License from a particular 238 | Contributor are reinstated (a) provisionally, unless and until such 239 | Contributor explicitly and finally terminates Your grants, and (b) on an 240 | ongoing basis, if such Contributor fails to notify You of the 241 | non-compliance by some reasonable means prior to 60 days after You have 242 | come back into compliance. Moreover, Your grants from a particular 243 | Contributor are reinstated on an ongoing basis if such Contributor 244 | notifies You of the non-compliance by some reasonable means, this is the 245 | first time You have received notice of non-compliance with this License 246 | from such Contributor, and You become compliant prior to 30 days after 247 | Your receipt of the notice. 248 | 249 | 5.2. If You initiate litigation against any entity by asserting a patent 250 | infringement claim (excluding declaratory judgment actions, 251 | counter-claims, and cross-claims) alleging that a Contributor Version 252 | directly or indirectly infringes any patent, then the rights granted to 253 | You by any and all Contributors for the Covered Software under Section 254 | 2.1 of this License shall terminate. 255 | 256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 257 | end user license agreements (excluding distributors and resellers) which 258 | have been validly granted by You or Your distributors under this License 259 | prior to termination shall survive termination. 260 | 261 | ************************************************************************ 262 | * * 263 | * 6. Disclaimer of Warranty * 264 | * ------------------------- * 265 | * * 266 | * Covered Software is provided under this License on an "as is" * 267 | * basis, without warranty of any kind, either expressed, implied, or * 268 | * statutory, including, without limitation, warranties that the * 269 | * Covered Software is free of defects, merchantable, fit for a * 270 | * particular purpose or non-infringing. The entire risk as to the * 271 | * quality and performance of the Covered Software is with You. * 272 | * Should any Covered Software prove defective in any respect, You * 273 | * (not any Contributor) assume the cost of any necessary servicing, * 274 | * repair, or correction. This disclaimer of warranty constitutes an * 275 | * essential part of this License. No use of any Covered Software is * 276 | * authorized under this License except under this disclaimer. * 277 | * * 278 | ************************************************************************ 279 | 280 | ************************************************************************ 281 | * * 282 | * 7. Limitation of Liability * 283 | * -------------------------- * 284 | * * 285 | * Under no circumstances and under no legal theory, whether tort * 286 | * (including negligence), contract, or otherwise, shall any * 287 | * Contributor, or anyone who distributes Covered Software as * 288 | * permitted above, be liable to You for any direct, indirect, * 289 | * special, incidental, or consequential damages of any character * 290 | * including, without limitation, damages for lost profits, loss of * 291 | * goodwill, work stoppage, computer failure or malfunction, or any * 292 | * and all other commercial damages or losses, even if such party * 293 | * shall have been informed of the possibility of such damages. This * 294 | * limitation of liability shall not apply to liability for death or * 295 | * personal injury resulting from such party's negligence to the * 296 | * extent applicable law prohibits such limitation. Some * 297 | * jurisdictions do not allow the exclusion or limitation of * 298 | * incidental or consequential damages, so this exclusion and * 299 | * limitation may not apply to You. * 300 | * * 301 | ************************************************************************ 302 | 303 | 8. Litigation 304 | ------------- 305 | 306 | Any litigation relating to this License may be brought only in the 307 | courts of a jurisdiction where the defendant maintains its principal 308 | place of business and such litigation shall be governed by laws of that 309 | jurisdiction, without reference to its conflict-of-law provisions. 310 | Nothing in this Section shall prevent a party's ability to bring 311 | cross-claims or counter-claims. 312 | 313 | 9. Miscellaneous 314 | ---------------- 315 | 316 | This License represents the complete agreement concerning the subject 317 | matter hereof. If any provision of this License is held to be 318 | unenforceable, such provision shall be reformed only to the extent 319 | necessary to make it enforceable. Any law or regulation which provides 320 | that the language of a contract shall be construed against the drafter 321 | shall not be used to construe this License against a Contributor. 322 | 323 | 10. Versions of the License 324 | --------------------------- 325 | 326 | 10.1. New Versions 327 | 328 | Mozilla Foundation is the license steward. Except as provided in Section 329 | 10.3, no one other than the license steward has the right to modify or 330 | publish new versions of this License. Each version will be given a 331 | distinguishing version number. 332 | 333 | 10.2. Effect of New Versions 334 | 335 | You may distribute the Covered Software under the terms of the version 336 | of the License under which You originally received the Covered Software, 337 | or under the terms of any subsequent version published by the license 338 | steward. 339 | 340 | 10.3. Modified Versions 341 | 342 | If you create software not governed by this License, and you want to 343 | create a new license for such software, you may create and use a 344 | modified version of this License if you rename the license and remove 345 | any references to the name of the license steward (except to note that 346 | such modified license differs from this License). 347 | 348 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 349 | Licenses 350 | 351 | If You choose to distribute Source Code Form that is Incompatible With 352 | Secondary Licenses under the terms of this version of the License, the 353 | notice described in Exhibit B of this License must be attached. 354 | 355 | Exhibit A - Source Code Form License Notice 356 | ------------------------------------------- 357 | 358 | This Source Code Form is subject to the terms of the Mozilla Public 359 | License, v. 2.0. If a copy of the MPL was not distributed with this 360 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 361 | 362 | If it is not possible or desirable to put the notice in a particular 363 | file, then You may include the notice in a location (such as a LICENSE 364 | file in a relevant directory) where a recipient would be likely to look 365 | for such a notice. 366 | 367 | You may add additional accurate notices of copyright ownership. 368 | 369 | Exhibit B - "Incompatible With Secondary Licenses" Notice 370 | --------------------------------------------------------- 371 | 372 | This Source Code Form is "Incompatible With Secondary Licenses", as 373 | defined by the Mozilla Public License, v. 2.0. 374 | -------------------------------------------------------------------------------- /zmq/_handle_incoming.pony: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | interface _HandleIncoming 6 | fun ref new_peer(p: _SocketPeer) => None 7 | fun ref lost_peer(p: _SocketPeer) => None 8 | fun apply(p: _SocketPeer, m: Message)? 9 | 10 | class _HandleIncomingAllPeers is _HandleIncoming 11 | """ 12 | Never discard messages. 13 | """ 14 | fun apply(p: _SocketPeer, m: Message) => None 15 | 16 | class _HandleIncomingSinglePeer is _HandleIncoming 17 | """ 18 | Discard messages that don't come from the single most recently activated peer. 19 | """ 20 | var _peer: (_SocketPeer | None) = None 21 | fun ref new_peer(p: _SocketPeer) => _peer = p 22 | fun ref lost_peer(p: _SocketPeer) => _peer = None 23 | fun apply(p: _SocketPeer, m: Message)? => 24 | if not (p is _peer) then error end 25 | 26 | class _HandleIncomingDiscard is _HandleIncoming 27 | """ 28 | Discard all messages. 29 | """ 30 | fun apply(p: _SocketPeer, m: Message)? => 31 | error 32 | -------------------------------------------------------------------------------- /zmq/_handle_outgoing.pony: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | use "collections" 6 | 7 | interface _HandleOutgoing 8 | fun ref new_peer(p: _SocketPeer) => None 9 | fun ref lost_peer(p: _SocketPeer) => None 10 | fun ref apply(m: Message)? 11 | 12 | class _HandleOutgoingAllPeers is _HandleOutgoing 13 | """ 14 | Route each outgoing message to all active peers. 15 | """ 16 | let _peers: List[_SocketPeer] = _peers.create() 17 | 18 | fun ref new_peer(p: _SocketPeer) => _peers.push(p) 19 | 20 | fun ref lost_peer(p: _SocketPeer) => 21 | for node in _peers.nodes() do 22 | try 23 | if node()? is p then 24 | node.remove() 25 | return 26 | end 27 | end 28 | end 29 | 30 | fun ref apply(m: Message) => 31 | for peer in _peers.values() do 32 | peer.send(m) 33 | end 34 | 35 | class _HandleOutgoingRoundRobin is _HandleOutgoing 36 | """ 37 | Route each outgoing message to a different peer in a round-robin order. 38 | """ 39 | let _peers: List[_SocketPeer] = _peers.create() 40 | var _robin: USize = 0 // TODO: Linked-list-oriented implementation. 41 | 42 | fun ref new_peer(p: _SocketPeer) => _peers.push(p) 43 | 44 | fun ref lost_peer(p: _SocketPeer) => 45 | for node in _peers.nodes() do 46 | try 47 | if node()? is p then 48 | node.remove() 49 | return 50 | end 51 | end 52 | end 53 | 54 | fun ref apply(m: Message)? => 55 | (try _peers(_robin = _robin + 1)? 56 | else _robin = 1; _peers(0)? 57 | end).send(m) 58 | 59 | class _HandleOutgoingSubscribedPeers is _HandleOutgoing 60 | """ 61 | Route outgoing messages to peers with a subscription matching the first frame. 62 | """ 63 | fun ref apply(m: Message) => None 64 | 65 | class _HandleOutgoingRoutingFrame is _HandleOutgoing 66 | """ 67 | Route outgoing messages using the first frame as a peer identity. 68 | """ 69 | fun ref apply(m: Message) => None 70 | 71 | class _HandleOutgoingSinglePeer is _HandleOutgoing 72 | """ 73 | Route all outgoing messages to the most recently activated peer. 74 | """ 75 | var _peer: (_SocketPeer | None) = None 76 | fun ref new_peer(p: _SocketPeer) => _peer = p 77 | fun ref lost_peer(p: _SocketPeer) => _peer = None 78 | fun ref apply(m: Message)? => 79 | (_peer as _SocketPeer).send(m) 80 | 81 | class _HandleOutgoingDiscard is _HandleOutgoing 82 | """ 83 | Discard all messages. 84 | """ 85 | fun ref apply(m: Message) => None 86 | -------------------------------------------------------------------------------- /zmq/_message_queue.pony: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | use "collections" 6 | use zmtp = "zmtp" 7 | 8 | interface tag _MessageQueueWritable 9 | be write(data: ByteSeq) 10 | 11 | class _MessageQueue 12 | let _inner: List[Message] = _inner.create() 13 | var _empty: Bool = true 14 | var _write_transform: _MessageWriteTransform = recover zmtp.MessageWriter end 15 | 16 | fun ref set_write_transform(writex: _MessageWriteTransform) => 17 | _write_transform = consume writex 18 | 19 | fun ref push(message: Message) => 20 | """ 21 | Push a message to send at the next flush. 22 | """ 23 | _inner.push(message) 24 | _empty = false 25 | 26 | fun ref flush(target: _MessageQueueWritable) => 27 | """ 28 | Send all queued messages to target. 29 | """ 30 | if _empty then return end 31 | while true do 32 | let msg = try _inner.shift()? else (_empty = true; return) end 33 | target.write(_write_transform(msg)) 34 | end 35 | 36 | fun ref send(message: Message, target: (_MessageQueueWritable | None), active: Bool) => 37 | """ 38 | If active and target is not None, send message to target, else push for later. 39 | """ 40 | if active then 41 | match target | let target': _MessageQueueWritable => 42 | flush(target') 43 | target'.write(_write_transform(message)) 44 | else 45 | push(message) 46 | end 47 | else 48 | push(message) 49 | end 50 | 51 | interface tag _MessageQueueSimpleReceivable 52 | be received(message: Message) 53 | 54 | // TODO: Remove this class and reconcile with refactored _MessageQueue above. 55 | class _MessageQueueSimple 56 | let _inner: List[Message] = _inner.create() 57 | var _empty: Bool = true 58 | 59 | fun ref push(message: Message) => 60 | """ 61 | Push a message to send at the next flush. 62 | """ 63 | _inner.push(message) 64 | _empty = false 65 | 66 | fun ref flush(target: _MessageQueueSimpleReceivable) => 67 | """ 68 | Send all queued messages to target. 69 | """ 70 | if _empty then return end 71 | while true do 72 | let msg = try _inner.shift()? else (_empty = true; return) end 73 | target.received(msg) 74 | end 75 | 76 | fun ref send(message: Message, target: (_MessageQueueSimpleReceivable | None), active: Bool) => 77 | """ 78 | If active and target is not None, send message to target, else push for later. 79 | """ 80 | if active then 81 | match target | let target': _MessageQueueSimpleReceivable => 82 | flush(target') 83 | target'.received(message) 84 | else 85 | push(message) 86 | end 87 | else 88 | push(message) 89 | end 90 | -------------------------------------------------------------------------------- /zmq/_observe_incoming.pony: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | interface val _ObserveIncoming 6 | fun tag observe() => None // TODO: flesh out this interface 7 | 8 | primitive _ObserveIncomingNone is _ObserveIncoming 9 | primitive _ObserveIncomingRoutingFrame is _ObserveIncoming 10 | primitive _ObserveIncomingSubscriptionFilter is _ObserveIncoming 11 | -------------------------------------------------------------------------------- /zmq/_observe_outgoing.pony: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | interface val _ObserveOutgoing 6 | fun tag observe() => None // TODO: flesh out this interface 7 | 8 | primitive _ObserveOutgoingNone is _ObserveOutgoing 9 | primitive _ObserveOutgoingRoutingFrame is _ObserveOutgoing 10 | -------------------------------------------------------------------------------- /zmq/_reconnect_timer.pony: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | use "time" 6 | 7 | interface tag _ReconnectTimerNotifiable 8 | be _reconnect_timer_fire() 9 | 10 | class _ReconnectTimerNotify is TimerNotify 11 | let _parent: _ReconnectTimerNotifiable 12 | new iso create(parent: _ReconnectTimerNotifiable) => 13 | _parent = parent 14 | fun ref apply(timer: Timer, count: U64): Bool => 15 | _parent._reconnect_timer_fire() 16 | false 17 | -------------------------------------------------------------------------------- /zmq/_session_keeper.pony: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | use buffered = "buffered" 6 | use z85 = "z85" 7 | use zmtp = "zmtp" 8 | use "sodium" 9 | 10 | class _SessionKeeper 11 | let _socket_opts: SocketOptions val 12 | 13 | let _session: zmtp.Session = zmtp.Session 14 | let _buffer: buffered.Reader = buffered.Reader 15 | 16 | new create(socket_opts: SocketOptions val) => 17 | _socket_opts = socket_opts 18 | 19 | fun ref start(notify': zmtp.SessionNotify) => 20 | _buffer.clear() 21 | _session.start(this, notify', _make_mechanism()) 22 | 23 | fun _make_curve_key(key: String): String? => 24 | match key.size() 25 | | 40 => z85.Z85.decode(key)? 26 | | 32 => key 27 | else error 28 | end 29 | 30 | fun ref _make_curve_mechanism(): zmtp.Mechanism? => 31 | let pk = CryptoBoxPublicKey(_make_curve_key( 32 | CurvePublicKey.find_in(_socket_opts))?) 33 | let sk = CryptoBoxSecretKey(_make_curve_key( 34 | CurveSecretKey.find_in(_socket_opts))?) 35 | if CurveAsServer.find_in(_socket_opts) then 36 | return zmtp.MechanismAuthCurveServer(_session, sk, pk) 37 | else 38 | let pks = CryptoBoxPublicKey(_make_curve_key( 39 | CurvePublicKeyOfServer.find_in(_socket_opts))?) 40 | return zmtp.MechanismAuthCurveClient(_session, sk, pk, pks) 41 | end 42 | 43 | fun ref _make_mechanism(): zmtp.Mechanism => 44 | try _make_curve_mechanism()? 45 | else zmtp.MechanismAuthNull.create(_session) 46 | end 47 | 48 | fun ref handle_input(data: Array[U8] iso) => 49 | _buffer.append(consume data) 50 | _session.handle_input(_buffer) 51 | 52 | fun ref handle_zap_response(zap: _ZapResponse) => 53 | _session.handle_zap_response(zap) 54 | 55 | fun _socket_type(): SocketType => 56 | _SocketTypeAsSocketOption.find_in(_socket_opts) 57 | 58 | /// 59 | // Convenience methods for the underlying session 60 | 61 | fun as_server(): Bool => 62 | CurveAsServer.find_in(_socket_opts) 63 | 64 | fun auth_mechanism(): String => 65 | try _make_curve_key(CurveSecretKey.find_in(_socket_opts))? 66 | _make_curve_key(CurvePublicKey.find_in(_socket_opts))? 67 | "CURVE" 68 | else 69 | "NULL" 70 | end 71 | 72 | fun socket_type_string(): String => 73 | _socket_type().string() 74 | 75 | fun socket_type_accepts(string: String): Bool => 76 | _socket_type().accepts(string) 77 | -------------------------------------------------------------------------------- /zmq/_socket_bind_inproc.pony: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | actor _SocketBindInProc 6 | let _parent: Socket 7 | let _socket_opts: SocketOptions val 8 | 9 | new create(parent: Socket, socket_opts: SocketOptions val, endpoint: BindInProc) 10 | => 11 | _parent = parent 12 | _socket_opts = socket_opts 13 | endpoint._get_ctx()._inproc_bind(endpoint._get_path(), this) 14 | 15 | be accept_connection(peer: _SocketPeerInProc) => 16 | let peer' = _SocketPeerInProcBound(_parent, _socket_opts) 17 | peer'.activated(peer) 18 | peer.activated(peer') 19 | 20 | be dispose() => 21 | None 22 | 23 | actor _SocketPeerInProcBound 24 | let _parent: Socket 25 | let _socket_opts: SocketOptions val 26 | 27 | var _peer: (_SocketPeerInProc | None) = None 28 | var _active: Bool = false 29 | 30 | let _messages: _MessageQueueSimple = _MessageQueueSimple 31 | 32 | new create(parent: Socket, socket_opts: SocketOptions val) 33 | => 34 | _parent = parent 35 | _socket_opts = socket_opts 36 | 37 | be dispose() => 38 | _active = false 39 | 40 | be activated(peer: _SocketPeerInProc) => 41 | _peer = peer 42 | _active = true 43 | _parent._connected(this) 44 | _messages.flush(peer) 45 | 46 | be received(message: Message) => 47 | _parent._received(this, message) 48 | 49 | be send(message: Message) => 50 | _messages.send(message, _peer, _active) 51 | -------------------------------------------------------------------------------- /zmq/_socket_bind_tcp.pony: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | use "net" 6 | use zmtp = "zmtp" 7 | 8 | actor _SocketBindTCP 9 | var _inner: TCPListener 10 | new create(parent: Socket, socket_opts: SocketOptions val, endpoint: BindTCP) => 11 | _inner = TCPListener( 12 | endpoint._get_auth(), 13 | _SocketBindTCPListenNotify(parent, socket_opts), 14 | endpoint._get_host(), 15 | endpoint._get_port()) 16 | be dispose() => 17 | _inner.dispose() 18 | 19 | class _SocketBindTCPListenNotify is TCPListenNotify 20 | let _parent: Socket 21 | let _socket_opts: SocketOptions val 22 | 23 | new iso create(parent: Socket, socket_opts: SocketOptions val) => 24 | _parent = parent 25 | _socket_opts = socket_opts 26 | 27 | fun ref connected(listen: TCPListener ref): TCPConnectionNotify iso^ => 28 | _SocketTCPNotify(_SocketPeerTCPBound(_parent, _socket_opts)) 29 | 30 | fun ref not_listening(listen: TCPListener ref) => None // TODO 31 | 32 | actor _SocketPeerTCPBound is (_SocketTCPNotifiable & zmtp.SessionNotify) 33 | let _parent: Socket 34 | let _socket_opts: SocketOptions val 35 | var _inner: (_SocketTCPTarget | None) = None 36 | var _active: Bool 37 | let _messages: _MessageQueue = _MessageQueue 38 | let _session: _SessionKeeper 39 | 40 | new create(parent: Socket, socket_opts: SocketOptions val) => 41 | _parent = parent 42 | _socket_opts = socket_opts 43 | _inner = None 44 | _active = false 45 | _session = _SessionKeeper(socket_opts) 46 | 47 | be dispose() => 48 | try (_inner as _SocketTCPTarget).dispose() end 49 | _inner = None 50 | _active = false 51 | 52 | be send(message: Message) => 53 | _messages.send(message, _inner, _active) 54 | 55 | /// 56 | // _SocketTCPNotifiable interface behaviors 57 | 58 | be notify_start(target: _SocketTCPTarget) => 59 | _inner = target 60 | _session.start(this) 61 | 62 | be notify_input(data: Array[U8] iso) => 63 | _session.handle_input(consume data) 64 | 65 | be notify_closed() => 66 | dispose() 67 | 68 | be notify_connect_failed() => 69 | dispose() 70 | 71 | /// 72 | // Zap support helper behaviours 73 | 74 | be notify_zap_response(zap: _ZapResponse) => 75 | _session.handle_zap_response(zap) 76 | 77 | /// 78 | // Session handler methods 79 | 80 | fun ref activated(writex: _MessageWriteTransform) => 81 | _active = true 82 | _parent._connected(this) 83 | _messages.set_write_transform(consume writex) 84 | try _messages.flush(_inner as _SocketTCPTarget) end 85 | 86 | fun ref protocol_error(string: String) => 87 | dispose() 88 | _parent._protocol_error(this, string) 89 | 90 | fun ref write(bytes: ByteSeq) => 91 | try (_inner as _SocketTCPTarget).write(bytes) end 92 | 93 | fun ref received(message: Message) => 94 | _parent._received(this, message) 95 | 96 | fun ref zap_request(zap: _ZapRequest) => 97 | let t: _SocketPeerTCPBound = this 98 | let respond: _ZapRespond = 99 | {(res: _ZapResponse) => t.notify_zap_response(res) } val 100 | 101 | let handler = ZapHandler.find_in(_socket_opts) 102 | try (handler as _ZapRequestNotifiable).handle_zap_request(zap, respond) 103 | else notify_zap_response(_ZapResponse) // no handler, so respond with 200 OK 104 | end 105 | -------------------------------------------------------------------------------- /zmq/_socket_peer_inproc.pony: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | actor _SocketPeerInProc 6 | let _parent: Socket 7 | let _socket_opts: SocketOptions val 8 | 9 | var _peer: (_SocketPeerInProcBound | None) = None 10 | var _active: Bool = false 11 | 12 | let _messages: _MessageQueueSimple = _MessageQueueSimple 13 | 14 | new create(parent: Socket, socket_opts: SocketOptions val, endpoint: ConnectInProc) => 15 | _parent = parent 16 | _socket_opts = socket_opts 17 | endpoint._get_ctx()._inproc_connect(endpoint._get_path(), this) 18 | 19 | be dispose() => 20 | _active = false 21 | 22 | be activated(peer: _SocketPeerInProcBound) => 23 | _peer = peer 24 | _active = true 25 | _parent._connected(this) 26 | _messages.flush(peer) 27 | 28 | be received(message: Message) => 29 | _parent._received(this, message) 30 | 31 | be send(message: Message) => 32 | _messages.send(message, _peer, _active) 33 | -------------------------------------------------------------------------------- /zmq/_socket_peer_tcp.pony: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | use "time" 6 | use "net" 7 | use zmtp = "zmtp" 8 | 9 | actor _SocketPeerTCP is (_SocketTCPNotifiable & zmtp.SessionNotify) 10 | let _parent: Socket 11 | let _socket_opts: SocketOptions val 12 | let _endpoint: ConnectTCP 13 | var _inner: (_SocketTCPTarget | None) = None 14 | let _session: _SessionKeeper 15 | 16 | var _active: Bool = false 17 | var _disposed: Bool = false 18 | 19 | let _messages: _MessageQueue = _MessageQueue 20 | 21 | var _reconnect_timer: (Timer tag | None) = None 22 | 23 | new create(parent: Socket, socket_opts: SocketOptions val, endpoint: ConnectTCP) => 24 | _parent = parent 25 | _socket_opts = socket_opts 26 | _endpoint = endpoint 27 | _inner = TCPConnection( 28 | _endpoint._get_auth(), 29 | _SocketTCPNotify(this), 30 | _endpoint._get_host(), 31 | _endpoint._get_port()) 32 | _session = _SessionKeeper(socket_opts) 33 | 34 | be dispose() => 35 | try (_inner as _SocketTCPTarget).dispose() end 36 | _inner = None 37 | _active = false 38 | _disposed = true 39 | 40 | be send(message: Message) => 41 | _messages.send(message, _inner, _active) 42 | 43 | fun ref _reconnect_later() => 44 | try (_inner as _SocketTCPTarget).dispose() end 45 | _inner = None 46 | let ns = _reconnect_interval_ns() 47 | _parent.set_timer(Timer(_ReconnectTimerNotify(this), ns, ns)) 48 | 49 | fun _reconnect_interval_ns(): U64 => 50 | (ReconnectInterval.find_in(_socket_opts) * 1e9).u64() 51 | 52 | be _reconnect_timer_fire() => 53 | if not _active and not _disposed then 54 | _inner = TCPConnection( 55 | _endpoint._get_auth(), 56 | _SocketTCPNotify(this), 57 | _endpoint._get_host(), 58 | _endpoint._get_port()) 59 | end 60 | 61 | /// 62 | // _SocketTCPNotifiable interface behaviors 63 | 64 | be notify_start(target: _SocketTCPTarget) => 65 | _inner = target 66 | _session.start(this) 67 | 68 | be notify_input(data: Array[U8] iso) => 69 | _session.handle_input(consume data) 70 | 71 | be notify_closed() => 72 | _active = false 73 | if not _disposed then _reconnect_later() end 74 | 75 | be notify_connect_failed() => 76 | _active = false 77 | _reconnect_later() 78 | 79 | /// 80 | // Zap support helper behaviours 81 | 82 | be notify_zap_response(zap: _ZapResponse) => 83 | _session.handle_zap_response(zap) 84 | 85 | /// 86 | // Session handler methods 87 | 88 | fun ref activated(writex: _MessageWriteTransform) => 89 | _active = true 90 | _parent._connected(this) 91 | _messages.set_write_transform(consume writex) 92 | try _messages.flush(_inner as _SocketTCPTarget) end 93 | 94 | fun ref protocol_error(string: String) => 95 | _active = false 96 | _reconnect_later() 97 | _parent._protocol_error(this, string) 98 | 99 | fun ref write(bytes: ByteSeq) => 100 | try (_inner as _SocketTCPTarget).write(bytes) end 101 | 102 | fun ref received(message: Message) => 103 | _parent._received(this, message) 104 | 105 | fun ref zap_request(zap: _ZapRequest) => 106 | let t: _SocketPeerTCP = this 107 | let respond: _ZapRespond = 108 | {(res: _ZapResponse) => t.notify_zap_response(res) } val 109 | 110 | let handler = ZapHandler.find_in(_socket_opts) 111 | try (handler as _ZapRequestNotifiable).handle_zap_request(zap, respond) 112 | else notify_zap_response(_ZapResponse) // no handler, so respond with 200 OK 113 | end 114 | -------------------------------------------------------------------------------- /zmq/_socket_tcp_notify.pony: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | use "net" 6 | use zmtp = "zmtp" 7 | 8 | interface tag _SocketTCPTarget is _MessageQueueWritable 9 | be dispose() 10 | 11 | interface tag _SocketTCPNotifiable 12 | be notify_start(target: _SocketTCPTarget) 13 | be notify_input(data: Array[U8] iso) 14 | be notify_closed() 15 | be notify_connect_failed() 16 | 17 | class _SocketTCPNotify is TCPConnectionNotify 18 | let _parent: _SocketTCPNotifiable 19 | 20 | new iso create(parent: _SocketTCPNotifiable) => 21 | _parent = parent 22 | 23 | fun ref accepted(conn: TCPConnection ref) => 24 | _parent.notify_start(conn) 25 | 26 | fun ref connected(conn: TCPConnection ref) => 27 | _parent.notify_start(conn) 28 | 29 | fun ref connect_failed(conn: TCPConnection ref) => 30 | _parent.notify_connect_failed() 31 | 32 | fun ref closed(conn: TCPConnection ref) => 33 | _parent.notify_closed() 34 | 35 | fun ref received(conn: TCPConnection ref, data: Array[U8] iso, 36 | times: USize): Bool 37 | => 38 | _parent.notify_input(consume data) 39 | true 40 | -------------------------------------------------------------------------------- /zmq/_zap.pony: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | use zmtp = "zmtp" 6 | 7 | type _ZapRequest is zmtp.ZapRequest 8 | type _ZapResponse is zmtp.ZapResponse 9 | 10 | type _ZapRequestNotifiable is zmtp.ZapRequestNotifiable 11 | type _ZapRespond is zmtp.ZapRespond 12 | -------------------------------------------------------------------------------- /zmq/bind.pony: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | use "collections" 6 | use "net" 7 | 8 | trait val Bind is (Equatable[Bind] & Hashable) 9 | 10 | class val BindInProc is Bind 11 | let _ctx: Context 12 | let _path: String 13 | 14 | new val create(ctx': Context, path': String) => 15 | _ctx = ctx'; _path = path' 16 | 17 | fun _get_ctx(): Context => _ctx 18 | fun _get_path(): String => _path 19 | 20 | fun hash(): USize => (digestof _ctx).hash() xor _path.hash() 21 | fun eq(that': Bind): Bool => 22 | match that' | let that: BindInProc => 23 | (_ctx is that._ctx) and (_path == that._path) 24 | else false 25 | end 26 | 27 | type _BindTCPAuth is (AmbientAuth | NetAuth | TCPAuth | TCPListenAuth) 28 | class val BindTCP is Bind 29 | let _auth: _BindTCPAuth 30 | let _host: String 31 | let _port: String 32 | 33 | new val create(auth': _BindTCPAuth, host': String, port': String) => 34 | _auth = auth'; _host = host'; _port = port' 35 | 36 | fun _get_auth(): _BindTCPAuth => _auth 37 | fun _get_host(): String => _host 38 | fun _get_port(): String => _port 39 | 40 | fun hash(): USize => _host.hash() xor _port.hash() 41 | fun eq(that': Bind): Bool => 42 | match that' | let that: BindTCP => 43 | (_host == that._host) and (_port == that._port) 44 | else false 45 | end 46 | -------------------------------------------------------------------------------- /zmq/connect.pony: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | use "collections" 6 | use "net" 7 | 8 | trait val Connect is (Equatable[Connect] & Hashable) 9 | 10 | class val ConnectInProc is Connect 11 | let _ctx: Context 12 | let _path: String 13 | 14 | new val create(ctx': Context, path': String) => 15 | _ctx = ctx'; _path = path' 16 | 17 | fun _get_ctx(): Context => _ctx 18 | fun _get_path(): String => _path 19 | 20 | fun hash(): USize => (digestof _ctx).hash() xor _path.hash() 21 | fun eq(that': Connect): Bool => 22 | match that' | let that: ConnectInProc => 23 | (_ctx is that._ctx) and (_path == that._path) 24 | else false 25 | end 26 | 27 | type _ConnectTCPAuth is (AmbientAuth | NetAuth | TCPAuth | TCPConnectAuth) 28 | class val ConnectTCP is Connect 29 | let _auth: _ConnectTCPAuth 30 | let _host: String 31 | let _port: String 32 | 33 | new val create(auth': _ConnectTCPAuth, host': String, port': String) => 34 | _auth = auth'; _host = host'; _port = port' 35 | 36 | fun _get_auth(): _ConnectTCPAuth => _auth 37 | fun _get_host(): String => _host 38 | fun _get_port(): String => _port 39 | 40 | fun hash(): USize => _host.hash() xor _port.hash() 41 | fun eq(that': Connect): Bool => 42 | match that' | let that: ConnectTCP => 43 | (_host == that._host) and (_port == that._port) 44 | else false 45 | end 46 | -------------------------------------------------------------------------------- /zmq/context.pony: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | use "collections" 6 | 7 | actor Context 8 | let _ready_binds: Map[String, _SocketBindInProc] = _ready_binds.create() 9 | let _ready_peers: Map[String, List[_SocketPeerInProc]] = _ready_peers.create() 10 | 11 | be _inproc_bind(string: String, bind: _SocketBindInProc) => 12 | // If there is not already a bind for this string 13 | if not _ready_binds.contains(string) then 14 | // Set this bind as the bind for this string 15 | _ready_binds(string) = bind 16 | 17 | // Connect peers that are already waiting for a bind 18 | try let peers = _ready_peers(string)? 19 | for peer in peers.values() do 20 | bind.accept_connection(peer) 21 | end 22 | end 23 | end 24 | 25 | be _inproc_connect(string: String, peer: _SocketPeerInProc) => 26 | // Add this peer to peer list for this string 27 | let peer_list = try _ready_peers(string)? else 28 | let list = List[_SocketPeerInProc] 29 | _ready_peers(string) = list 30 | list 31 | end 32 | peer_list.push(peer) 33 | 34 | // Connect to a bind if there is one available 35 | try _ready_binds(string)?.accept_connection(peer) end 36 | -------------------------------------------------------------------------------- /zmq/message.pony: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | use zmtp = "zmtp" 6 | 7 | type Message is zmtp.Message 8 | type MessageFrame is zmtp.Frame 9 | type _MessageParser is zmtp.MessageParser 10 | type _MessageWriteTransform is zmtp.MessageWriteTransform 11 | -------------------------------------------------------------------------------- /zmq/socket.pony: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | use "collections" 6 | use "time" 7 | use "inspect" 8 | 9 | interface tag SocketPeer // public, limited 10 | be send(message: Message) 11 | 12 | interface tag _SocketPeer 13 | be send(message: Message) 14 | be dispose() 15 | 16 | interface tag _SocketBind 17 | be dispose() 18 | 19 | interface val SocketAccessLambda 20 | fun val apply(socket: Socket ref) 21 | 22 | actor Socket 23 | let _notify: SocketNotify 24 | 25 | let _peers: Map[Connect, _SocketPeer] = _peers.create() 26 | let _binds: Map[Bind, _SocketBind] = _binds.create() 27 | let _bind_peers: MapIs[_SocketBind, List[_SocketPeer]] = _bind_peers.create() 28 | 29 | let _timers: Timers = _timers.create() 30 | let _outgoing: List[Message] = _outgoing.create() 31 | 32 | let _socket_opts: SocketOptions = _socket_opts.create() 33 | 34 | let _handle_in: _HandleIncoming 35 | let _handle_out: _HandleOutgoing 36 | let _observe_in: _ObserveIncoming 37 | let _observe_out: _ObserveOutgoing 38 | 39 | new create(socket_type: SocketType, notify: SocketNotify = SocketNotifyNone) => 40 | _notify = notify 41 | _handle_in = socket_type.handle_incoming() 42 | _handle_out = socket_type.handle_outgoing() 43 | _observe_in = socket_type.observe_incoming() 44 | _observe_out = socket_type.observe_outgoing() 45 | _SocketOptionsUtil.set_in(_SocketTypeAsSocketOption(socket_type), _socket_opts) 46 | 47 | be dispose() => 48 | _timers.dispose() 49 | for peer in _peers.values() do 50 | peer.dispose() 51 | end 52 | for peer in _binds.values() do 53 | peer.dispose() 54 | end 55 | for peers in _bind_peers.values() do 56 | for peer in peers.values() do 57 | peer.dispose() 58 | end 59 | end 60 | _notify.closed(this) 61 | 62 | fun _socket_opts_clone(): SocketOptions iso^ => 63 | let clone = recover iso SocketOptions end 64 | for v in _socket_opts.values() do 65 | clone.push(v) 66 | end 67 | clone 68 | 69 | fun _make_peer(endpoint: Connect): _SocketPeer? => 70 | match endpoint 71 | | let e: ConnectTCP => _SocketPeerTCP(this, _socket_opts_clone(), e) 72 | | let e: ConnectInProc => _SocketPeerInProc(this, _socket_opts_clone(), e) 73 | else error 74 | end 75 | 76 | fun _make_bind(endpoint: Bind): _SocketBind? => 77 | match endpoint 78 | | let e: BindTCP => _SocketBindTCP(this, _socket_opts_clone(), e) 79 | | let e: BindInProc => _SocketBindInProc(this, _socket_opts_clone(), e) 80 | else error 81 | end 82 | 83 | be access(f: SocketAccessLambda) => 84 | (consume f)(this) 85 | 86 | be set(optval: SocketOptionWithValue) => set_now(optval) 87 | fun ref set_now(optval: SocketOptionWithValue) => 88 | _SocketOptionsUtil.set_in(optval, _socket_opts) 89 | 90 | be apply(action: (Bind | Connect)) => apply_now(action) 91 | fun ref apply_now(action: (Bind | Connect)) => 92 | match action 93 | | let e: Bind => 94 | if not _binds.contains(e) then 95 | _binds(e) = try _make_bind(e)? else return end 96 | end 97 | | let e: Connect => 98 | if not _peers.contains(e) then 99 | let peer = try _make_peer(e)? else return end 100 | _peers(e) = peer 101 | _new_peer(peer) 102 | end 103 | end 104 | 105 | be send(message: Message) => send_now(message) 106 | fun ref send_now(message: Message) => 107 | _outgoing.push(message) 108 | _maybe_send_messages() 109 | 110 | be set_timer(timer: Timer iso) => 111 | _timers(consume timer) 112 | 113 | be _protocol_error(peer: _SocketPeer, string: String) => 114 | Inspect.print("_protocol_error: " + string) 115 | 116 | be _connected(peer: _SocketPeer) => 117 | _new_peer(peer) 118 | _maybe_send_messages() 119 | 120 | be _received(peer: _SocketPeer, message: Message) => 121 | try _handle_in(peer, message)? 122 | _notify.received(this, peer, consume message) 123 | end 124 | 125 | be _connected_from_bind(bind': _SocketBind, peer: _SocketPeer) => 126 | (try _bind_peers(bind')? else 127 | let list = List[_SocketPeer] 128 | _bind_peers(bind') = list 129 | list 130 | end).push(peer) 131 | _new_peer(peer) 132 | 133 | be _bind_closed(bind': _SocketBind) => 134 | for (key, other) in _binds.pairs() do 135 | if other is bind' then 136 | try _binds.remove(key)? end 137 | end 138 | end 139 | try 140 | for peer in _bind_peers(bind')?.values() do 141 | _lost_peer(peer) 142 | end 143 | end 144 | bind'.dispose() 145 | 146 | fun ref _maybe_send_messages() => 147 | try while true do 148 | let m = _outgoing.shift()? 149 | try _handle_out(m)? 150 | else _outgoing.unshift(m) 151 | error 152 | end 153 | end end 154 | 155 | fun ref _new_peer(peer: _SocketPeer) => 156 | _handle_in.new_peer(peer) 157 | _handle_out.new_peer(peer) 158 | _notify.new_peer(this, peer) 159 | 160 | fun ref _lost_peer(peer: _SocketPeer) => 161 | _handle_in.lost_peer(peer) 162 | _handle_out.lost_peer(peer) 163 | _notify.lost_peer(this, peer) 164 | peer.dispose() 165 | -------------------------------------------------------------------------------- /zmq/socket_notify.pony: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | interface val SocketNotify 6 | fun val received(socket: Socket, peer: SocketPeer, message: Message) => 7 | """ 8 | Called when a new message is received from a peer. 9 | """ 10 | None 11 | 12 | fun val new_peer(socket: Socket, peer: SocketPeer) => 13 | """ 14 | Called when a new peer is added to the Socket. 15 | """ 16 | None 17 | 18 | fun val lost_peer(socket: Socket, peer: SocketPeer) => 19 | """ 20 | Called when a peer is removed from the Socket. 21 | """ 22 | None 23 | 24 | fun val closed(socket: Socket) => 25 | """ 26 | Called when the socket is closed. 27 | """ 28 | None 29 | 30 | class val SocketNotifyNone is SocketNotify 31 | new val create() => None 32 | 33 | interface tag SocketNotifiableActor 34 | be received(socket: Socket, peer: SocketPeer, message: Message) => None 35 | be new_peer(socket: Socket, peer: SocketPeer) => None 36 | be lost_peer(socket: Socket, peer: SocketPeer) => None 37 | be closed(socket: Socket) => None 38 | 39 | class val SocketNotifyActor is SocketNotify 40 | let _parent: SocketNotifiableActor 41 | new val create(parent: SocketNotifiableActor) => _parent = parent 42 | 43 | fun val received(s: Socket, p: SocketPeer, m: Message) => _parent.received(s, p, m) 44 | fun val new_peer(s: Socket, p: SocketPeer) => _parent.new_peer(s, p) 45 | fun val lost_peer(s: Socket, p: SocketPeer) => _parent.lost_peer(s, p) 46 | fun val closed(s: Socket) => _parent.closed(s) 47 | 48 | -------------------------------------------------------------------------------- /zmq/socket_options.pony: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | use "collections" 6 | 7 | /// 8 | // Generic structures 9 | 10 | interface tag SocketOption[A: Any #share] 11 | fun tag apply(value: A): _SocketOptionWithValue[A] => 12 | _SocketOptionWithValue[A](this, value) 13 | 14 | fun tag default(): A 15 | fun tag validate(value: A)? => None 16 | fun tag validate_error(): String => "Invalid socket option value." 17 | 18 | fun tag find_in(list: SocketOptions box): A => 19 | try 20 | var iter = list.values() 21 | while iter.has_next() do 22 | try var optval = iter.next()? as _SocketOptionWithValue[A] 23 | if optval.option_tag() is this then 24 | return optval.value 25 | end 26 | end 27 | end 28 | error 29 | else 30 | default() 31 | end 32 | 33 | fun tag set_in(list: SocketOptions, value: A): Bool => 34 | _SocketOptionsUtil.set_in(apply(value), list) 35 | 36 | class val _SocketOptionWithValue[A: Any #share] is SocketOptionWithValue 37 | let option: SocketOption[A] 38 | let value: A 39 | fun option_tag(): Any tag => option 40 | fun validate(): None? => option.validate(value)? 41 | new val create(option': SocketOption[A], value': A) => 42 | option = option' 43 | value = value' 44 | 45 | interface val SocketOptionWithValue 46 | fun option_tag(): Any tag 47 | fun validate(): None? 48 | 49 | type SocketOptions is List[SocketOptionWithValue] 50 | 51 | primitive _SocketOptionsUtil 52 | fun val set_in(this_opt: SocketOptionWithValue, list: SocketOptions): Bool => 53 | try this_opt.validate()? else return false end 54 | 55 | for other_node in list.nodes() do 56 | try 57 | let other = other_node()? 58 | if other.option_tag() is this_opt.option_tag() then 59 | other_node.remove() 60 | end 61 | end 62 | end 63 | 64 | list.push(this_opt) 65 | true 66 | 67 | /// 68 | // Internal-only socket options 69 | 70 | primitive _SocketTypeAsSocketOption is SocketOption[SocketType] 71 | fun tag default(): SocketType => PAIR 72 | 73 | /// 74 | // Socket option shared behaviors 75 | 76 | interface _SocketOptionCurveKey is SocketOption[String] 77 | fun tag default(): String => "" 78 | fun tag validate(value: String)? => 79 | match value.size() 80 | | 0 | 32 | 40 => true // TODO: validate Z85 encoding when size == 40 81 | else error 82 | end 83 | fun tag validate_error(): String => 84 | "CURVE keys must be either 32-byte binary or 40-byte Z85-encoded strings." 85 | 86 | /// 87 | // Socket options 88 | 89 | primitive CurveAsServer is SocketOption[Bool] 90 | """ 91 | Indicates that the socket should act as a server for CURVE encryption. 92 | If set to true, the other socket must act as a client, and must know the 93 | public key of the server socket prior to connecting. 94 | """ 95 | fun tag default(): Bool => false 96 | 97 | primitive CurvePublicKey is _SocketOptionCurveKey 98 | """ 99 | The local public key to use for CURVE encryption, as a string. 100 | Both the server and the client socket must set a public key, 101 | which may be distributed to others to establish a trusted identity. 102 | Each public key is associated with a secret key, which must be 103 | kept secret to maintain security. 104 | """ 105 | 106 | primitive CurveSecretKey is _SocketOptionCurveKey 107 | """ 108 | The local secret key to use for CURVE encryption, as a string. 109 | Both the server and the client socket must set a secret key, 110 | and must keep their secret key secret to maintain security. 111 | Each secret key is associated with a public key, which may be 112 | distributed to others to establish a trusted identity. 113 | """ 114 | 115 | primitive CurvePublicKeyOfServer is _SocketOptionCurveKey 116 | """ 117 | The expected public key of the remote server when using CURVE encryption. 118 | The client socket must set this option before connecting to a server 119 | and it must correlate to the secret key of the server socket 120 | for the CURVE encryption handshake to complete successfully. 121 | """ 122 | 123 | primitive HandshakeTimeout is SocketOption[F64] 124 | """ 125 | NOT YET IMPLEMENTED. 126 | The maximum time to allow for new connections to complete their handshake. 127 | Handshaking establishes the ZMTP protocol version, exchanges configuration 128 | between sockets, and establishes authentication or encryption when applicable. 129 | If handshake does not complete within the timeout, the connection is dropped. 130 | Values are given in seconds, with 0 indicating no time limit. 131 | """ 132 | fun tag default(): F64 => 30.0 133 | 134 | primitive HeartbeatInterval is SocketOption[F64] 135 | """ 136 | NOT YET IMPLEMENTED. 137 | NOT YET DOCUMENTED. 138 | """ 139 | fun tag default(): F64 => 0.0 140 | 141 | primitive HeartbeatTimeout is SocketOption[F64] 142 | """ 143 | NOT YET IMPLEMENTED. 144 | NOT YET DOCUMENTED. 145 | """ 146 | fun tag default(): F64 => 0.0 147 | 148 | primitive HeartbeatTTL is SocketOption[U64] 149 | """ 150 | NOT YET IMPLEMENTED. 151 | NOT YET DOCUMENTED. 152 | """ 153 | fun tag default(): U64 => 0 154 | 155 | primitive MaxMessageSize is SocketOption[U64] 156 | """ 157 | NOT YET IMPLEMENTED. 158 | The maximum size of message to receive, in bytes. 159 | A peer that sends a message larger than this size will be disconnected. 160 | A value of 0 indicates no size limit. 161 | """ 162 | fun tag default(): U64 => 0 163 | 164 | primitive MulticastMaxHops is SocketOption[U64] 165 | """ 166 | NOT YET IMPLEMENTED. 167 | NOT YET DOCUMENTED. 168 | """ 169 | fun tag default(): U64 => 0 170 | 171 | primitive MulticastMaxRate is SocketOption[U64] 172 | """ 173 | NOT YET IMPLEMENTED. 174 | NOT YET DOCUMENTED. 175 | """ 176 | fun tag default(): U64 => 0 177 | 178 | primitive MulticastRecoveryInterval is SocketOption[F64] 179 | """ 180 | NOT YET IMPLEMENTED. 181 | NOT YET DOCUMENTED. 182 | """ 183 | fun tag default(): F64 => 0 184 | 185 | primitive ProbeRouter is SocketOption[Bool] 186 | """ 187 | NOT YET IMPLEMENTED. 188 | If true, the socket will automatically send an empty message after 189 | completing a connection handshake with a ROUTER socket, providing the 190 | ROUTER application with a signal that a new peer has connected. 191 | """ 192 | fun tag default(): Bool => false 193 | 194 | primitive QueueOutgoingMax is SocketOption[U64] 195 | """ 196 | NOT YET IMPLEMENTED. 197 | NOT YET DOCUMENTED. 198 | """ 199 | fun tag default(): U64 => 0 200 | 201 | primitive ReconnectInterval is SocketOption[F64] 202 | """ 203 | NOT YET IMPLEMENTED. 204 | NOT YET DOCUMENTED. 205 | """ 206 | fun tag default(): F64 => 0.1 207 | 208 | primitive ReconnectIntervalMax is SocketOption[F64] 209 | """ 210 | NOT YET IMPLEMENTED. 211 | NOT YET DOCUMENTED. 212 | """ 213 | fun tag default(): F64 => 0.1 214 | 215 | primitive RouterHandover is SocketOption[Bool] 216 | """ 217 | NOT YET IMPLEMENTED. 218 | NOT YET DOCUMENTED. 219 | """ 220 | fun tag default(): Bool => false 221 | 222 | primitive RouterMandatory is SocketOption[Bool] 223 | """ 224 | NOT YET IMPLEMENTED. 225 | NOT YET DOCUMENTED. 226 | """ 227 | fun tag default(): Bool => false 228 | 229 | primitive RoutingIdentity is SocketOption[String] 230 | """ 231 | NOT YET IMPLEMENTED. 232 | NOT YET DOCUMENTED. 233 | """ 234 | fun tag default(): String => "" 235 | fun tag validate(value: String)? => 236 | if value.size() > 255 then error end 237 | fun tag validate_error(): String => 238 | "Routing identity strings may not be longer than 255 bytes." 239 | 240 | primitive Subscribe is SocketOption[String] 241 | """ 242 | NOT YET IMPLEMENTED. 243 | Add a string to the set of subscriptions received by a SUB socket. 244 | If the given string already exists in the set, the set is not changed. 245 | Messages whose first frame prefix-matches any of the subscribe set strings 246 | will be received by the SUB socket; all other messages will be filtered. 247 | If no subscriptions are added, the SUB socket will receive no messages. 248 | Subscribing with an empty string implies all messages should be received. 249 | """ 250 | fun tag default(): String => "" 251 | 252 | primitive SubscribeInverse is SocketOption[Bool] 253 | """ 254 | NOT YET IMPLEMENTED. 255 | If true, the semantics of the set of given subscribe strings are inverted. 256 | All messages which would otherwise be received will be filtered, and 257 | all messages which would otherwise be filtered will be received. 258 | """ 259 | fun tag default(): Bool => false 260 | 261 | primitive Unsubscribe is SocketOption[String] 262 | """ 263 | NOT YET IMPLEMENTED. 264 | Remove a string to the set of subscriptions received by a SUB socket. 265 | If the given string isn't currently in the set, the set is not changed. 266 | Messages whose first frame prefix-matches any of the subscribe set strings 267 | will be received by the SUB socket; all other messages will be filtered. 268 | If no subscriptions are added, the SUB socket will receive no messages. 269 | Subscribing with an empty string implies all messages should be received. 270 | """ 271 | fun tag default(): String => "" 272 | 273 | primitive XPubManual is SocketOption[Bool] 274 | """ 275 | NOT YET IMPLEMENTED. 276 | NOT YET DOCUMENTED. 277 | """ 278 | fun tag default(): Bool => false 279 | 280 | primitive XPubVerboseSubscribe is SocketOption[Bool] 281 | """ 282 | NOT YET IMPLEMENTED. 283 | If true, an XPUB will forward all subscription messages to the application. 284 | Otherwise, only additions to the subscription set will be forwarded. 285 | """ 286 | fun tag default(): Bool => false 287 | 288 | primitive XPubVerboseUnsubscribe is SocketOption[Bool] 289 | """ 290 | NOT YET IMPLEMENTED. 291 | If true, an XPUB will forward all unsubscription messages to the application. 292 | Otherwise, only removals from the subscription set will be forwarded. 293 | """ 294 | fun tag default(): Bool => false 295 | 296 | primitive XPubWelcomeMessage is SocketOption[(String | None)] 297 | """ 298 | NOT YET IMPLEMENTED. 299 | NOT YET DOCUMENTED. 300 | """ 301 | fun tag default(): (String | None) => None 302 | 303 | primitive ZapHandler is SocketOption[(_ZapRequestNotifiable | None)] 304 | """ 305 | An actor that is responsible for all remote sockets that try to handshake. 306 | Each handshake will cause a handle_zap_request message to be sent to the 307 | given ZAP handler actor, which is responsible for sending a response that 308 | indicates whether the associated remote is allowed to complete the handshake. 309 | NOT YET IMPLEMENTED (fully). 310 | Currently only implemented for CURVE sockets with CurveAsServer(true). 311 | """ 312 | fun tag default(): (_ZapRequestNotifiable | None) => None 313 | -------------------------------------------------------------------------------- /zmq/socket_type.pony: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | interface val SocketType 6 | fun tag string(): String 7 | fun tag accepts(other: String): Bool 8 | fun tag handle_outgoing(): _HandleOutgoing 9 | fun tag handle_incoming(): _HandleIncoming 10 | fun tag observe_outgoing(): _ObserveOutgoing => _ObserveOutgoingNone 11 | fun tag observe_incoming(): _ObserveIncoming => _ObserveIncomingNone 12 | 13 | /// 14 | // SocketTypes 15 | 16 | primitive REQ is SocketType 17 | fun tag string(): String => "REQ" 18 | fun tag accepts(other: String): Bool => (other == "REP") 19 | or (other == "ROUTER") 20 | fun tag handle_outgoing(): _HandleOutgoing => _HandleOutgoingRoundRobin 21 | fun tag handle_incoming(): _HandleIncoming => _HandleIncomingAllPeers 22 | 23 | primitive REP is SocketType 24 | fun tag string(): String => "REP" 25 | fun tag accepts(other: String): Bool => (other == "REQ") 26 | or (other == "DEALER") 27 | fun tag handle_outgoing(): _HandleOutgoing => _HandleOutgoingDiscard // only allow by promise or peer 28 | fun tag handle_incoming(): _HandleIncoming => _HandleIncomingAllPeers 29 | 30 | primitive DEALER is SocketType 31 | fun tag string(): String => "DEALER" 32 | fun tag accepts(other: String): Bool => (other == "REP") 33 | or (other == "DEALER") 34 | or (other == "ROUTER") 35 | fun tag handle_outgoing(): _HandleOutgoing => _HandleOutgoingRoundRobin 36 | fun tag handle_incoming(): _HandleIncoming => _HandleIncomingAllPeers 37 | fun tag observe_outgoing(): _ObserveOutgoing => _ObserveOutgoingRoutingFrame 38 | 39 | primitive ROUTER is SocketType 40 | fun tag string(): String => "ROUTER" 41 | fun tag accepts(other: String): Bool => (other == "REQ") 42 | or (other == "DEALER") 43 | or (other == "ROUTER") 44 | fun tag handle_outgoing(): _HandleOutgoing => _HandleOutgoingRoutingFrame 45 | fun tag handle_incoming(): _HandleIncoming => _HandleIncomingAllPeers 46 | fun tag observe_incoming(): _ObserveIncoming => _ObserveIncomingRoutingFrame 47 | 48 | primitive PUB is SocketType 49 | fun tag string(): String => "PUB" 50 | fun tag accepts(other: String): Bool => (other == "SUB") 51 | or (other == "XSUB") 52 | fun tag handle_outgoing(): _HandleOutgoing => _HandleOutgoingSubscribedPeers 53 | fun tag handle_incoming(): _HandleIncoming => _HandleIncomingDiscard 54 | fun tag observe_incoming(): _ObserveIncoming => _ObserveIncomingSubscriptionFilter 55 | 56 | primitive SUB is SocketType 57 | fun tag string(): String => "SUB" 58 | fun tag accepts(other: String): Bool => (other == "PUB") 59 | or (other == "XPUB") 60 | fun tag handle_outgoing(): _HandleOutgoing => _HandleOutgoingDiscard 61 | fun tag handle_incoming(): _HandleIncoming => _HandleIncomingAllPeers 62 | 63 | primitive XPUB is SocketType 64 | fun tag string(): String => "XPUB" 65 | fun tag accepts(other: String): Bool => (other == "SUB") 66 | or (other == "XSUB") 67 | fun tag handle_outgoing(): _HandleOutgoing => _HandleOutgoingAllPeers 68 | fun tag handle_incoming(): _HandleIncoming => _HandleIncomingAllPeers 69 | 70 | primitive XSUB is SocketType 71 | fun tag string(): String => "XSUB" 72 | fun tag accepts(other: String): Bool => (other == "PUB") 73 | or (other == "XPUB") 74 | fun tag handle_outgoing(): _HandleOutgoing => _HandleOutgoingAllPeers 75 | fun tag handle_incoming(): _HandleIncoming => _HandleIncomingAllPeers 76 | 77 | primitive PUSH is SocketType 78 | fun tag string(): String => "PUSH" 79 | fun tag accepts(other: String): Bool => (other == "PULL") 80 | fun tag handle_outgoing(): _HandleOutgoing => _HandleOutgoingRoundRobin 81 | fun tag handle_incoming(): _HandleIncoming => _HandleIncomingDiscard 82 | 83 | primitive PULL is SocketType 84 | fun tag string(): String => "PULL" 85 | fun tag accepts(other: String): Bool => (other == "PUSH") 86 | fun tag handle_outgoing(): _HandleOutgoing => _HandleOutgoingDiscard 87 | fun tag handle_incoming(): _HandleIncoming => _HandleIncomingAllPeers 88 | 89 | primitive PAIR is SocketType 90 | fun tag string(): String => "PAIR" 91 | fun tag accepts(other: String): Bool => (other == "PAIR") 92 | fun tag handle_outgoing(): _HandleOutgoing => _HandleOutgoingSinglePeer 93 | fun tag handle_incoming(): _HandleIncoming => _HandleIncomingSinglePeer 94 | -------------------------------------------------------------------------------- /zmq/test/main.pony: -------------------------------------------------------------------------------- 1 | 2 | use "ponytest" 3 | 4 | actor Main is TestList 5 | new create(env: Env) => PonyTest(env, this) 6 | new make() => None 7 | 8 | fun tag tests(test: PonyTest) => 9 | test(MessageTest) 10 | test(Z85Test) 11 | test(SocketOptionsTest) 12 | SocketTransportTests.tests(test) 13 | SocketTypeTests.tests(test) 14 | -------------------------------------------------------------------------------- /zmq/test/message_test.pony: -------------------------------------------------------------------------------- 1 | 2 | use "ponytest" 3 | use zmq = ".." 4 | 5 | class MessageTest is UnitTest 6 | new iso create() => None 7 | fun name(): String => "zmq.Message" 8 | 9 | fun apply(h: TestHelper) => 10 | h.assert_eq[zmq.Message]( 11 | recover zmq.Message.>push("foo") end, 12 | recover zmq.Message.>push("foo") end 13 | ) 14 | 15 | h.assert_false( 16 | recover zmq.Message.>push("foo") end == 17 | recover zmq.Message.>push("bar") end, 18 | "expected " + zmq.Message.>push("foo").string() + " " + 19 | "not to eq " + zmq.Message.>push("bar").string() 20 | ) 21 | -------------------------------------------------------------------------------- /zmq/test/socket_options_test.pony: -------------------------------------------------------------------------------- 1 | 2 | use "ponytest" 3 | use zmq = ".." 4 | 5 | class SocketOptionsTest is UnitTest 6 | new iso create() => None 7 | fun name(): String => "zmq.SocketOptions" 8 | 9 | fun apply(h: TestHelper) => 10 | // Start with an empty set of SocketOptions; all are at their defaults. 11 | let socket_opts = zmq.SocketOptions 12 | h.assert_eq[USize](socket_opts.size(), 0) 13 | h.assert_eq[F64](zmq.ReconnectInterval.find_in(socket_opts), 14 | zmq.ReconnectInterval.default()) 15 | h.assert_eq[F64](zmq.HeartbeatInterval.find_in(socket_opts), 16 | zmq.HeartbeatInterval.default()) 17 | 18 | // Set an option to grow the set and override the default for that option. 19 | h.assert_true(zmq.ReconnectInterval.set_in(socket_opts, 0.25)) 20 | h.assert_eq[USize](socket_opts.size(), 1) 21 | h.assert_eq[F64](zmq.ReconnectInterval.find_in(socket_opts), 0.25) 22 | h.assert_eq[F64](zmq.HeartbeatInterval.find_in(socket_opts), 23 | zmq.HeartbeatInterval.default()) 24 | 25 | // Set another option to grow and override again. 26 | h.assert_true(zmq.HeartbeatInterval.set_in(socket_opts, 10.0)) 27 | h.assert_eq[USize](socket_opts.size(), 2) 28 | h.assert_eq[F64](zmq.ReconnectInterval.find_in(socket_opts), 0.25) 29 | h.assert_eq[F64](zmq.HeartbeatInterval.find_in(socket_opts), 10.0) 30 | 31 | // Set an already-set option many times; takes the latest and does not grow. 32 | h.assert_true(zmq.ReconnectInterval.set_in(socket_opts, 0.5)) 33 | h.assert_true(zmq.ReconnectInterval.set_in(socket_opts, 1.0)) 34 | h.assert_true(zmq.ReconnectInterval.set_in(socket_opts, 2.0)) 35 | h.assert_eq[USize](socket_opts.size(), 2) 36 | h.assert_eq[F64](zmq.ReconnectInterval.find_in(socket_opts), 2.0) 37 | h.assert_eq[F64](zmq.HeartbeatInterval.find_in(socket_opts), 10.0) 38 | 39 | // Set an option to an invalid value; returns false and does not grow. 40 | h.assert_false(zmq.CurveSecretKey.set_in(socket_opts, "not_a_key")) 41 | h.assert_eq[USize](socket_opts.size(), 2) 42 | 43 | // Set and find a boolean option. 44 | h.assert_false(zmq.CurveAsServer.find_in(socket_opts)) 45 | h.assert_true(zmq.CurveAsServer.set_in(socket_opts, true)) 46 | h.assert_true(zmq.CurveAsServer.find_in(socket_opts)) 47 | h.assert_eq[USize](socket_opts.size(), 3) 48 | -------------------------------------------------------------------------------- /zmq/test/socket_transport_tests.pony: -------------------------------------------------------------------------------- 1 | 2 | use "ponytest" 3 | use "net" 4 | use zmq = ".." 5 | use zmtp = "../zmtp" 6 | 7 | primitive SocketTransportTests is TestList 8 | fun tag tests(test: PonyTest) => 9 | 10 | test(SocketTransportTest("InProc", 11 | {(ctx: zmq.Context, a: zmq.Socket, b: zmq.Socket) => 12 | a(zmq.BindInProc(ctx, "SocketTransportTest")) 13 | b(zmq.ConnectInProc(ctx, "SocketTransportTest")) 14 | } val)) 15 | 16 | test(SocketTransportTest("TCP", 17 | {(net_auth: NetAuth, a: zmq.Socket, b: zmq.Socket) => 18 | a(zmq.BindTCP(net_auth, "localhost", "8888")) 19 | b(zmq.ConnectTCP(net_auth, "localhost", "8888")) 20 | } val)) 21 | 22 | test(SocketTransportTest("TCP + Curve", 23 | {(net_auth: NetAuth, a: zmq.Socket, b: zmq.Socket) => 24 | a.set(zmq.CurvePublicKey("b8loV^tt{Wvs9Fx!xTI3[e/x1n.ud0]>9Tj*BGPt")) 25 | a.set(zmq.CurveSecretKey("mjr{I->@v1rhtZ9^Q5BZN7MLI50]*/Eyn]s")) 30 | b.set(zmq.CurvePublicKeyOfServer("b8loV^tt{Wvs9Fx!xTI3[e/x1n.ud0]>9Tj*BGPt")) 31 | 32 | a(zmq.BindTCP(net_auth, "localhost", "8889")) 33 | b(zmq.ConnectTCP(net_auth, "localhost", "8889")) 34 | } val)) 35 | 36 | test(SocketTransportTest("TCP + Curve + Zap", 37 | {(net_auth: NetAuth, a: zmq.Socket, b: zmq.Socket) => 38 | let zap_handler = 39 | object is zmtp.ZapRequestNotifiable 40 | be handle_zap_request(req: zmtp.ZapRequest, respond: zmtp.ZapRespond) => 41 | // TODO: check public key (field of req) 42 | respond(zmtp.ZapResponse.success("bob")) 43 | end 44 | 45 | a.set(zmq.CurvePublicKey("b8loV^tt{Wvs9Fx!xTI3[e/x1n.ud0]>9Tj*BGPt")) 46 | a.set(zmq.CurveSecretKey("mjr{I->@v1rhtZ9^Q5BZN7MLI50]*/Eyn]s")) 52 | b.set(zmq.CurvePublicKeyOfServer("b8loV^tt{Wvs9Fx!xTI3[e/x1n.ud0]>9Tj*BGPt")) 53 | 54 | a(zmq.BindTCP(net_auth, "localhost", "8890")) 55 | b(zmq.ConnectTCP(net_auth, "localhost", "8890")) 56 | } val)) 57 | 58 | interface val _SocketTransportTestsSetupNetLambda 59 | fun val apply(net_auth: NetAuth, a: zmq.Socket, b: zmq.Socket) 60 | 61 | interface val _SocketTransportTestsSetupContextLambda 62 | fun val apply(ctx: zmq.Context, a: zmq.Socket, b: zmq.Socket) 63 | 64 | type _SocketTransportTestsSetupLambda is 65 | (_SocketTransportTestsSetupNetLambda | _SocketTransportTestsSetupContextLambda) 66 | 67 | class SocketTransportTest is UnitTest 68 | let _desc: String 69 | let _setup: _SocketTransportTestsSetupLambda 70 | new iso create(desc: String, setup: _SocketTransportTestsSetupLambda) => 71 | _desc = desc 72 | _setup = setup 73 | 74 | fun name(): String => "zmq.Socket (transport: " + _desc + ")" 75 | 76 | fun apply(h: TestHelper)? => 77 | let ra = _SocketReactor; let a = zmq.Socket(zmq.PAIR, ra.notify()) 78 | let rb = _SocketReactor; let b = zmq.Socket(zmq.PAIR, rb.notify()) 79 | 80 | let net_auth = NetAuth(h.env.root as AmbientAuth) 81 | let ctx = zmq.Context 82 | 83 | match _setup 84 | | let setup: _SocketTransportTestsSetupNetLambda => setup(net_auth, a, b) 85 | | let setup: _SocketTransportTestsSetupContextLambda => setup(ctx, a, b) 86 | end 87 | 88 | a.send(recover zmq.Message.>push("foo") end) 89 | b.send(recover zmq.Message.>push("bar") end) 90 | 91 | ra.next({(m: zmq.Message) => 92 | h.assert_eq[zmq.Message](m, recover zmq.Message.>push("bar") end) 93 | a.dispose() 94 | } val) 95 | 96 | rb.next({(m: zmq.Message) => 97 | h.assert_eq[zmq.Message](m, recover zmq.Message.>push("foo") end) 98 | b.dispose() 99 | } val) 100 | 101 | ra.when_closed({()(h,rb) => 102 | rb.when_closed({()(h) => 103 | h.complete(true) 104 | } val) 105 | } val) 106 | 107 | h.long_test(5_000_000_000) 108 | -------------------------------------------------------------------------------- /zmq/test/socket_type_tests.pony: -------------------------------------------------------------------------------- 1 | 2 | use "ponytest" 3 | use "collections" 4 | use zmq = ".." 5 | 6 | primitive SocketTypeTests is TestList 7 | fun tag tests(test: PonyTest) => 8 | test(SocketTypeTestPairPair) 9 | test(SocketTypeTestPushNPull) 10 | test(SocketTypeTestPullNPush) 11 | test(SocketTypeTestReqNRep) 12 | test(SocketTypeTestRepNReq) 13 | 14 | trait SocketTypeTest is UnitTest 15 | fun tag recv(h: TestHelper, rs: _SocketReactor, s: zmq.Socket, m': zmq.Message) => 16 | rs.next(recover this~_recv_lambda(h, s, m') end) 17 | 18 | fun tag recv_last(h: TestHelper, rs: _SocketReactor, s: zmq.Socket, m': zmq.Message) => 19 | rs.next(recover this~_recv_last_lambda(h, s, m') end) 20 | 21 | fun tag _recv_lambda(h: TestHelper, s: zmq.Socket, m': zmq.Message, m: zmq.Message) => 22 | h.assert_eq[zmq.Message](m, m') 23 | 24 | fun tag _recv_last_lambda(h: TestHelper, s: zmq.Socket, m': zmq.Message, m: zmq.Message) => 25 | h.assert_eq[zmq.Message](m, m') 26 | s.dispose() 27 | 28 | fun tag recv_unordered_set(h: TestHelper, rs: _SocketReactor, s: zmq.Socket, expected_list: Array[zmq.Message] val) => 29 | rs.next_n(expected_list.size(), {(list: List[zmq.Message])(h,s,expected_list) => 30 | if list.size() != expected_list.size() then 31 | h.fail("Expected " + expected_list.size().string() + " messages, " + 32 | "but got " + list.size().string()) 33 | end 34 | 35 | for expected in expected_list.values() do 36 | for node in list.nodes() do 37 | try if node()? == expected then 38 | node.remove() 39 | break 40 | end end 41 | end 42 | end 43 | 44 | for remaining in list.values() do 45 | h.fail("Got unexpected message: "+remaining.string()) 46 | end 47 | 48 | s.dispose() 49 | } val) 50 | 51 | fun tag wait_1_reactor(h: TestHelper, ra: _SocketReactor) => 52 | ra.when_closed({()(h) => 53 | h.complete(true) 54 | } val) 55 | 56 | h.long_test(5_000_000_000) 57 | 58 | fun tag wait_2_reactors(h: TestHelper, ra: _SocketReactor, rb: _SocketReactor) => 59 | ra.when_closed({()(h, rb) => 60 | rb.when_closed({()(h) => 61 | h.complete(true) 62 | } val) 63 | } val) 64 | 65 | h.long_test(5_000_000_000) 66 | 67 | fun tag wait_3_reactors(h: TestHelper, ra: _SocketReactor, rb: _SocketReactor, rc: _SocketReactor) => 68 | ra.when_closed({()(h, rb, rc) => 69 | rb.when_closed({()(h, rc) => 70 | rc.when_closed({()(h) => 71 | h.complete(true) 72 | } val) 73 | } val) 74 | } val) 75 | 76 | h.long_test(5_000_000_000) 77 | 78 | class SocketTypeTestPairPair is SocketTypeTest 79 | new iso create() => None 80 | fun name(): String => "zmq.Socket (type: 1-PAIR <-> 1-PAIR)" 81 | 82 | fun apply(h: TestHelper) => 83 | let ra = _SocketReactor; let a = zmq.Socket(zmq.PAIR, ra.notify()) 84 | let rb = _SocketReactor; let b = zmq.Socket(zmq.PAIR, rb.notify()) 85 | 86 | let ctx = zmq.Context 87 | a(zmq.BindInProc(ctx, "SocketTypeTestPairPair")) 88 | b(zmq.ConnectInProc(ctx, "SocketTypeTestPairPair")) 89 | 90 | a.access({(a: zmq.Socket ref) => 91 | a.send_now(recover zmq.Message.>push("b1") end) 92 | a.send_now(recover zmq.Message.>push("b2") end) 93 | a.send_now(recover zmq.Message.>push("b3") end) 94 | } val) 95 | 96 | b.access({(b: zmq.Socket ref) => 97 | b.send_now(recover zmq.Message.>push("a1") end) 98 | b.send_now(recover zmq.Message.>push("a2") end) 99 | b.send_now(recover zmq.Message.>push("a3") end) 100 | } val) 101 | 102 | recv(h, ra, a, recover zmq.Message.>push("a1") end) 103 | recv(h, ra, a, recover zmq.Message.>push("a2") end) 104 | recv_last(h, ra, a, recover zmq.Message.>push("a3") end) 105 | 106 | recv(h, rb, b, recover zmq.Message.>push("b1") end) 107 | recv(h, rb, b, recover zmq.Message.>push("b2") end) 108 | recv_last(h, rb, b, recover zmq.Message.>push("b3") end) 109 | 110 | wait_2_reactors(h, ra, rb) 111 | 112 | class SocketTypeTestPushNPull is SocketTypeTest 113 | new iso create() => None 114 | fun name(): String => "zmq.Socket (type: 1-PUSH --> N-PULL)" 115 | 116 | fun apply(h: TestHelper) => 117 | let rs = _SocketReactor; let s = zmq.Socket(zmq.PUSH, rs.notify()) 118 | let ra = _SocketReactor; let a = zmq.Socket(zmq.PULL, ra.notify()) 119 | let rb = _SocketReactor; let b = zmq.Socket(zmq.PULL, rb.notify()) 120 | let rc = _SocketReactor; let c = zmq.Socket(zmq.PULL, rc.notify()) 121 | 122 | let ctx = zmq.Context 123 | a(zmq.BindInProc(ctx, "SocketTypeTestPushNPull/a")) 124 | b(zmq.BindInProc(ctx, "SocketTypeTestPushNPull/b")) 125 | c(zmq.BindInProc(ctx, "SocketTypeTestPushNPull/c")) 126 | s(zmq.ConnectInProc(ctx, "SocketTypeTestPushNPull/a")) 127 | s(zmq.ConnectInProc(ctx, "SocketTypeTestPushNPull/b")) 128 | s(zmq.ConnectInProc(ctx, "SocketTypeTestPushNPull/c")) 129 | 130 | s.access({(s: zmq.Socket ref) => 131 | s.send_now(recover zmq.Message.>push("a1") end) 132 | s.send_now(recover zmq.Message.>push("b1") end) 133 | s.send_now(recover zmq.Message.>push("c1") end) 134 | s.send_now(recover zmq.Message.>push("a2") end) 135 | s.send_now(recover zmq.Message.>push("b2") end) 136 | s.send_now(recover zmq.Message.>push("c2") end) 137 | s.send_now(recover zmq.Message.>push("a3") end) 138 | s.send_now(recover zmq.Message.>push("b3") end) 139 | s.send_now(recover zmq.Message.>push("c3") end) 140 | } val) 141 | 142 | recv(h, ra, a, recover zmq.Message.>push("a1") end) 143 | recv(h, ra, a, recover zmq.Message.>push("a2") end) 144 | recv_last(h, ra, a, recover zmq.Message.>push("a3") end) 145 | 146 | recv(h, rb, b, recover zmq.Message.>push("b1") end) 147 | recv(h, rb, b, recover zmq.Message.>push("b2") end) 148 | recv_last(h, rb, b, recover zmq.Message.>push("b3") end) 149 | 150 | recv(h, rc, c, recover zmq.Message.>push("c1") end) 151 | recv(h, rc, c, recover zmq.Message.>push("c2") end) 152 | recv_last(h, rc, c, recover zmq.Message.>push("c3") end) 153 | 154 | wait_3_reactors(h, ra, rb, rc) 155 | 156 | class SocketTypeTestPullNPush is SocketTypeTest 157 | new iso create() => None 158 | fun name(): String => "zmq.Socket (type: 1-PULL <-- N-PUSH)" 159 | 160 | fun apply(h: TestHelper) => 161 | let rs = _SocketReactor; let s = zmq.Socket(zmq.PULL, rs.notify()) 162 | let ra = _SocketReactor; let a = zmq.Socket(zmq.PUSH, ra.notify()) 163 | let rb = _SocketReactor; let b = zmq.Socket(zmq.PUSH, rb.notify()) 164 | let rc = _SocketReactor; let c = zmq.Socket(zmq.PUSH, rc.notify()) 165 | 166 | let ctx = zmq.Context 167 | a(zmq.BindInProc(ctx, "SocketTypeTestPullNPush/a")) 168 | b(zmq.BindInProc(ctx, "SocketTypeTestPullNPush/b")) 169 | c(zmq.BindInProc(ctx, "SocketTypeTestPullNPush/c")) 170 | s(zmq.ConnectInProc(ctx, "SocketTypeTestPullNPush/a")) 171 | s(zmq.ConnectInProc(ctx, "SocketTypeTestPullNPush/b")) 172 | s(zmq.ConnectInProc(ctx, "SocketTypeTestPullNPush/c")) 173 | 174 | a.send(recover zmq.Message.>push("a1") end) 175 | b.send(recover zmq.Message.>push("b1") end) 176 | c.send(recover zmq.Message.>push("c1") end) 177 | a.send(recover zmq.Message.>push("a2") end) 178 | b.send(recover zmq.Message.>push("b2") end) 179 | c.send(recover zmq.Message.>push("c2") end) 180 | a.send(recover zmq.Message.>push("a3") end) 181 | b.send(recover zmq.Message.>push("b3") end) 182 | c.send(recover zmq.Message.>push("c3") end) 183 | 184 | recv_unordered_set(h, rs, s, recover [ 185 | recover val zmq.Message.>push("a1") end 186 | recover val zmq.Message.>push("b1") end 187 | recover val zmq.Message.>push("c1") end 188 | recover val zmq.Message.>push("a2") end 189 | recover val zmq.Message.>push("b2") end 190 | recover val zmq.Message.>push("c2") end 191 | recover val zmq.Message.>push("a3") end 192 | recover val zmq.Message.>push("b3") end 193 | recover val zmq.Message.>push("c3") end 194 | ] end) 195 | 196 | wait_1_reactor(h, rs) 197 | 198 | class SocketTypeTestReqNRep is SocketTypeTest 199 | new iso create() => None 200 | fun name(): String => "zmq.Socket (type: 1-REQ --> N-REP)" 201 | 202 | fun apply(h: TestHelper) => 203 | let rs = _SocketReactor; let s = zmq.Socket(zmq.REQ, rs.notify()) 204 | let ra = _SocketReactor; let a = zmq.Socket(zmq.REP, ra.notify()) 205 | let rb = _SocketReactor; let b = zmq.Socket(zmq.REP, rb.notify()) 206 | let rc = _SocketReactor; let c = zmq.Socket(zmq.REP, rc.notify()) 207 | 208 | let ctx = zmq.Context 209 | a(zmq.BindInProc(ctx, "SocketTypeTestReqNRep/a")) 210 | b(zmq.BindInProc(ctx, "SocketTypeTestReqNRep/b")) 211 | c(zmq.BindInProc(ctx, "SocketTypeTestReqNRep/c")) 212 | s(zmq.ConnectInProc(ctx, "SocketTypeTestReqNRep/a")) 213 | s(zmq.ConnectInProc(ctx, "SocketTypeTestReqNRep/b")) 214 | s(zmq.ConnectInProc(ctx, "SocketTypeTestReqNRep/c")) 215 | 216 | s.access({(s: zmq.Socket ref) => 217 | s.send_now(recover zmq.Message.>push("a") end) 218 | s.send_now(recover zmq.Message.>push("b") end) 219 | s.send_now(recover zmq.Message.>push("c") end) 220 | } val) 221 | 222 | ra.next({(p: zmq.SocketPeer, m: zmq.Message)(ra) => 223 | p.send(recover zmq.Message.>append(m).>push("A") end) 224 | } val) 225 | 226 | rb.next({(p: zmq.SocketPeer, m: zmq.Message)(rb) => 227 | p.send(recover zmq.Message.>append(m).>push("B") end) 228 | } val) 229 | 230 | rc.next({(p: zmq.SocketPeer, m: zmq.Message)(rc) => 231 | p.send(recover zmq.Message.>append(m).>push("C") end) 232 | } val) 233 | 234 | recv_unordered_set(h, rs, s, recover [ 235 | recover val zmq.Message.>push("a").>push("A") end 236 | recover val zmq.Message.>push("b").>push("B") end 237 | recover val zmq.Message.>push("c").>push("C") end 238 | ] end) 239 | 240 | wait_1_reactor(h, rs) 241 | 242 | class SocketTypeTestRepNReq is SocketTypeTest 243 | new iso create() => None 244 | fun name(): String => "zmq.Socket (type: 1-REP <-- N-REQ)" 245 | 246 | fun apply(h: TestHelper) => 247 | let rs = _SocketReactor; let s = zmq.Socket(zmq.REP, rs.notify()) 248 | let ra = _SocketReactor; let a = zmq.Socket(zmq.REQ, ra.notify()) 249 | let rb = _SocketReactor; let b = zmq.Socket(zmq.REQ, rb.notify()) 250 | let rc = _SocketReactor; let c = zmq.Socket(zmq.REQ, rc.notify()) 251 | 252 | let ctx = zmq.Context 253 | a(zmq.BindInProc(ctx, "SocketTypeTestRepNReq/a")) 254 | b(zmq.BindInProc(ctx, "SocketTypeTestRepNReq/b")) 255 | c(zmq.BindInProc(ctx, "SocketTypeTestRepNReq/c")) 256 | s(zmq.ConnectInProc(ctx, "SocketTypeTestRepNReq/a")) 257 | s(zmq.ConnectInProc(ctx, "SocketTypeTestRepNReq/b")) 258 | s(zmq.ConnectInProc(ctx, "SocketTypeTestRepNReq/c")) 259 | 260 | a.send(recover zmq.Message.>push("a") end) 261 | b.send(recover zmq.Message.>push("b") end) 262 | c.send(recover zmq.Message.>push("c") end) 263 | 264 | for i in Range(0, 3) do 265 | rs.next({(p: zmq.SocketPeer, m: zmq.Message)(rs) => 266 | p.send(recover zmq.Message.>append(m).>push("S") end) 267 | } val) 268 | end 269 | 270 | recv_last(h, ra, a, recover zmq.Message.>push("a").>push("S") end) 271 | recv_last(h, rb, b, recover zmq.Message.>push("b").>push("S") end) 272 | recv_last(h, rc, c, recover zmq.Message.>push("c").>push("S") end) 273 | 274 | wait_3_reactors(h, ra, rb, rc) 275 | -------------------------------------------------------------------------------- /zmq/test/util.pony: -------------------------------------------------------------------------------- 1 | 2 | use "collections" 3 | use zmq = ".." 4 | 5 | interface val _Handler 6 | fun val apply() 7 | 8 | interface val _MessageHandler 9 | fun val apply(message: zmq.Message) 10 | 11 | interface val _PeerMessageHandler 12 | fun val apply(peer: zmq.SocketPeer, message: zmq.Message) 13 | 14 | interface val _MessageListHandler 15 | fun val apply(message: List[zmq.Message]) 16 | 17 | type _SocketReactorHandler is 18 | ( _MessageHandler 19 | | _PeerMessageHandler 20 | | (USize, _MessageListHandler)) 21 | 22 | actor _SocketReactor is zmq.SocketNotifiableActor 23 | let _messages: List[(zmq.SocketPeer, zmq.Message)] = _messages.create() 24 | let _handlers: List[_SocketReactorHandler] = _handlers.create() 25 | 26 | var _closed_handler: (_Handler | None) = None 27 | var _closed: Bool = false 28 | var _ran_closed_handler: Bool = false 29 | 30 | fun tag notify(): zmq.SocketNotify^ => 31 | zmq.SocketNotifyActor(this) 32 | 33 | be next(handler: (_MessageHandler | _PeerMessageHandler)) => 34 | _handlers.push(consume handler) 35 | maybe_run_handlers() 36 | 37 | be next_n(n: USize, handler: _MessageListHandler) => 38 | _handlers.push((n, consume handler)) 39 | maybe_run_handlers() 40 | 41 | be received(socket: zmq.Socket, peer: zmq.SocketPeer, message: zmq.Message) => 42 | _messages.push((peer, message)) 43 | maybe_run_handlers() 44 | 45 | be when_closed(handler: _Handler) => 46 | _closed_handler = consume handler 47 | maybe_run_closed_handler() 48 | 49 | be closed(socket: zmq.Socket) => 50 | _closed = true 51 | maybe_run_closed_handler() 52 | 53 | fun ref maybe_run_handlers() => 54 | try 55 | while (_handlers.size() > 0) and (_messages.size() > 0) do 56 | match _handlers.shift()? 57 | | let h: _MessageHandler => 58 | (let peer, let message) = _messages.shift()? 59 | (consume h)(message) 60 | 61 | | let h: _PeerMessageHandler => 62 | (let peer, let message) = _messages.shift()? 63 | (consume h)(peer, message) 64 | 65 | | (let n': USize, let h: _MessageListHandler) => 66 | var n = n' 67 | if _messages.size() < n then _handlers.unshift((n, consume h)); error end 68 | 69 | let list = List[zmq.Message] 70 | while n > 0 do 71 | n = n - 1 72 | (let peer, let message) = _messages.shift()? 73 | list.push(message) 74 | end 75 | (consume h)(list) 76 | end 77 | end 78 | end 79 | 80 | fun ref maybe_run_closed_handler() => 81 | if _closed and not _ran_closed_handler then 82 | match (_closed_handler = None) | let closed_handler: _Handler => 83 | (consume closed_handler)() 84 | _ran_closed_handler = true 85 | end 86 | end 87 | -------------------------------------------------------------------------------- /zmq/test/z85_test.pony: -------------------------------------------------------------------------------- 1 | 2 | use "ponytest" 3 | use "../z85" 4 | 5 | class Z85Test is UnitTest 6 | new iso create() => None 7 | fun name(): String => "zmq.Z85" 8 | 9 | fun apply(h: TestHelper) => 10 | // Example from ZMQ RFC 32 for Z85. 11 | test_pair(h, "HelloWorld", recover [as U8: 12 | 0x86; 0x4F; 0xD2; 0x6F; 0xB5; 0x59; 0xF7; 0x5B 13 | ] end) 14 | 15 | // Examples of encoded string size not divisible by 5 16 | test_decode_error(h, "HelloWorlds") 17 | test_decode_error(h, "HelloWorl") 18 | 19 | // Examples of illegal characters in encoded string 20 | test_decode_error(h, "Hello Z85!") 21 | test_decode_error(h, "Hello\nZ85!") 22 | test_decode_error(h, "Hello\x7FZ85!") 23 | 24 | // Examples of binary size not divisible by 4 25 | test_encode_error(h, recover [as U8: 26 | 0x86; 0x4F; 0xD2; 0x6F; 0xB5; 0x59; 0xF7; 0x5B; 0x01 27 | ] end) 28 | test_encode_error(h, recover [as U8: 29 | 0x86; 0x4F; 0xD2; 0x6F; 0xB5; 0x59; 0xF7 30 | ] end) 31 | 32 | // Example client public key from `man curve_zmq`. 33 | test_pair(h, "Yne@$w-vo}U?@Lns47E1%kR.o@n%FcmmsL/@{H8]yf7", recover [as U8: 50 | 0x54; 0xFC; 0xBA; 0x24; 0xE9; 0x32; 0x49; 0x96 51 | 0x93; 0x16; 0xFB; 0x61; 0x7C; 0x87; 0x2B; 0xB0 52 | 0xC1; 0xD1; 0xFF; 0x14; 0x80; 0x04; 0x27; 0xC5 53 | 0x94; 0xCB; 0xFA; 0xCF; 0x1B; 0xC2; 0xD6; 0x52 54 | ] end) 55 | 56 | // Example server private key from `man curve_zmq`. 57 | test_pair(h, "JTKVSB%%)wK0E.X)V>+}o?pNmC{O&4W4b!Ni{Lh6", recover [as U8: 58 | 0x8E; 0x0B; 0xDD; 0x69; 0x76; 0x28; 0xB9; 0x1D 59 | 0x8F; 0x24; 0x55; 0x87; 0xEE; 0x95; 0xC5; 0xB0 60 | 0x4D; 0x48; 0x96; 0x3F; 0x79; 0x25; 0x98; 0x77 61 | 0xB4; 0x9C; 0xD9; 0x06; 0x3A; 0xEA; 0xD3; 0xB7 62 | ] end) 63 | 64 | fun test_pair(h: TestHelper, str: String, bin: Array[U8] val) => 65 | try h.assert_eq[String](Z85.encode(bin)?, str) 66 | else h.fail("expected to be able to Z85-encode to string: "+str) 67 | end 68 | try h.assert_eq[String](Z85.decode(str)?, recover String.>append(bin) end) 69 | else h.fail("expected to be able to Z85-decode from string: "+str) 70 | end 71 | 72 | fun test_decode_error(h: TestHelper, str: String) => 73 | try Z85.decode(str)? 74 | h.fail("expected NOT to be able to Z85-decode from string: "+str) 75 | end 76 | 77 | fun test_encode_error(h: TestHelper, bin: Array[U8] val) => 78 | try Z85.encode(bin)? 79 | h.fail("expected NOT to be able to Z85-encode the binary.") 80 | end 81 | -------------------------------------------------------------------------------- /zmq/z85/LICENSE: -------------------------------------------------------------------------------- 1 | Mozilla Public License Version 2.0 2 | ================================== 3 | 4 | 1. Definitions 5 | -------------- 6 | 7 | 1.1. "Contributor" 8 | means each individual or legal entity that creates, contributes to 9 | the creation of, or owns Covered Software. 10 | 11 | 1.2. "Contributor Version" 12 | means the combination of the Contributions of others (if any) used 13 | by a Contributor and that particular Contributor's Contribution. 14 | 15 | 1.3. "Contribution" 16 | means Covered Software of a particular Contributor. 17 | 18 | 1.4. "Covered Software" 19 | means Source Code Form to which the initial Contributor has attached 20 | the notice in Exhibit A, the Executable Form of such Source Code 21 | Form, and Modifications of such Source Code Form, in each case 22 | including portions thereof. 23 | 24 | 1.5. "Incompatible With Secondary Licenses" 25 | means 26 | 27 | (a) that the initial Contributor has attached the notice described 28 | in Exhibit B to the Covered Software; or 29 | 30 | (b) that the Covered Software was made available under the terms of 31 | version 1.1 or earlier of the License, but not also under the 32 | terms of a Secondary License. 33 | 34 | 1.6. "Executable Form" 35 | means any form of the work other than Source Code Form. 36 | 37 | 1.7. "Larger Work" 38 | means a work that combines Covered Software with other material, in 39 | a separate file or files, that is not Covered Software. 40 | 41 | 1.8. "License" 42 | means this document. 43 | 44 | 1.9. "Licensable" 45 | means having the right to grant, to the maximum extent possible, 46 | whether at the time of the initial grant or subsequently, any and 47 | all of the rights conveyed by this License. 48 | 49 | 1.10. "Modifications" 50 | means any of the following: 51 | 52 | (a) any file in Source Code Form that results from an addition to, 53 | deletion from, or modification of the contents of Covered 54 | Software; or 55 | 56 | (b) any new file in Source Code Form that contains any Covered 57 | Software. 58 | 59 | 1.11. "Patent Claims" of a Contributor 60 | means any patent claim(s), including without limitation, method, 61 | process, and apparatus claims, in any patent Licensable by such 62 | Contributor that would be infringed, but for the grant of the 63 | License, by the making, using, selling, offering for sale, having 64 | made, import, or transfer of either its Contributions or its 65 | Contributor Version. 66 | 67 | 1.12. "Secondary License" 68 | means either the GNU General Public License, Version 2.0, the GNU 69 | Lesser General Public License, Version 2.1, the GNU Affero General 70 | Public License, Version 3.0, or any later versions of those 71 | licenses. 72 | 73 | 1.13. "Source Code Form" 74 | means the form of the work preferred for making modifications. 75 | 76 | 1.14. "You" (or "Your") 77 | means an individual or a legal entity exercising rights under this 78 | License. For legal entities, "You" includes any entity that 79 | controls, is controlled by, or is under common control with You. For 80 | purposes of this definition, "control" means (a) the power, direct 81 | or indirect, to cause the direction or management of such entity, 82 | whether by contract or otherwise, or (b) ownership of more than 83 | fifty percent (50%) of the outstanding shares or beneficial 84 | ownership of such entity. 85 | 86 | 2. License Grants and Conditions 87 | -------------------------------- 88 | 89 | 2.1. Grants 90 | 91 | Each Contributor hereby grants You a world-wide, royalty-free, 92 | non-exclusive license: 93 | 94 | (a) under intellectual property rights (other than patent or trademark) 95 | Licensable by such Contributor to use, reproduce, make available, 96 | modify, display, perform, distribute, and otherwise exploit its 97 | Contributions, either on an unmodified basis, with Modifications, or 98 | as part of a Larger Work; and 99 | 100 | (b) under Patent Claims of such Contributor to make, use, sell, offer 101 | for sale, have made, import, and otherwise transfer either its 102 | Contributions or its Contributor Version. 103 | 104 | 2.2. Effective Date 105 | 106 | The licenses granted in Section 2.1 with respect to any Contribution 107 | become effective for each Contribution on the date the Contributor first 108 | distributes such Contribution. 109 | 110 | 2.3. Limitations on Grant Scope 111 | 112 | The licenses granted in this Section 2 are the only rights granted under 113 | this License. No additional rights or licenses will be implied from the 114 | distribution or licensing of Covered Software under this License. 115 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 116 | Contributor: 117 | 118 | (a) for any code that a Contributor has removed from Covered Software; 119 | or 120 | 121 | (b) for infringements caused by: (i) Your and any other third party's 122 | modifications of Covered Software, or (ii) the combination of its 123 | Contributions with other software (except as part of its Contributor 124 | Version); or 125 | 126 | (c) under Patent Claims infringed by Covered Software in the absence of 127 | its Contributions. 128 | 129 | This License does not grant any rights in the trademarks, service marks, 130 | or logos of any Contributor (except as may be necessary to comply with 131 | the notice requirements in Section 3.4). 132 | 133 | 2.4. Subsequent Licenses 134 | 135 | No Contributor makes additional grants as a result of Your choice to 136 | distribute the Covered Software under a subsequent version of this 137 | License (see Section 10.2) or under the terms of a Secondary License (if 138 | permitted under the terms of Section 3.3). 139 | 140 | 2.5. Representation 141 | 142 | Each Contributor represents that the Contributor believes its 143 | Contributions are its original creation(s) or it has sufficient rights 144 | to grant the rights to its Contributions conveyed by this License. 145 | 146 | 2.6. Fair Use 147 | 148 | This License is not intended to limit any rights You have under 149 | applicable copyright doctrines of fair use, fair dealing, or other 150 | equivalents. 151 | 152 | 2.7. Conditions 153 | 154 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 155 | in Section 2.1. 156 | 157 | 3. Responsibilities 158 | ------------------- 159 | 160 | 3.1. Distribution of Source Form 161 | 162 | All distribution of Covered Software in Source Code Form, including any 163 | Modifications that You create or to which You contribute, must be under 164 | the terms of this License. You must inform recipients that the Source 165 | Code Form of the Covered Software is governed by the terms of this 166 | License, and how they can obtain a copy of this License. You may not 167 | attempt to alter or restrict the recipients' rights in the Source Code 168 | Form. 169 | 170 | 3.2. Distribution of Executable Form 171 | 172 | If You distribute Covered Software in Executable Form then: 173 | 174 | (a) such Covered Software must also be made available in Source Code 175 | Form, as described in Section 3.1, and You must inform recipients of 176 | the Executable Form how they can obtain a copy of such Source Code 177 | Form by reasonable means in a timely manner, at a charge no more 178 | than the cost of distribution to the recipient; and 179 | 180 | (b) You may distribute such Executable Form under the terms of this 181 | License, or sublicense it under different terms, provided that the 182 | license for the Executable Form does not attempt to limit or alter 183 | the recipients' rights in the Source Code Form under this License. 184 | 185 | 3.3. Distribution of a Larger Work 186 | 187 | You may create and distribute a Larger Work under terms of Your choice, 188 | provided that You also comply with the requirements of this License for 189 | the Covered Software. If the Larger Work is a combination of Covered 190 | Software with a work governed by one or more Secondary Licenses, and the 191 | Covered Software is not Incompatible With Secondary Licenses, this 192 | License permits You to additionally distribute such Covered Software 193 | under the terms of such Secondary License(s), so that the recipient of 194 | the Larger Work may, at their option, further distribute the Covered 195 | Software under the terms of either this License or such Secondary 196 | License(s). 197 | 198 | 3.4. Notices 199 | 200 | You may not remove or alter the substance of any license notices 201 | (including copyright notices, patent notices, disclaimers of warranty, 202 | or limitations of liability) contained within the Source Code Form of 203 | the Covered Software, except that You may alter any license notices to 204 | the extent required to remedy known factual inaccuracies. 205 | 206 | 3.5. Application of Additional Terms 207 | 208 | You may choose to offer, and to charge a fee for, warranty, support, 209 | indemnity or liability obligations to one or more recipients of Covered 210 | Software. However, You may do so only on Your own behalf, and not on 211 | behalf of any Contributor. You must make it absolutely clear that any 212 | such warranty, support, indemnity, or liability obligation is offered by 213 | You alone, and You hereby agree to indemnify every Contributor for any 214 | liability incurred by such Contributor as a result of warranty, support, 215 | indemnity or liability terms You offer. You may include additional 216 | disclaimers of warranty and limitations of liability specific to any 217 | jurisdiction. 218 | 219 | 4. Inability to Comply Due to Statute or Regulation 220 | --------------------------------------------------- 221 | 222 | If it is impossible for You to comply with any of the terms of this 223 | License with respect to some or all of the Covered Software due to 224 | statute, judicial order, or regulation then You must: (a) comply with 225 | the terms of this License to the maximum extent possible; and (b) 226 | describe the limitations and the code they affect. Such description must 227 | be placed in a text file included with all distributions of the Covered 228 | Software under this License. Except to the extent prohibited by statute 229 | or regulation, such description must be sufficiently detailed for a 230 | recipient of ordinary skill to be able to understand it. 231 | 232 | 5. Termination 233 | -------------- 234 | 235 | 5.1. The rights granted under this License will terminate automatically 236 | if You fail to comply with any of its terms. However, if You become 237 | compliant, then the rights granted under this License from a particular 238 | Contributor are reinstated (a) provisionally, unless and until such 239 | Contributor explicitly and finally terminates Your grants, and (b) on an 240 | ongoing basis, if such Contributor fails to notify You of the 241 | non-compliance by some reasonable means prior to 60 days after You have 242 | come back into compliance. Moreover, Your grants from a particular 243 | Contributor are reinstated on an ongoing basis if such Contributor 244 | notifies You of the non-compliance by some reasonable means, this is the 245 | first time You have received notice of non-compliance with this License 246 | from such Contributor, and You become compliant prior to 30 days after 247 | Your receipt of the notice. 248 | 249 | 5.2. If You initiate litigation against any entity by asserting a patent 250 | infringement claim (excluding declaratory judgment actions, 251 | counter-claims, and cross-claims) alleging that a Contributor Version 252 | directly or indirectly infringes any patent, then the rights granted to 253 | You by any and all Contributors for the Covered Software under Section 254 | 2.1 of this License shall terminate. 255 | 256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 257 | end user license agreements (excluding distributors and resellers) which 258 | have been validly granted by You or Your distributors under this License 259 | prior to termination shall survive termination. 260 | 261 | ************************************************************************ 262 | * * 263 | * 6. Disclaimer of Warranty * 264 | * ------------------------- * 265 | * * 266 | * Covered Software is provided under this License on an "as is" * 267 | * basis, without warranty of any kind, either expressed, implied, or * 268 | * statutory, including, without limitation, warranties that the * 269 | * Covered Software is free of defects, merchantable, fit for a * 270 | * particular purpose or non-infringing. The entire risk as to the * 271 | * quality and performance of the Covered Software is with You. * 272 | * Should any Covered Software prove defective in any respect, You * 273 | * (not any Contributor) assume the cost of any necessary servicing, * 274 | * repair, or correction. This disclaimer of warranty constitutes an * 275 | * essential part of this License. No use of any Covered Software is * 276 | * authorized under this License except under this disclaimer. * 277 | * * 278 | ************************************************************************ 279 | 280 | ************************************************************************ 281 | * * 282 | * 7. Limitation of Liability * 283 | * -------------------------- * 284 | * * 285 | * Under no circumstances and under no legal theory, whether tort * 286 | * (including negligence), contract, or otherwise, shall any * 287 | * Contributor, or anyone who distributes Covered Software as * 288 | * permitted above, be liable to You for any direct, indirect, * 289 | * special, incidental, or consequential damages of any character * 290 | * including, without limitation, damages for lost profits, loss of * 291 | * goodwill, work stoppage, computer failure or malfunction, or any * 292 | * and all other commercial damages or losses, even if such party * 293 | * shall have been informed of the possibility of such damages. This * 294 | * limitation of liability shall not apply to liability for death or * 295 | * personal injury resulting from such party's negligence to the * 296 | * extent applicable law prohibits such limitation. Some * 297 | * jurisdictions do not allow the exclusion or limitation of * 298 | * incidental or consequential damages, so this exclusion and * 299 | * limitation may not apply to You. * 300 | * * 301 | ************************************************************************ 302 | 303 | 8. Litigation 304 | ------------- 305 | 306 | Any litigation relating to this License may be brought only in the 307 | courts of a jurisdiction where the defendant maintains its principal 308 | place of business and such litigation shall be governed by laws of that 309 | jurisdiction, without reference to its conflict-of-law provisions. 310 | Nothing in this Section shall prevent a party's ability to bring 311 | cross-claims or counter-claims. 312 | 313 | 9. Miscellaneous 314 | ---------------- 315 | 316 | This License represents the complete agreement concerning the subject 317 | matter hereof. If any provision of this License is held to be 318 | unenforceable, such provision shall be reformed only to the extent 319 | necessary to make it enforceable. Any law or regulation which provides 320 | that the language of a contract shall be construed against the drafter 321 | shall not be used to construe this License against a Contributor. 322 | 323 | 10. Versions of the License 324 | --------------------------- 325 | 326 | 10.1. New Versions 327 | 328 | Mozilla Foundation is the license steward. Except as provided in Section 329 | 10.3, no one other than the license steward has the right to modify or 330 | publish new versions of this License. Each version will be given a 331 | distinguishing version number. 332 | 333 | 10.2. Effect of New Versions 334 | 335 | You may distribute the Covered Software under the terms of the version 336 | of the License under which You originally received the Covered Software, 337 | or under the terms of any subsequent version published by the license 338 | steward. 339 | 340 | 10.3. Modified Versions 341 | 342 | If you create software not governed by this License, and you want to 343 | create a new license for such software, you may create and use a 344 | modified version of this License if you rename the license and remove 345 | any references to the name of the license steward (except to note that 346 | such modified license differs from this License). 347 | 348 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 349 | Licenses 350 | 351 | If You choose to distribute Source Code Form that is Incompatible With 352 | Secondary Licenses under the terms of this version of the License, the 353 | notice described in Exhibit B of this License must be attached. 354 | 355 | Exhibit A - Source Code Form License Notice 356 | ------------------------------------------- 357 | 358 | This Source Code Form is subject to the terms of the Mozilla Public 359 | License, v. 2.0. If a copy of the MPL was not distributed with this 360 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 361 | 362 | If it is not possible or desirable to put the notice in a particular 363 | file, then You may include the notice in a location (such as a LICENSE 364 | file in a relevant directory) where a recipient would be likely to look 365 | for such a notice. 366 | 367 | You may add additional accurate notices of copyright ownership. 368 | 369 | Exhibit B - "Incompatible With Secondary Licenses" Notice 370 | --------------------------------------------------------- 371 | 372 | This Source Code Form is "Incompatible With Secondary Licenses", as 373 | defined by the Mozilla Public License, v. 2.0. 374 | -------------------------------------------------------------------------------- /zmq/z85/z85.pony: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | primitive Z85 6 | // Maps base 256 to base 85 7 | fun tag encode_table(): Array[U8] val => recover [as U8: 8 | '0'; '1'; '2'; '3'; '4'; '5'; '6'; '7'; '8'; '9' 9 | 'a'; 'b'; 'c'; 'd'; 'e'; 'f'; 'g'; 'h'; 'i'; 'j' 10 | 'k'; 'l'; 'm'; 'n'; 'o'; 'p'; 'q'; 'r'; 's'; 't' 11 | 'u'; 'v'; 'w'; 'x'; 'y'; 'z'; 'A'; 'B'; 'C'; 'D' 12 | 'E'; 'F'; 'G'; 'H'; 'I'; 'J'; 'K'; 'L'; 'M'; 'N' 13 | 'O'; 'P'; 'Q'; 'R'; 'S'; 'T'; 'U'; 'V'; 'W'; 'X' 14 | 'Y'; 'Z'; '.'; '-'; ':'; '+'; '='; '^'; '!'; '/' 15 | '*'; '?'; '&'; '<'; '>'; '('; ')'; '['; ']'; '{' 16 | '}'; '@'; '%'; '$'; '#' 17 | ] end 18 | 19 | // Maps base 85 to base 256 (over a partial range starting with 33 at idx 0) 20 | fun tag decode_table(): Array[(U8 | None)] val => recover [as (U8 | None): 21 | None; 0x44; None; 0x54; 0x53; 0x52; 0x48; None 22 | 0x4B; 0x4C; 0x46; 0x41; None; 0x3F; 0x3E; 0x45 23 | 0x00; 0x01; 0x02; 0x03; 0x04; 0x05; 0x06; 0x07 24 | 0x08; 0x09; 0x40; None; 0x49; 0x42; 0x4A; 0x47 25 | 0x51; 0x24; 0x25; 0x26; 0x27; 0x28; 0x29; 0x2A 26 | 0x2B; 0x2C; 0x2D; 0x2E; 0x2F; 0x30; 0x31; 0x32 27 | 0x33; 0x34; 0x35; 0x36; 0x37; 0x38; 0x39; 0x3A 28 | 0x3B; 0x3C; 0x3D; 0x4D; None; 0x4E; 0x43; None 29 | None; 0x0A; 0x0B; 0x0C; 0x0D; 0x0E; 0x0F; 0x10 30 | 0x11; 0x12; 0x13; 0x14; 0x15; 0x16; 0x17; 0x18 31 | 0x19; 0x1A; 0x1B; 0x1C; 0x1D; 0x1E; 0x1F; 0x20 32 | 0x21; 0x22; 0x23; 0x4F; None; 0x50; None; None 33 | ] end 34 | 35 | fun tag encode(input: ReadSeq[U8]): String? => 36 | if (input.size() % 4) != 0 then error end 37 | 38 | let table = encode_table() 39 | var output = recover trn String end 40 | 41 | var u32: U32 = 0 42 | var idx: U8 = 0 43 | for byte in input.values() do 44 | u32 = (u32 << 8) + byte.u32() 45 | if idx == 3 then 46 | output.push(table(((u32 / 52200625) % 85).usize())?) 47 | output.push(table(((u32 / 614125) % 85).usize())?) 48 | output.push(table(((u32 / 7225) % 85).usize())?) 49 | output.push(table(((u32 / 85) % 85).usize())?) 50 | output.push(table(((u32 ) % 85).usize())?) 51 | u32 = 0 end 52 | idx = (idx + 1) % 4 end 53 | 54 | output 55 | 56 | fun tag decode(input: ReadSeq[U8]): String? => 57 | if (input.size() % 5) != 0 then error end 58 | 59 | let table = decode_table() 60 | var output = recover trn String end 61 | 62 | var u32: U32 = 0 63 | var idx: U8 = 0 64 | for byte in input.values() do 65 | u32 = (u32 * 85) + (table(byte.usize() - 32)? as U8).u32() 66 | if idx == 4 then 67 | output.push((u32 >> 24).u8()) 68 | output.push((u32 >> 16).u8()) 69 | output.push((u32 >> 8).u8()) 70 | output.push((u32 ).u8()) 71 | u32 = 0 end 72 | idx = (idx + 1) % 5 end 73 | 74 | output 75 | -------------------------------------------------------------------------------- /zmq/zmtp/LICENSE: -------------------------------------------------------------------------------- 1 | Mozilla Public License Version 2.0 2 | ================================== 3 | 4 | 1. Definitions 5 | -------------- 6 | 7 | 1.1. "Contributor" 8 | means each individual or legal entity that creates, contributes to 9 | the creation of, or owns Covered Software. 10 | 11 | 1.2. "Contributor Version" 12 | means the combination of the Contributions of others (if any) used 13 | by a Contributor and that particular Contributor's Contribution. 14 | 15 | 1.3. "Contribution" 16 | means Covered Software of a particular Contributor. 17 | 18 | 1.4. "Covered Software" 19 | means Source Code Form to which the initial Contributor has attached 20 | the notice in Exhibit A, the Executable Form of such Source Code 21 | Form, and Modifications of such Source Code Form, in each case 22 | including portions thereof. 23 | 24 | 1.5. "Incompatible With Secondary Licenses" 25 | means 26 | 27 | (a) that the initial Contributor has attached the notice described 28 | in Exhibit B to the Covered Software; or 29 | 30 | (b) that the Covered Software was made available under the terms of 31 | version 1.1 or earlier of the License, but not also under the 32 | terms of a Secondary License. 33 | 34 | 1.6. "Executable Form" 35 | means any form of the work other than Source Code Form. 36 | 37 | 1.7. "Larger Work" 38 | means a work that combines Covered Software with other material, in 39 | a separate file or files, that is not Covered Software. 40 | 41 | 1.8. "License" 42 | means this document. 43 | 44 | 1.9. "Licensable" 45 | means having the right to grant, to the maximum extent possible, 46 | whether at the time of the initial grant or subsequently, any and 47 | all of the rights conveyed by this License. 48 | 49 | 1.10. "Modifications" 50 | means any of the following: 51 | 52 | (a) any file in Source Code Form that results from an addition to, 53 | deletion from, or modification of the contents of Covered 54 | Software; or 55 | 56 | (b) any new file in Source Code Form that contains any Covered 57 | Software. 58 | 59 | 1.11. "Patent Claims" of a Contributor 60 | means any patent claim(s), including without limitation, method, 61 | process, and apparatus claims, in any patent Licensable by such 62 | Contributor that would be infringed, but for the grant of the 63 | License, by the making, using, selling, offering for sale, having 64 | made, import, or transfer of either its Contributions or its 65 | Contributor Version. 66 | 67 | 1.12. "Secondary License" 68 | means either the GNU General Public License, Version 2.0, the GNU 69 | Lesser General Public License, Version 2.1, the GNU Affero General 70 | Public License, Version 3.0, or any later versions of those 71 | licenses. 72 | 73 | 1.13. "Source Code Form" 74 | means the form of the work preferred for making modifications. 75 | 76 | 1.14. "You" (or "Your") 77 | means an individual or a legal entity exercising rights under this 78 | License. For legal entities, "You" includes any entity that 79 | controls, is controlled by, or is under common control with You. For 80 | purposes of this definition, "control" means (a) the power, direct 81 | or indirect, to cause the direction or management of such entity, 82 | whether by contract or otherwise, or (b) ownership of more than 83 | fifty percent (50%) of the outstanding shares or beneficial 84 | ownership of such entity. 85 | 86 | 2. License Grants and Conditions 87 | -------------------------------- 88 | 89 | 2.1. Grants 90 | 91 | Each Contributor hereby grants You a world-wide, royalty-free, 92 | non-exclusive license: 93 | 94 | (a) under intellectual property rights (other than patent or trademark) 95 | Licensable by such Contributor to use, reproduce, make available, 96 | modify, display, perform, distribute, and otherwise exploit its 97 | Contributions, either on an unmodified basis, with Modifications, or 98 | as part of a Larger Work; and 99 | 100 | (b) under Patent Claims of such Contributor to make, use, sell, offer 101 | for sale, have made, import, and otherwise transfer either its 102 | Contributions or its Contributor Version. 103 | 104 | 2.2. Effective Date 105 | 106 | The licenses granted in Section 2.1 with respect to any Contribution 107 | become effective for each Contribution on the date the Contributor first 108 | distributes such Contribution. 109 | 110 | 2.3. Limitations on Grant Scope 111 | 112 | The licenses granted in this Section 2 are the only rights granted under 113 | this License. No additional rights or licenses will be implied from the 114 | distribution or licensing of Covered Software under this License. 115 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 116 | Contributor: 117 | 118 | (a) for any code that a Contributor has removed from Covered Software; 119 | or 120 | 121 | (b) for infringements caused by: (i) Your and any other third party's 122 | modifications of Covered Software, or (ii) the combination of its 123 | Contributions with other software (except as part of its Contributor 124 | Version); or 125 | 126 | (c) under Patent Claims infringed by Covered Software in the absence of 127 | its Contributions. 128 | 129 | This License does not grant any rights in the trademarks, service marks, 130 | or logos of any Contributor (except as may be necessary to comply with 131 | the notice requirements in Section 3.4). 132 | 133 | 2.4. Subsequent Licenses 134 | 135 | No Contributor makes additional grants as a result of Your choice to 136 | distribute the Covered Software under a subsequent version of this 137 | License (see Section 10.2) or under the terms of a Secondary License (if 138 | permitted under the terms of Section 3.3). 139 | 140 | 2.5. Representation 141 | 142 | Each Contributor represents that the Contributor believes its 143 | Contributions are its original creation(s) or it has sufficient rights 144 | to grant the rights to its Contributions conveyed by this License. 145 | 146 | 2.6. Fair Use 147 | 148 | This License is not intended to limit any rights You have under 149 | applicable copyright doctrines of fair use, fair dealing, or other 150 | equivalents. 151 | 152 | 2.7. Conditions 153 | 154 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 155 | in Section 2.1. 156 | 157 | 3. Responsibilities 158 | ------------------- 159 | 160 | 3.1. Distribution of Source Form 161 | 162 | All distribution of Covered Software in Source Code Form, including any 163 | Modifications that You create or to which You contribute, must be under 164 | the terms of this License. You must inform recipients that the Source 165 | Code Form of the Covered Software is governed by the terms of this 166 | License, and how they can obtain a copy of this License. You may not 167 | attempt to alter or restrict the recipients' rights in the Source Code 168 | Form. 169 | 170 | 3.2. Distribution of Executable Form 171 | 172 | If You distribute Covered Software in Executable Form then: 173 | 174 | (a) such Covered Software must also be made available in Source Code 175 | Form, as described in Section 3.1, and You must inform recipients of 176 | the Executable Form how they can obtain a copy of such Source Code 177 | Form by reasonable means in a timely manner, at a charge no more 178 | than the cost of distribution to the recipient; and 179 | 180 | (b) You may distribute such Executable Form under the terms of this 181 | License, or sublicense it under different terms, provided that the 182 | license for the Executable Form does not attempt to limit or alter 183 | the recipients' rights in the Source Code Form under this License. 184 | 185 | 3.3. Distribution of a Larger Work 186 | 187 | You may create and distribute a Larger Work under terms of Your choice, 188 | provided that You also comply with the requirements of this License for 189 | the Covered Software. If the Larger Work is a combination of Covered 190 | Software with a work governed by one or more Secondary Licenses, and the 191 | Covered Software is not Incompatible With Secondary Licenses, this 192 | License permits You to additionally distribute such Covered Software 193 | under the terms of such Secondary License(s), so that the recipient of 194 | the Larger Work may, at their option, further distribute the Covered 195 | Software under the terms of either this License or such Secondary 196 | License(s). 197 | 198 | 3.4. Notices 199 | 200 | You may not remove or alter the substance of any license notices 201 | (including copyright notices, patent notices, disclaimers of warranty, 202 | or limitations of liability) contained within the Source Code Form of 203 | the Covered Software, except that You may alter any license notices to 204 | the extent required to remedy known factual inaccuracies. 205 | 206 | 3.5. Application of Additional Terms 207 | 208 | You may choose to offer, and to charge a fee for, warranty, support, 209 | indemnity or liability obligations to one or more recipients of Covered 210 | Software. However, You may do so only on Your own behalf, and not on 211 | behalf of any Contributor. You must make it absolutely clear that any 212 | such warranty, support, indemnity, or liability obligation is offered by 213 | You alone, and You hereby agree to indemnify every Contributor for any 214 | liability incurred by such Contributor as a result of warranty, support, 215 | indemnity or liability terms You offer. You may include additional 216 | disclaimers of warranty and limitations of liability specific to any 217 | jurisdiction. 218 | 219 | 4. Inability to Comply Due to Statute or Regulation 220 | --------------------------------------------------- 221 | 222 | If it is impossible for You to comply with any of the terms of this 223 | License with respect to some or all of the Covered Software due to 224 | statute, judicial order, or regulation then You must: (a) comply with 225 | the terms of this License to the maximum extent possible; and (b) 226 | describe the limitations and the code they affect. Such description must 227 | be placed in a text file included with all distributions of the Covered 228 | Software under this License. Except to the extent prohibited by statute 229 | or regulation, such description must be sufficiently detailed for a 230 | recipient of ordinary skill to be able to understand it. 231 | 232 | 5. Termination 233 | -------------- 234 | 235 | 5.1. The rights granted under this License will terminate automatically 236 | if You fail to comply with any of its terms. However, if You become 237 | compliant, then the rights granted under this License from a particular 238 | Contributor are reinstated (a) provisionally, unless and until such 239 | Contributor explicitly and finally terminates Your grants, and (b) on an 240 | ongoing basis, if such Contributor fails to notify You of the 241 | non-compliance by some reasonable means prior to 60 days after You have 242 | come back into compliance. Moreover, Your grants from a particular 243 | Contributor are reinstated on an ongoing basis if such Contributor 244 | notifies You of the non-compliance by some reasonable means, this is the 245 | first time You have received notice of non-compliance with this License 246 | from such Contributor, and You become compliant prior to 30 days after 247 | Your receipt of the notice. 248 | 249 | 5.2. If You initiate litigation against any entity by asserting a patent 250 | infringement claim (excluding declaratory judgment actions, 251 | counter-claims, and cross-claims) alleging that a Contributor Version 252 | directly or indirectly infringes any patent, then the rights granted to 253 | You by any and all Contributors for the Covered Software under Section 254 | 2.1 of this License shall terminate. 255 | 256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 257 | end user license agreements (excluding distributors and resellers) which 258 | have been validly granted by You or Your distributors under this License 259 | prior to termination shall survive termination. 260 | 261 | ************************************************************************ 262 | * * 263 | * 6. Disclaimer of Warranty * 264 | * ------------------------- * 265 | * * 266 | * Covered Software is provided under this License on an "as is" * 267 | * basis, without warranty of any kind, either expressed, implied, or * 268 | * statutory, including, without limitation, warranties that the * 269 | * Covered Software is free of defects, merchantable, fit for a * 270 | * particular purpose or non-infringing. The entire risk as to the * 271 | * quality and performance of the Covered Software is with You. * 272 | * Should any Covered Software prove defective in any respect, You * 273 | * (not any Contributor) assume the cost of any necessary servicing, * 274 | * repair, or correction. This disclaimer of warranty constitutes an * 275 | * essential part of this License. No use of any Covered Software is * 276 | * authorized under this License except under this disclaimer. * 277 | * * 278 | ************************************************************************ 279 | 280 | ************************************************************************ 281 | * * 282 | * 7. Limitation of Liability * 283 | * -------------------------- * 284 | * * 285 | * Under no circumstances and under no legal theory, whether tort * 286 | * (including negligence), contract, or otherwise, shall any * 287 | * Contributor, or anyone who distributes Covered Software as * 288 | * permitted above, be liable to You for any direct, indirect, * 289 | * special, incidental, or consequential damages of any character * 290 | * including, without limitation, damages for lost profits, loss of * 291 | * goodwill, work stoppage, computer failure or malfunction, or any * 292 | * and all other commercial damages or losses, even if such party * 293 | * shall have been informed of the possibility of such damages. This * 294 | * limitation of liability shall not apply to liability for death or * 295 | * personal injury resulting from such party's negligence to the * 296 | * extent applicable law prohibits such limitation. Some * 297 | * jurisdictions do not allow the exclusion or limitation of * 298 | * incidental or consequential damages, so this exclusion and * 299 | * limitation may not apply to You. * 300 | * * 301 | ************************************************************************ 302 | 303 | 8. Litigation 304 | ------------- 305 | 306 | Any litigation relating to this License may be brought only in the 307 | courts of a jurisdiction where the defendant maintains its principal 308 | place of business and such litigation shall be governed by laws of that 309 | jurisdiction, without reference to its conflict-of-law provisions. 310 | Nothing in this Section shall prevent a party's ability to bring 311 | cross-claims or counter-claims. 312 | 313 | 9. Miscellaneous 314 | ---------------- 315 | 316 | This License represents the complete agreement concerning the subject 317 | matter hereof. If any provision of this License is held to be 318 | unenforceable, such provision shall be reformed only to the extent 319 | necessary to make it enforceable. Any law or regulation which provides 320 | that the language of a contract shall be construed against the drafter 321 | shall not be used to construe this License against a Contributor. 322 | 323 | 10. Versions of the License 324 | --------------------------- 325 | 326 | 10.1. New Versions 327 | 328 | Mozilla Foundation is the license steward. Except as provided in Section 329 | 10.3, no one other than the license steward has the right to modify or 330 | publish new versions of this License. Each version will be given a 331 | distinguishing version number. 332 | 333 | 10.2. Effect of New Versions 334 | 335 | You may distribute the Covered Software under the terms of the version 336 | of the License under which You originally received the Covered Software, 337 | or under the terms of any subsequent version published by the license 338 | steward. 339 | 340 | 10.3. Modified Versions 341 | 342 | If you create software not governed by this License, and you want to 343 | create a new license for such software, you may create and use a 344 | modified version of this License if you rename the license and remove 345 | any references to the name of the license steward (except to note that 346 | such modified license differs from this License). 347 | 348 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 349 | Licenses 350 | 351 | If You choose to distribute Source Code Form that is Incompatible With 352 | Secondary Licenses under the terms of this version of the License, the 353 | notice described in Exhibit B of this License must be attached. 354 | 355 | Exhibit A - Source Code Form License Notice 356 | ------------------------------------------- 357 | 358 | This Source Code Form is subject to the terms of the Mozilla Public 359 | License, v. 2.0. If a copy of the MPL was not distributed with this 360 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 361 | 362 | If it is not possible or desirable to put the notice in a particular 363 | file, then You may include the notice in a location (such as a LICENSE 364 | file in a relevant directory) where a recipient would be likely to look 365 | for such a notice. 366 | 367 | You may add additional accurate notices of copyright ownership. 368 | 369 | Exhibit B - "Incompatible With Secondary Licenses" Notice 370 | --------------------------------------------------------- 371 | 372 | This Source Code Form is "Incompatible With Secondary Licenses", as 373 | defined by the Mozilla Public License, v. 2.0. 374 | -------------------------------------------------------------------------------- /zmq/zmtp/_buffer.pony: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | use buffered = "buffered" 6 | 7 | type _Buffer is buffered.Reader 8 | -------------------------------------------------------------------------------- /zmq/zmtp/_curve_message_writer.pony: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | use "sodium" 6 | 7 | class _CurveMessageWriter is MessageWriteTransform 8 | let sk: CryptoBoxSecretKey 9 | let pk: CryptoBoxPublicKey 10 | let nonce_gen: _CurveNonceGenerator 11 | let nonce_prefix: String 12 | 13 | new create(sk': CryptoBoxSecretKey, pk': CryptoBoxPublicKey, 14 | nonce_gen': _CurveNonceGenerator, nonce_prefix': String 15 | ) => 16 | sk = sk'; pk = pk'; nonce_gen = nonce_gen'; nonce_prefix = nonce_prefix' 17 | 18 | fun ref apply(message: Message box): Array[U8] val => 19 | let output = recover trn Array[U8] end 20 | 21 | for node in message.nodes() do 22 | let frame': (Frame | None) = try node()? else None end 23 | 24 | match frame' | let frame: Frame => 25 | let message_box = CommandAuthCurveMessageBox 26 | message_box.has_more = node.has_next() 27 | message_box.payload = frame 28 | 29 | let command = CommandAuthCurveMessage 30 | let short_nonce = nonce_gen.next_short() 31 | let nonce = CryptoBoxNonce(nonce_prefix + short_nonce) 32 | command.short_nonce = short_nonce 33 | command.data_box = try CryptoBox(message_box.string(), nonce, sk, pk)? else 34 | "" // TODO: some way to protocol-error from here? 35 | end 36 | output.append(CommandParser.write(command)) 37 | end 38 | end 39 | 40 | output 41 | -------------------------------------------------------------------------------- /zmq/zmtp/_curve_nonce_generator.pony: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | use "sodium" 6 | 7 | class _CurveNonceGenerator 8 | var _next_short: U64 = 1 9 | 10 | new iso create() => None 11 | 12 | fun ref next_short(): String => 13 | let out = recover trn String end 14 | out.push((_next_short >> 56).u8()) 15 | out.push((_next_short >> 48).u8()) 16 | out.push((_next_short >> 40).u8()) 17 | out.push((_next_short >> 32).u8()) 18 | out.push((_next_short >> 24).u8()) 19 | out.push((_next_short >> 16).u8()) 20 | out.push((_next_short >> 8).u8()) 21 | out.push((_next_short >> 0).u8()) 22 | _next_short = _next_short + 1 // TODO: reconnect on overflow 23 | consume out 24 | 25 | fun tag next_long(): String => 26 | recover CryptoBox.random_bytes(16) end 27 | -------------------------------------------------------------------------------- /zmq/zmtp/command.pony: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | use "collections" 6 | 7 | interface Command 8 | new ref create() 9 | fun name(): String val 10 | fun bytes(): Array[U8] val 11 | fun ref apply(orig: CommandUnknown)? 12 | 13 | type CommandMetadata is Map[String, String] 14 | 15 | class CommandUtil 16 | fun tag read_string_as_metadata(metadata: CommandMetadata, string: String) => 17 | let bytes = recover trn Array[U8] end 18 | for byte in string.values() do 19 | bytes.push(byte) 20 | end 21 | read_bytes_as_metadata(metadata, consume bytes) 22 | 23 | fun tag write_string_as_metadata(metadata: CommandMetadata box): String => 24 | let bytes = write_bytes_as_metadata(metadata) 25 | recover val String.>append(bytes) end 26 | 27 | fun tag read_bytes_as_metadata(metadata: CommandMetadata, bytes: Array[U8] val) => 28 | let buffer = _Buffer.>append(bytes) 29 | if metadata.size() > 0 then metadata.clear() end 30 | 31 | while buffer.size() > 0 do 32 | try 33 | let key = recover iso String end 34 | let value = recover iso String end 35 | 36 | let key_size = USize.from[U8](buffer.u8()?) 37 | key.append(buffer.block(key_size)?) 38 | let value_size = USize.from[U32](buffer.u32_be()?) 39 | value.append(buffer.block(value_size)?) 40 | 41 | metadata(consume key) = consume value 42 | end 43 | end 44 | 45 | fun tag write_bytes_as_metadata(metadata: CommandMetadata box): Array[U8] val => 46 | let output = recover trn Array[U8] end 47 | 48 | for (key, value) in metadata.pairs() do 49 | output.push(key.size().u8()) 50 | output.append(key) 51 | output.append(_Util.make_bytes(value.size().u32())) 52 | output.append(value) 53 | end 54 | 55 | output 56 | 57 | class CommandUnknown 58 | let _name: String 59 | let _bytes: Array[U8] val 60 | fun name(): String => _name 61 | fun bytes(): Array[U8] val => _bytes 62 | new create(name': String, bytes': Array[U8] val) => 63 | _name = name' 64 | _bytes = bytes' 65 | -------------------------------------------------------------------------------- /zmq/zmtp/command_auth_curve.pony: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | use "collections" 6 | use "sodium" 7 | 8 | class CommandAuthCurveHello is Command 9 | var version_major: U8 = 1 10 | var version_minor: U8 = 0 11 | var ct_pk: CryptoBoxPublicKey = CryptoBoxPublicKey("") 12 | var short_nonce: String = "" 13 | var signature_box: String = "" 14 | 15 | new create() => None 16 | fun name(): String => "HELLO" 17 | 18 | fun bytes(): Array[U8] val => 19 | let output = recover trn Array[U8] end 20 | output.push(version_major) 21 | output.push(version_minor) 22 | output.append(recover [as U8: 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0 23 | 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0 24 | 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0 25 | 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0] end) 26 | output.append(ct_pk.string()) 27 | output.append(short_nonce) 28 | output.append(signature_box) 29 | output 30 | 31 | fun ref apply(orig: CommandUnknown)? => 32 | if orig.name() != name() then error end 33 | let orig_bytes = orig.bytes() 34 | let buffer = recover iso _Buffer.>append(orig_bytes) end 35 | 36 | version_major = buffer.u8()? 37 | version_minor = buffer.u8()? 38 | buffer.skip(72)? // anti-amplification padding 39 | ct_pk = CryptoBoxPublicKey(recover String.>append(buffer.block(32)?) end) 40 | short_nonce = recover String.>append(buffer.block(8)?) end 41 | signature_box = recover String.>append(buffer.block(80)?) end 42 | 43 | class CommandAuthCurveWelcome is Command 44 | var long_nonce: String = "" 45 | var data_box: String = "" 46 | 47 | new create() => None 48 | fun name(): String => "WELCOME" 49 | 50 | fun bytes(): Array[U8] val => 51 | let output = recover trn Array[U8] end 52 | output.append(long_nonce) 53 | output.append(data_box) 54 | output 55 | 56 | fun ref apply(orig: CommandUnknown)? => 57 | if orig.name() != name() then error end 58 | let orig_bytes = orig.bytes() 59 | let buffer = recover iso _Buffer.>append(orig_bytes) end 60 | 61 | long_nonce = recover String.>append(buffer.block(16)?) end 62 | data_box = recover String.>append(buffer.block(144)?) end 63 | 64 | class CommandAuthCurveInitiate is Command 65 | var cookie: String = "" 66 | var short_nonce: String = "" 67 | var data_box: String = "" 68 | 69 | new create() => None 70 | fun name(): String => "INITIATE" 71 | 72 | fun bytes(): Array[U8] val => 73 | let output = recover trn Array[U8] end 74 | output.append(cookie) 75 | output.append(short_nonce) 76 | output.append(data_box) 77 | output 78 | 79 | fun ref apply(orig: CommandUnknown)? => 80 | if orig.name() != name() then error end 81 | let orig_bytes = orig.bytes() 82 | let buffer = recover iso _Buffer.>append(orig_bytes) end 83 | 84 | cookie = recover String.>append(buffer.block(96)?) end 85 | short_nonce = recover String.>append(buffer.block(8)?) end 86 | data_box = recover String.>append(buffer.block(buffer.size())?) end 87 | 88 | class CommandAuthCurveReady is Command 89 | var short_nonce: String = "" 90 | var data_box: String = "" 91 | 92 | new create() => None 93 | fun name(): String => "READY" 94 | 95 | fun bytes(): Array[U8] val => 96 | let output = recover trn Array[U8] end 97 | output.append(short_nonce) 98 | output.append(data_box) 99 | output 100 | 101 | fun ref apply(orig: CommandUnknown)? => 102 | if orig.name() != name() then error end 103 | let orig_bytes = orig.bytes() 104 | let buffer = recover iso _Buffer.>append(orig_bytes) end 105 | 106 | short_nonce = recover String.>append(buffer.block(8)?) end 107 | data_box = recover String.>append(buffer.block(buffer.size())?) end 108 | 109 | class CommandAuthCurveError is Command 110 | var reason: String = "" 111 | 112 | new create() => None 113 | fun name(): String => "ERROR" 114 | 115 | fun bytes(): Array[U8] val => 116 | let output = recover trn Array[U8] end 117 | output.append(reason) 118 | output 119 | 120 | fun ref apply(orig: CommandUnknown)? => 121 | if orig.name() != name() then error end 122 | let orig_bytes = orig.bytes() 123 | reason = recover String.>append(orig_bytes) end 124 | 125 | class CommandAuthCurveMessage is Command 126 | var short_nonce: String = "" 127 | var data_box: String = "" 128 | 129 | new create() => None 130 | fun name(): String => "MESSAGE" 131 | 132 | fun bytes(): Array[U8] val => 133 | let output = recover trn Array[U8] end 134 | output.append(short_nonce) 135 | output.append(data_box) 136 | output 137 | 138 | fun ref apply(orig: CommandUnknown)? => 139 | if orig.name() != name() then error end 140 | let orig_bytes = orig.bytes() 141 | let buffer = recover iso _Buffer.>append(orig_bytes) end 142 | 143 | short_nonce = recover String.>append(buffer.block(8)?) end 144 | data_box = recover String.>append(buffer.block(buffer.size())?) end 145 | 146 | /// 147 | // Encrypted boxes inside of Commands 148 | 149 | class CommandAuthCurveWelcomeBox 150 | var st_pk: CryptoBoxPublicKey = CryptoBoxPublicKey("") 151 | var cookie: String = "" 152 | 153 | fun string(): String => 154 | let output = recover trn String end 155 | output.append(st_pk.string()) 156 | output.append(cookie) 157 | output 158 | 159 | fun ref apply(data: String): CommandAuthCurveWelcomeBox => 160 | st_pk = CryptoBoxPublicKey(data.substring(0, 32)) 161 | cookie = data.substring(32) 162 | this 163 | 164 | class CommandAuthCurveInitiateBox 165 | var c_pk: CryptoBoxPublicKey = CryptoBoxPublicKey("") 166 | var long_nonce: String = "" 167 | var vouch_box: String = "" 168 | let metadata: CommandMetadata = metadata.create() 169 | 170 | fun string(): String => 171 | let output = recover trn String end 172 | output.append(c_pk.string()) 173 | output.append(long_nonce) 174 | output.append(vouch_box) 175 | output.append(CommandUtil.write_bytes_as_metadata(metadata)) 176 | output 177 | 178 | fun ref apply(data: String): CommandAuthCurveInitiateBox => 179 | c_pk = CryptoBoxPublicKey(data.substring(0, 32)) 180 | long_nonce = data.substring(32, 48) 181 | vouch_box = data.substring(48, 128) 182 | CommandUtil.read_string_as_metadata(metadata, data.substring(128)) 183 | this 184 | 185 | class CommandAuthCurveInitiateVouchBox 186 | var ct_pk: CryptoBoxPublicKey = CryptoBoxPublicKey("") 187 | var s_pk: CryptoBoxPublicKey = CryptoBoxPublicKey("") 188 | 189 | fun string(): String => 190 | let output = recover trn String end 191 | output.append(ct_pk.string()) 192 | output.append(s_pk.string()) 193 | output 194 | 195 | fun ref apply(data: String): CommandAuthCurveInitiateVouchBox => 196 | ct_pk = CryptoBoxPublicKey(data.substring(0, 32)) 197 | s_pk = CryptoBoxPublicKey(data.substring(32, 64)) 198 | this 199 | 200 | class CommandAuthCurveReadyBox 201 | let metadata: CommandMetadata = metadata.create() 202 | 203 | fun string(): String => 204 | let output = recover trn String end 205 | output.append(CommandUtil.write_bytes_as_metadata(metadata)) 206 | output 207 | 208 | fun ref apply(data: String): CommandAuthCurveReadyBox => 209 | CommandUtil.read_string_as_metadata(metadata, data) 210 | this 211 | 212 | class CommandAuthCurveMessageBox 213 | var has_more: Bool = false 214 | var payload: Frame = "" 215 | 216 | fun string(): String => 217 | let output = recover trn String end 218 | let flags: U8 = if has_more then 0x01 else 0x00 end 219 | output.push(flags) 220 | output.append(payload) 221 | output 222 | 223 | fun ref apply(data: String): CommandAuthCurveMessageBox => 224 | let flags = try data(0)? else 0x00 end 225 | has_more = flags != 0x00 226 | payload = data.substring(1) 227 | this 228 | -------------------------------------------------------------------------------- /zmq/zmtp/command_auth_null.pony: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | use "collections" 6 | 7 | class CommandAuthNullReady is Command 8 | let metadata: CommandMetadata = metadata.create() 9 | fun name(): String => "READY" 10 | fun bytes(): Array[U8] val => CommandUtil.write_bytes_as_metadata(metadata) 11 | new create() => None // TODO: figure out why ponyc default constructors are now iso as of 718c37398270b1a9fafa85a7ba2af286f4d53a5f 12 | fun ref apply(orig: CommandUnknown)? => 13 | if orig.name() != name() then error end 14 | CommandUtil.read_bytes_as_metadata(metadata, orig.bytes()) 15 | -------------------------------------------------------------------------------- /zmq/zmtp/command_parser.pony: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | use "format" 5 | 6 | primitive CommandParser 7 | fun write(command: Command box): Array[U8] val => 8 | let output = recover trn Array[U8] end 9 | let inner = recover trn Array[U8] end 10 | 11 | // Write name size, name, and body to inner byte array. 12 | let name = command.name() 13 | inner.push(name.size().u8()) 14 | inner.append(name) 15 | inner.append(command.bytes()) 16 | 17 | // Determine the ident and size bytewidth based on the size itself. 18 | let is_short = inner.size() <= 0xFF 19 | let ident: U8 = if is_short then 0x04 else 0x06 end 20 | let size = if is_short then inner.size().u8() else inner.size().u64() end 21 | 22 | // Write the ident, size, and the inner byte array to the output byte array. 23 | output.push(ident) 24 | output.append(_Util.make_bytes(size)) 25 | output.append(consume inner) 26 | 27 | output 28 | 29 | fun read(buffer: _Buffer, notify: SessionNotify): CommandUnknown? => 30 | var offset: USize = 0 31 | 32 | // Peek ident byte to determine number of size bytes, then peek size. 33 | let ident = buffer.peek_u8()?; offset = offset + 1 34 | let size = match ident 35 | | 0x04 => offset = offset + 1; USize.from[U8](buffer.peek_u8(1)?) 36 | | 0x06 => offset = offset + 8; buffer.peek_u64_be(1)?.usize() // TODO: this breaks for 32-bit systems - we need a better solution 37 | // Note that the following are not actually allowed by spec, 38 | // but they are used by the libzmq implementation for 39 | // CURVE MESSAGE commands, so we have to accept them for interop. 40 | | 0x00 => offset = offset + 1; USize.from[U8](buffer.peek_u8(1)?) 41 | | 0x01 => offset = offset + 1; USize.from[U8](buffer.peek_u8(1)?) 42 | | 0x02 => offset = offset + 8; buffer.peek_u64_be(1)?.usize() // TODO: this breaks for 32-bit systems - we need a better solution 43 | | 0x03 => offset = offset + 8; buffer.peek_u64_be(1)?.usize() // TODO: this breaks for 32-bit systems - we need a better solution 44 | else 45 | notify.protocol_error("unknown command ident byte: " + Format.int[U8](ident, FormatHex)) 46 | error 47 | end 48 | 49 | // Raise error if not all bytes are available yet. 50 | if buffer.size() < (offset + size) then error end 51 | 52 | // Skip the bytes obtained by peeking. 53 | buffer.skip(consume offset)? 54 | 55 | // Read the name size and name string. 56 | let name_size = USize.from[U8](buffer.u8()?) 57 | let name: String trn = recover String end 58 | name.append(buffer.block(name_size)?) 59 | 60 | // Read the rest of the body. 61 | let bytes: Array[U8] val = buffer.block(size - 1 - name_size)? 62 | 63 | CommandUnknown(consume name, consume bytes) 64 | -------------------------------------------------------------------------------- /zmq/zmtp/greeting.pony: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | primitive Greeting 6 | fun write(mechanism: String, as_server: Bool): Array[U8] val => 7 | let output: Array[U8] trn = recover Array[U8] end 8 | 9 | output.append(recover [as U8: 10 | 0xFF // signature-start 11 | 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00 // signature-padding 12 | 0x7F // signature-end 13 | 0x03; 0x00 // version(major, minor) 14 | ] end) 15 | 16 | for byte in mechanism.values() do output.push(byte) end 17 | output.append(recover Array[U8].init(0x00, 20 - mechanism.size()) end) 18 | 19 | output.push(if as_server then 0x01 else 0x00 end) 20 | 21 | output.append(recover [as U8: 22 | 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00 // filler 23 | 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00 // filler 24 | 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00 // filler 25 | 0x00 // filler 26 | ] end) 27 | 28 | output 29 | 30 | fun read(buffer: _Buffer ref, notify: SessionNotify, mechanism: String, 31 | as_server: Bool): String? 32 | => 33 | if buffer.size() < 64 then error end // try again later 34 | 35 | if buffer.u8()? != 0xFF then notify.protocol_error("signature-start"); error end 36 | buffer.skip(8)? // signature-padding 37 | if buffer.u8()? != 0x7F then notify.protocol_error("signature-end"); error end 38 | 39 | let version = buffer.u8()? 40 | if version < 0x03 then 41 | notify.protocol_error("version-major: " + version.string()) 42 | error 43 | end 44 | buffer.skip(1)? // version-minor 45 | 46 | let other_mechanism = String 47 | other_mechanism.>append(buffer.block(20)?).>strip(String.>push(0)) 48 | if mechanism != other_mechanism then 49 | notify.protocol_error("other mechanism: " + mechanism) 50 | error 51 | end 52 | 53 | // TODO: reinstate as-server check here 54 | buffer.skip(1)? // as-server 55 | // let other_as_server: Bool = buffer.u8() != 0x00 56 | // if (mechanism != "NULL") and (as_server is other_as_server) then 57 | // notify.protocol_error("other as-server: " + as_server.string()) 58 | // error 59 | // end 60 | 61 | buffer.skip(31)? // filler 62 | 63 | version.string() 64 | -------------------------------------------------------------------------------- /zmq/zmtp/mechanism.pony: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | interface Mechanism 6 | fun ref handle_start() 7 | fun ref handle_input(buffer: _Buffer ref) 8 | fun ref handle_zap_response(zap: ZapResponse) => None 9 | 10 | class MechanismNone is Mechanism 11 | fun ref handle_start() => None 12 | fun ref handle_input(buffer: _Buffer ref) => None 13 | -------------------------------------------------------------------------------- /zmq/zmtp/mechanism_auth_curve_client.pony: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | use "sodium" 6 | 7 | primitive _MechanismAuthCurveClientStateReadGreeting 8 | primitive _MechanismAuthCurveClientStateReadHandshakeWelcome 9 | primitive _MechanismAuthCurveClientStateReadHandshakeReady 10 | primitive _MechanismAuthCurveClientStateReadMessage 11 | 12 | type _MechanismAuthCurveClientState is 13 | ( _MechanismAuthCurveClientStateReadGreeting 14 | | _MechanismAuthCurveClientStateReadHandshakeWelcome 15 | | _MechanismAuthCurveClientStateReadHandshakeReady 16 | | _MechanismAuthCurveClientStateReadMessage) 17 | 18 | // TODO: improve performance with CryptoBox precomputation after handshake. 19 | class MechanismAuthCurveClient is Mechanism 20 | let _session: Session 21 | let _c_sk: CryptoBoxSecretKey 22 | let _c_pk: CryptoBoxPublicKey 23 | let _s_pk: CryptoBoxPublicKey 24 | let _ct_sk: CryptoBoxSecretKey 25 | let _ct_pk: CryptoBoxPublicKey 26 | var _st_pk: CryptoBoxPublicKey = CryptoBoxPublicKey("") 27 | 28 | var _state: _MechanismAuthCurveClientState = _MechanismAuthCurveClientStateReadGreeting 29 | var _nonce_gen: _CurveNonceGenerator iso = _nonce_gen.create() 30 | 31 | new create(session: Session, c_sk: CryptoBoxSecretKey, c_pk: CryptoBoxPublicKey, s_pk: CryptoBoxPublicKey) => 32 | _session = session 33 | _c_sk = c_sk 34 | _c_pk = c_pk 35 | _s_pk = s_pk 36 | (_ct_sk, _ct_pk) = try CryptoBox.keypair()? 37 | else (CryptoBoxSecretKey(""), CryptoBoxPublicKey("")) end 38 | 39 | fun ref _next_state(state: _MechanismAuthCurveClientState) => 40 | _state = state 41 | 42 | fun ref handle_input(buffer: _Buffer ref) => 43 | try while true do 44 | match _state 45 | | _MechanismAuthCurveClientStateReadGreeting => _read_greeting(buffer)? 46 | | _MechanismAuthCurveClientStateReadHandshakeWelcome => _read_welcome(buffer)? 47 | | _MechanismAuthCurveClientStateReadHandshakeReady => _read_ready(buffer)? 48 | | _MechanismAuthCurveClientStateReadMessage => _read_message(buffer)? 49 | end 50 | end end 51 | 52 | fun ref handle_start() => 53 | _next_state(_MechanismAuthCurveClientStateReadGreeting) 54 | _session._write_greeting() 55 | 56 | fun ref _read_greeting(buffer: _Buffer ref)? => 57 | _session._read_greeting(buffer)? 58 | _next_state(_MechanismAuthCurveClientStateReadHandshakeWelcome) 59 | _write_hello()? 60 | 61 | fun ref _write_hello()? => 62 | let command = CommandAuthCurveHello 63 | let short_nonce = _nonce_gen.next_short() 64 | let nonce = CryptoBoxNonce("CurveZMQHELLO---" + short_nonce) 65 | let signature = "\x00\x00\x00\x00\x00\x00\x00\x00" + 66 | "\x00\x00\x00\x00\x00\x00\x00\x00" + 67 | "\x00\x00\x00\x00\x00\x00\x00\x00" + 68 | "\x00\x00\x00\x00\x00\x00\x00\x00" + 69 | "\x00\x00\x00\x00\x00\x00\x00\x00" + 70 | "\x00\x00\x00\x00\x00\x00\x00\x00" + 71 | "\x00\x00\x00\x00\x00\x00\x00\x00" + 72 | "\x00\x00\x00\x00\x00\x00\x00\x00" 73 | command.ct_pk = _ct_pk 74 | command.short_nonce = short_nonce 75 | command.signature_box = try CryptoBox(signature, nonce, _ct_sk, _s_pk)? else 76 | _session.notify.protocol_error("couldn't encode HELLO box") 77 | error 78 | end 79 | _session._write_command(command) 80 | 81 | fun ref _read_welcome(buffer: _Buffer ref)? => 82 | // TODO: possibility of receiving ERROR command here. 83 | let command = _session._read_specific_command[CommandAuthCurveWelcome](buffer)? 84 | let nonce = CryptoBoxNonce("WELCOME-" + command.long_nonce) 85 | let data = try CryptoBox.open(command.data_box, nonce, _ct_sk, _s_pk)? else 86 | _session.notify.protocol_error("couldn't open WELCOME box") 87 | error 88 | end 89 | let welcome_box = CommandAuthCurveWelcomeBox(data) 90 | _st_pk = welcome_box.st_pk 91 | _next_state(_MechanismAuthCurveClientStateReadHandshakeReady) 92 | _write_initiate(welcome_box.cookie)? 93 | 94 | fun ref _write_initiate(cookie: String)? => 95 | let vouch_box = CommandAuthCurveInitiateVouchBox 96 | vouch_box.ct_pk = _ct_pk 97 | vouch_box.s_pk = _s_pk 98 | 99 | let initiate_box: CommandAuthCurveInitiateBox ref = CommandAuthCurveInitiateBox 100 | let vouch_long_nonce = _nonce_gen.next_long() 101 | let vouch_nonce = CryptoBoxNonce("VOUCH---" + vouch_long_nonce) 102 | initiate_box.c_pk = _c_pk 103 | initiate_box.long_nonce = vouch_long_nonce 104 | initiate_box.vouch_box = try CryptoBox(vouch_box.string(), vouch_nonce, _c_sk, _st_pk)? else 105 | _session.notify.protocol_error("couldn't encode INITIATE vouch box") 106 | error 107 | end 108 | initiate_box.metadata("Socket-Type") = _session.keeper.socket_type_string() 109 | 110 | let command = CommandAuthCurveInitiate 111 | let short_nonce = _nonce_gen.next_short() 112 | let nonce = CryptoBoxNonce("CurveZMQINITIATE" + short_nonce) 113 | command.cookie = cookie 114 | command.short_nonce = short_nonce 115 | command.data_box = try CryptoBox(initiate_box.string(), nonce, _ct_sk, _st_pk)? else 116 | _session.notify.protocol_error("couldn't encode INITIATE box") 117 | error 118 | end 119 | _session._write_command(command) 120 | 121 | fun ref _read_ready(buffer: _Buffer ref)? => 122 | // TODO: possibility of receiving ERROR command here. 123 | let command = _session._read_specific_command[CommandAuthCurveReady](buffer)? 124 | // TODO: validate that server's short nonces increment as per spec. 125 | let nonce = CryptoBoxNonce("CurveZMQREADY---" + command.short_nonce) 126 | let data = try CryptoBox.open(command.data_box, nonce, _ct_sk, _st_pk)? else 127 | _session.notify.protocol_error("couldn't open READY box") 128 | error 129 | end 130 | let welcome_box = CommandAuthCurveReadyBox(data) 131 | 132 | let other_type = try welcome_box.metadata("Socket-Type")? else "" end 133 | if not _session.keeper.socket_type_accepts(other_type) then 134 | let this_type = _session.keeper.socket_type_string() 135 | _session.notify.protocol_error(this_type+" socket cannot accept: "+other_type) 136 | error 137 | end 138 | 139 | _session.notify.activated(_make_message_writex()) 140 | _next_state(_MechanismAuthCurveClientStateReadMessage) 141 | 142 | fun ref _read_message(buffer: _Buffer ref)? => 143 | // TODO: possibility of receiving ERROR command here. 144 | let command = _session._read_specific_command[CommandAuthCurveMessage](buffer)? 145 | // TODO: validate that server's short nonces increment as per spec. 146 | let nonce = CryptoBoxNonce("CurveZMQMESSAGES" + command.short_nonce) 147 | let data = try CryptoBox.open(command.data_box, nonce, _ct_sk, _st_pk)? else 148 | _session.notify.protocol_error("couldn't open MESSAGE box") 149 | error 150 | end 151 | let message_box = CommandAuthCurveMessageBox(data) 152 | _session._add_to_message(message_box.payload) 153 | 154 | if not message_box.has_more then 155 | _session.notify.received(_session._take_message()) 156 | end 157 | 158 | fun ref _make_message_writex(): MessageWriteTransform iso^ => 159 | let pk = _st_pk 160 | let sk = _ct_sk 161 | // TODO: make the new local _nonce_gen unusable (to avoid dups with moved one) 162 | let nonce_gen: _CurveNonceGenerator iso = _nonce_gen = _CurveNonceGenerator 163 | 164 | recover 165 | _CurveMessageWriter(sk, pk, consume nonce_gen, "CurveZMQMESSAGEC") 166 | end 167 | -------------------------------------------------------------------------------- /zmq/zmtp/mechanism_auth_curve_server.pony: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | use "sodium" 6 | 7 | primitive _MechanismAuthCurveServerStateReadGreeting 8 | primitive _MechanismAuthCurveServerStateReadHandshakeHello 9 | primitive _MechanismAuthCurveServerStateReadHandshakeInitiate 10 | primitive _MechanismAuthCurveServerStateAwaitZapResponse 11 | primitive _MechanismAuthCurveServerStateReadMessage 12 | 13 | type _MechanismAuthCurveServerState is 14 | ( _MechanismAuthCurveServerStateReadGreeting 15 | | _MechanismAuthCurveServerStateReadHandshakeHello 16 | | _MechanismAuthCurveServerStateReadHandshakeInitiate 17 | | _MechanismAuthCurveServerStateAwaitZapResponse 18 | | _MechanismAuthCurveServerStateReadMessage) 19 | 20 | // TODO: improve performance with CryptoBox precomputation after handshake. 21 | class MechanismAuthCurveServer is Mechanism 22 | let _session: Session 23 | let _s_sk: CryptoBoxSecretKey 24 | let _s_pk: CryptoBoxPublicKey 25 | let _st_sk: CryptoBoxSecretKey 26 | let _st_pk: CryptoBoxPublicKey 27 | var _ct_pk: CryptoBoxPublicKey = CryptoBoxPublicKey("") 28 | var _c_pk: CryptoBoxPublicKey = CryptoBoxPublicKey("") 29 | var _cookie_key: CryptoSecretBoxKey = CryptoSecretBoxKey("") 30 | 31 | var _state: _MechanismAuthCurveServerState = _MechanismAuthCurveServerStateReadGreeting 32 | var _nonce_gen: _CurveNonceGenerator iso = _nonce_gen.create() 33 | 34 | new create(session: Session, s_sk: CryptoBoxSecretKey, s_pk: CryptoBoxPublicKey) => 35 | _session = session 36 | _s_sk = s_sk 37 | _s_pk = s_pk 38 | (_st_sk, _st_pk) = try CryptoBox.keypair()? 39 | else (CryptoBoxSecretKey(""), CryptoBoxPublicKey("")) end 40 | 41 | fun ref _next_state(state: _MechanismAuthCurveServerState) => 42 | _state = state 43 | 44 | fun ref handle_input(buffer: _Buffer ref) => 45 | try while true do 46 | match _state 47 | | _MechanismAuthCurveServerStateReadGreeting => _read_greeting(buffer)? 48 | | _MechanismAuthCurveServerStateReadHandshakeHello => _read_hello(buffer)? 49 | | _MechanismAuthCurveServerStateReadHandshakeInitiate => _read_initiate(buffer)? 50 | | _MechanismAuthCurveServerStateAwaitZapResponse => error 51 | | _MechanismAuthCurveServerStateReadMessage => _read_message(buffer)? 52 | end 53 | end end 54 | 55 | fun ref handle_zap_response(zap: ZapResponse) => 56 | if _state is _MechanismAuthCurveServerStateAwaitZapResponse then 57 | if zap.is_success() then 58 | try _write_ready()? end // TODO: handle zap.metadata 59 | else 60 | _session.notify.protocol_error("ZAP authentication failure") // TODO: more details 61 | end 62 | end 63 | 64 | fun ref handle_start() => 65 | _next_state(_MechanismAuthCurveServerStateReadGreeting) 66 | _session._write_greeting() 67 | 68 | fun ref _read_greeting(buffer: _Buffer ref)? => 69 | _session._read_greeting(buffer)? 70 | _next_state(_MechanismAuthCurveServerStateReadHandshakeHello) 71 | 72 | fun ref _read_hello(buffer: _Buffer ref)? => 73 | let command = _session._read_specific_command[CommandAuthCurveHello](buffer)? 74 | 75 | if not ((command.version_major == 1) and (command.version_minor == 0)) then 76 | _session.notify.protocol_error("unknown CurveZMQ version: " + 77 | command.version_major.string() + "." + 78 | command.version_minor.string()) 79 | error 80 | end 81 | 82 | _ct_pk = command.ct_pk 83 | let nonce = CryptoBoxNonce("CurveZMQHELLO---" + command.short_nonce) 84 | let data = try CryptoBox.open(command.signature_box, nonce, _s_sk, _ct_pk)? else 85 | _session.notify.protocol_error("couldn't open HELLO box") 86 | error 87 | end 88 | 89 | _next_state(_MechanismAuthCurveServerStateReadHandshakeInitiate) 90 | _write_welcome()? 91 | 92 | fun ref _write_welcome()? => 93 | _cookie_key = CryptoSecretBox.key() 94 | let cookie_nonce = _nonce_gen.next_long() 95 | let welcome_box = CommandAuthCurveWelcomeBox 96 | welcome_box.st_pk = _st_pk 97 | welcome_box.cookie = cookie_nonce + 98 | CryptoSecretBox(_ct_pk.string() + _st_sk.string(), 99 | CryptoSecretBoxNonce("COOKIE--" + cookie_nonce), _cookie_key)? 100 | 101 | let command = CommandAuthCurveWelcome 102 | let long_nonce = _nonce_gen.next_long() 103 | let nonce = CryptoBoxNonce("WELCOME-" + long_nonce) 104 | command.long_nonce = long_nonce 105 | command.data_box = try CryptoBox(welcome_box.string(), nonce, _s_sk, _ct_pk)? else 106 | _session.notify.protocol_error("couldn't encode WELCOME box") 107 | error 108 | end 109 | _session._write_command(command) 110 | 111 | fun ref _read_initiate(buffer: _Buffer ref)? => 112 | let command = _session._read_specific_command[CommandAuthCurveInitiate](buffer)? 113 | 114 | let cookie = try CryptoSecretBox.open(command.cookie.substring(16), 115 | CryptoSecretBoxNonce("COOKIE--" + command.cookie.substring(0, 16)), 116 | _cookie_key)? else 117 | _session.notify.protocol_error("couldn't open INITIATE cookie box") 118 | error 119 | end 120 | if (cookie.substring(0, 32) != _ct_pk.string()) 121 | or (cookie.substring(32, 64) != _st_sk.string()) then 122 | _session.notify.protocol_error("got incorrect INITIATE cookie") 123 | error 124 | end 125 | _cookie_key = CryptoSecretBoxKey("") // forget cookie key 126 | 127 | // TODO: verify incrementing short nonces 128 | let nonce = CryptoBoxNonce("CurveZMQINITIATE" + command.short_nonce) 129 | let data = try CryptoBox.open(command.data_box, nonce, _st_sk, _ct_pk)? else 130 | _session.notify.protocol_error("couldn't open INITIATE box") 131 | error 132 | end 133 | let initate_box = CommandAuthCurveInitiateBox(data) 134 | 135 | let other_type = try initate_box.metadata("Socket-Type")? else "" end 136 | if not _session.keeper.socket_type_accepts(other_type) then 137 | let this_type = _session.keeper.socket_type_string() 138 | _session.notify.protocol_error(this_type+" socket cannot accept: "+other_type) 139 | error 140 | end 141 | 142 | _c_pk = initate_box.c_pk 143 | let vouch_nonce = CryptoBoxNonce("VOUCH---" + initate_box.long_nonce) 144 | let vouch = try CryptoBox.open(initate_box.vouch_box, vouch_nonce, _st_sk, _c_pk)? else 145 | _session.notify.protocol_error("couldn't open INITIATE vouch box") 146 | error 147 | end 148 | let vouch_box = CommandAuthCurveInitiateVouchBox(vouch) 149 | 150 | if (vouch_box.ct_pk.string() != _ct_pk.string()) 151 | or (vouch_box.s_pk.string() != _s_pk.string()) then 152 | _session.notify.protocol_error("contents of INITIATE vouch box are incorrect") 153 | error 154 | end 155 | 156 | let zap: ZapRequest trn = ZapRequest 157 | // TODO: zap.domain = 158 | // TODO: zap.address = 159 | // TODO: zap.identity = 160 | zap.mechanism = "CURVE" 161 | zap.push_credential(_c_pk.string()) 162 | _session.notify.zap_request(consume zap) 163 | 164 | _next_state(_MechanismAuthCurveServerStateAwaitZapResponse) 165 | error // Don't read any more buffer input until ZapResponse returns 166 | 167 | fun ref _write_ready()? => 168 | let ready_box: CommandAuthCurveReadyBox ref = CommandAuthCurveReadyBox 169 | ready_box.metadata("Socket-Type") = _session.keeper.socket_type_string() 170 | 171 | let command = CommandAuthCurveReady 172 | let short_nonce = _nonce_gen.next_short() 173 | let nonce = CryptoBoxNonce("CurveZMQREADY---" + short_nonce) 174 | command.short_nonce = short_nonce 175 | command.data_box = try CryptoBox(ready_box.string(), nonce, _st_sk, _ct_pk)? else 176 | _session.notify.protocol_error("couldn't encode READY box") 177 | error 178 | end 179 | _session._write_command(command) 180 | 181 | _session.notify.activated(_make_message_writex()) 182 | _next_state(_MechanismAuthCurveServerStateReadMessage) 183 | 184 | fun ref _read_message(buffer: _Buffer ref)? => 185 | let command = _session._read_specific_command[CommandAuthCurveMessage](buffer)? 186 | // TODO: validate that client's short nonces increment as per spec. 187 | let nonce = CryptoBoxNonce("CurveZMQMESSAGEC" + command.short_nonce) 188 | let data = try CryptoBox.open(command.data_box, nonce, _st_sk, _ct_pk)? else 189 | _session.notify.protocol_error("couldn't open MESSAGE box") 190 | error 191 | end 192 | let message_box = CommandAuthCurveMessageBox(data) 193 | _session._add_to_message(message_box.payload) 194 | 195 | if not message_box.has_more then 196 | _session.notify.received(_session._take_message()) 197 | end 198 | 199 | fun ref _make_message_writex(): MessageWriteTransform iso^ => 200 | let pk = _ct_pk 201 | let sk = _st_sk 202 | // TODO: make the new local _nonce_gen unusable (to avoid dups with moved one) 203 | let nonce_gen: _CurveNonceGenerator iso = _nonce_gen = _CurveNonceGenerator 204 | 205 | recover 206 | _CurveMessageWriter(sk, pk, consume nonce_gen, "CurveZMQMESSAGES") 207 | end 208 | -------------------------------------------------------------------------------- /zmq/zmtp/mechanism_auth_null.pony: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | primitive _MechanismAuthNullStateReadGreeting 6 | primitive _MechanismAuthNullStateReadHandshakeReady 7 | primitive _MechanismAuthNullStateReadMessage 8 | 9 | type _MechanismAuthNullState is 10 | ( _MechanismAuthNullStateReadGreeting 11 | | _MechanismAuthNullStateReadHandshakeReady 12 | | _MechanismAuthNullStateReadMessage) 13 | 14 | class MechanismAuthNull is Mechanism 15 | let _session: Session 16 | var _state: _MechanismAuthNullState = _MechanismAuthNullStateReadGreeting 17 | 18 | new create(session: Session) => 19 | _session = session 20 | 21 | fun ref _next_state(state: _MechanismAuthNullState) => 22 | _state = state 23 | 24 | fun ref handle_input(buffer: _Buffer ref) => 25 | try while true do 26 | match _state 27 | | _MechanismAuthNullStateReadGreeting => _read_greeting(buffer)? 28 | | _MechanismAuthNullStateReadHandshakeReady => _read_ready_command(buffer)? 29 | | _MechanismAuthNullStateReadMessage => _read_message(buffer)? 30 | end 31 | end end 32 | 33 | fun ref handle_start() => 34 | _next_state(_MechanismAuthNullStateReadGreeting) 35 | _session._write_greeting() 36 | 37 | fun ref _write_greeting() => 38 | _session._write_greeting() 39 | 40 | fun ref _read_greeting(buffer: _Buffer ref)? => 41 | _session._read_greeting(buffer)? 42 | _next_state(_MechanismAuthNullStateReadHandshakeReady) 43 | _write_ready_command() 44 | 45 | fun ref _write_ready_command() => 46 | let command = CommandAuthNullReady 47 | command.metadata("Socket-Type") = _session.keeper.socket_type_string() 48 | _session._write_command(command) 49 | 50 | fun ref _read_ready_command(buffer: _Buffer ref)? => 51 | let command = _session._read_specific_command[CommandAuthNullReady](buffer)? 52 | 53 | let other_type = try command.metadata("Socket-Type")? else "" end 54 | if not _session.keeper.socket_type_accepts(other_type) then 55 | let this_type = _session.keeper.socket_type_string() 56 | _session.notify.protocol_error(this_type+" socket cannot accept: "+other_type) 57 | error 58 | end 59 | 60 | _session.notify.activated(recover MessageWriter end) 61 | _next_state(_MechanismAuthNullStateReadMessage) 62 | 63 | fun ref _read_message(buffer: _Buffer ref) ? => 64 | _session.notify.received(_session._read_message(buffer)?) 65 | _next_state(_MechanismAuthNullStateReadMessage) 66 | -------------------------------------------------------------------------------- /zmq/zmtp/message.pony: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | use "collections" 6 | use "inspect" 7 | 8 | type Frame is String 9 | 10 | class val Message is (Stringable & Equatable[Message box] & Seq[Frame]) 11 | let _inner: List[Frame] = _inner.create() 12 | new create(len: USize = 0) => None 13 | 14 | fun size(): USize => _inner.size() 15 | fun apply(i: USize = 0): Frame? => _inner.apply(i)? 16 | 17 | fun ref reserve(len: USize) => _inner.reserve(len); this 18 | fun ref clear() => _inner.clear(); this 19 | fun ref update(i: USize, value: Frame): Frame^? => _inner.update(i, value)? 20 | fun ref push(value: Frame) => _inner.push(value); this 21 | fun ref pop(): Frame^? => _inner.pop()? 22 | fun ref unshift(value: Frame) => _inner.unshift(value); this 23 | fun ref shift(): Frame^? => _inner.shift()? 24 | fun ref truncate(len: USize) => _inner.truncate(len); this 25 | fun ref concat(iter: Iterator[Frame^], offset: USize = 0, len: USize = -1) => 26 | _inner.concat(iter, offset, len); this 27 | fun ref append(seq: ReadSeq[Frame], offset: USize = 0, len: USize = -1) => 28 | _inner.append(seq, offset, len); this 29 | 30 | fun nodes(): ListNodes[Frame, this->ListNode[Frame]]^ => _inner.nodes() 31 | fun rnodes(): ListNodes[Frame, this->ListNode[Frame]]^ => _inner.rnodes() 32 | fun values(): ListValues[Frame, this->ListNode[Frame]]^ => _inner.values() 33 | fun rvalues(): ListValues[Frame, this->ListNode[Frame]]^ => _inner.rvalues() 34 | 35 | fun eq(that: Message box): Bool => 36 | if size() != that.size() then return false end 37 | try for i in Range(0, size()) do 38 | if not _frame_eq(this(i)?, that(i)?) then return false end 39 | end else return false end 40 | true 41 | 42 | fun tag _frame_eq(a: Frame, b: Frame): Bool => 43 | if a.size() != b.size() then return false end 44 | try for i in Range(0, a.size()) do 45 | if a(i)? != b(i)? then return false end 46 | end else return false end 47 | true 48 | 49 | fun inspect(): String => Inspect(this) 50 | 51 | fun string(): String iso^ => 52 | inspect().clone() 53 | -------------------------------------------------------------------------------- /zmq/zmtp/message_parser.pony: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | use "format" 5 | 6 | interface ref MessageWriteTransform 7 | fun ref apply(message: Message): Array[U8] val 8 | 9 | class MessageWriter is MessageWriteTransform 10 | fun ref apply(message: Message box): Array[U8] val => 11 | let output = recover trn Array[U8] end 12 | let frame_count = message.size() 13 | 14 | for node in message.nodes() do 15 | let frame': (Frame | None) = try node()? else None end 16 | let has_more = node.has_next() 17 | 18 | match frame' | let frame: Frame => 19 | // Determine the ident and size bytewidth based on the size and more flag. 20 | let is_short = frame.size() <= 0xFF 21 | let more: U8 = if has_more then 0x01 else 0x00 end 22 | let ident: U8 = if is_short then 0x00 or more else 0x02 or more end 23 | let size = if is_short then frame.size().u8() else frame.size() end 24 | 25 | // Write the ident, size, and the data byte array to the output byte array. 26 | output.push(ident) 27 | output.append(_Util.make_bytes(size)) 28 | output.append(frame) 29 | end 30 | end 31 | 32 | output 33 | 34 | class MessageParser 35 | var _message: Message trn = recover Message end 36 | 37 | fun ref read(buffer: _Buffer, notify: SessionNotify): Message trn^? => 38 | var has_more: Bool = true 39 | 40 | while has_more do 41 | var offset: USize = 0 42 | 43 | // Peek ident byte to determine number of size bytes, then peek size. 44 | let ident = buffer.peek_u8()?; offset = offset + 1 45 | let size = match ident 46 | | 0x00 | 0x01 => offset = offset + 1; USize.from[U8](buffer.peek_u8(1)?) 47 | | 0x02 | 0x03 => offset = offset + 8; buffer.peek_u64_be(1)?.usize() // TODO: this breaks for 32-bit systems - we need a better solution 48 | else 49 | notify.protocol_error("unknown frame ident byte: " + Format.int[U8](ident, FormatHex)) 50 | error 51 | end 52 | 53 | // Raise error if not all bytes are available yet. 54 | if buffer.size() < (offset + size) then error end 55 | 56 | // Skip the bytes obtained by peeking. 57 | buffer.skip(consume offset)? 58 | 59 | // Read the frame body and append it to the ongoing message. 60 | let frame = recover trn String end 61 | frame.append(buffer.block(size)?) 62 | _message.push(consume frame) 63 | 64 | // Get has_more flag from ident byte 65 | has_more = (0 != (ident and 0x01)) 66 | end 67 | 68 | // Transfer ownership of the current message to the caller and start a new one. 69 | _message = recover Message end 70 | 71 | fun ref add_to_message(frame: Frame) => 72 | _message.push(consume frame) 73 | 74 | fun ref take_message(): Message trn^ => 75 | // Transfer ownership of the current message to the caller and start a new one. 76 | _message = recover Message end 77 | -------------------------------------------------------------------------------- /zmq/zmtp/session.pony: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | interface ref _MessageWriteTransform 6 | fun ref apply(message: Message): Array[U8] val 7 | 8 | interface SessionNotify 9 | fun ref activated(writex: _MessageWriteTransform) 10 | fun ref protocol_error(string: String) 11 | fun ref write(bytes: ByteSeq) 12 | fun ref received(message: Message) 13 | fun ref zap_request(zap: ZapRequest) 14 | 15 | class _SessionNotifyNone is SessionNotify 16 | fun ref activated(writex: _MessageWriteTransform) => None 17 | fun ref protocol_error(string: String) => None 18 | fun ref write(bytes: ByteSeq) => None 19 | fun ref received(message: Message) => None 20 | fun ref zap_request(zap: ZapRequest) => None 21 | 22 | interface _SessionKeeper 23 | fun as_server(): Bool 24 | fun auth_mechanism(): String 25 | fun socket_type_string(): String 26 | fun socket_type_accepts(string: String): Bool 27 | 28 | class _SessionKeeperNone is _SessionKeeper 29 | fun as_server(): Bool => false 30 | fun auth_mechanism(): String => "" 31 | fun socket_type_string(): String => "" 32 | fun socket_type_accepts(string: String): Bool => false 33 | 34 | class Session 35 | var keeper: _SessionKeeper = _SessionKeeperNone 36 | var notify: SessionNotify = _SessionNotifyNone 37 | var _mechanism: Mechanism = MechanismNone 38 | 39 | let _message_parser: MessageParser = MessageParser 40 | 41 | fun ref start(k: _SessionKeeper, n: SessionNotify, m: Mechanism) => 42 | keeper = k 43 | notify = n 44 | _mechanism = m 45 | _mechanism.handle_start() 46 | 47 | fun ref handle_input(buffer: _Buffer ref) => 48 | _mechanism.handle_input(buffer) 49 | 50 | fun ref handle_zap_response(zap: ZapResponse) => 51 | _mechanism.handle_zap_response(zap) 52 | 53 | /// 54 | // Convenience methods for use by Mechanisms 55 | 56 | fun ref _write_greeting() => 57 | notify.write(Greeting.write(keeper.auth_mechanism(), keeper.as_server())) 58 | 59 | fun ref _read_greeting(buffer: _Buffer ref)? => 60 | Greeting.read(buffer, notify, keeper.auth_mechanism(), keeper.as_server())? 61 | 62 | fun ref _write_command(command: Command) => 63 | notify.write(CommandParser.write(command)) 64 | 65 | fun ref _read_command(buffer: _Buffer ref): CommandUnknown? => 66 | CommandParser.read(buffer, notify)? 67 | 68 | fun ref _read_specific_command[A: Command ref](buffer: _Buffer ref): A? => 69 | let c_data = _read_command(buffer)? 70 | let command = A.create() 71 | 72 | try command(c_data)? else 73 | notify.protocol_error("Expected "+command.name()+" command, got: "+c_data.name()) 74 | error 75 | end 76 | 77 | command 78 | 79 | fun ref _read_message(buffer: _Buffer ref): Message trn^? => 80 | _message_parser.read(buffer, notify)? 81 | 82 | fun ref _add_to_message(frame: Frame) => 83 | _message_parser.add_to_message(frame) 84 | 85 | fun ref _take_message(): Message trn^ => 86 | _message_parser.take_message() 87 | -------------------------------------------------------------------------------- /zmq/zmtp/util.pony: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | primitive _Util 6 | fun make_bytes[A: Unsigned = Unsigned](input: A): Array[U8] val => 7 | """ 8 | Convert the given unsigned integer to an array of bytes (big endian). 9 | """ 10 | match input 11 | | let x: U8 => recover [x] end 12 | | let x: U16 => recover [ 13 | (x >> 8).u8() 14 | x.u8()] end 15 | | let x: U32 => recover [ 16 | (x >> 24).u8() 17 | (x >> 16).u8() 18 | (x >> 8).u8() 19 | x.u8()] end 20 | | let x: U64 => recover [ 21 | (x >> 56).u8() 22 | (x >> 48).u8() 23 | (x >> 40).u8() 24 | (x >> 32).u8() 25 | (x >> 24).u8() 26 | (x >> 16).u8() 27 | (x >> 8).u8() 28 | x.u8()] end 29 | | let x: U128 => recover [ 30 | (x >> 120).u8() 31 | (x >> 112).u8() 32 | (x >> 104).u8() 33 | (x >> 96).u8() 34 | (x >> 88).u8() 35 | (x >> 80).u8() 36 | (x >> 72).u8() 37 | (x >> 64).u8() 38 | (x >> 56).u8() 39 | (x >> 48).u8() 40 | (x >> 40).u8() 41 | (x >> 32).u8() 42 | (x >> 24).u8() 43 | (x >> 16).u8() 44 | (x >> 8).u8() 45 | x.u8()] end 46 | else 47 | recover Array[U8] end 48 | end 49 | -------------------------------------------------------------------------------- /zmq/zmtp/zap.pony: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | class val ZapRequest 6 | var version: String = "1.0" 7 | var id: String = "" 8 | var domain: String = "" 9 | var address: String = "" 10 | var identity: String = "" 11 | var mechanism: String = "" 12 | var credentials: Array[String] = credentials.create() 13 | 14 | var _responder: (ZapRespond | None) = None 15 | 16 | new iso create() => None 17 | fun ref push_credential(string: String) => 18 | credentials.push(string) 19 | 20 | fun ref _set_responder(responder': ZapRespond) => 21 | _responder = responder' 22 | 23 | fun respond(res: ZapResponse trn) => 24 | res.version = version 25 | res.id = id 26 | try (_responder as ZapRespond)(consume res) end 27 | 28 | new val from_message(m: Message)? => 29 | let iter = m.values() 30 | version = iter.next()? 31 | id = iter.next()? 32 | domain = iter.next()? 33 | address = iter.next()? 34 | identity = iter.next()? 35 | mechanism = iter.next()? 36 | for credential in iter do 37 | credentials.push(credential) 38 | end 39 | 40 | fun as_message(): Message => // TODO: test commutativity 41 | let out = recover trn Message end 42 | out.push(version) 43 | out.push(id) 44 | out.push(domain) 45 | out.push(address) 46 | out.push(identity) 47 | out.push(mechanism) 48 | for credential in credentials.values() do 49 | out.push(credential) 50 | end 51 | out 52 | 53 | class val ZapResponse 54 | var version: String = "1.0" 55 | var id: String = "" 56 | var status_code: String = "200" 57 | var status_text: String = "OK" 58 | var user_id: String = "" 59 | var metadata: CommandMetadata = metadata.create() 60 | 61 | fun is_success(): Bool => status_code == "200" 62 | 63 | new iso create() => None 64 | 65 | new iso success(user_id': String = "") => 66 | user_id = user_id' 67 | 68 | new iso temp_error(status_text': String = "") => 69 | status_code = "300" 70 | status_text = status_text' 71 | 72 | new iso auth_error(status_text': String = "") => 73 | status_code = "400" 74 | status_text = status_text' 75 | 76 | new iso server_error(status_text': String = "") => 77 | status_code = "500" 78 | status_text = status_text' 79 | 80 | new val from_message(m: Message)? => 81 | let iter = m.values() 82 | version = iter.next()? 83 | id = iter.next()? 84 | status_code = iter.next()? 85 | status_text = iter.next()? 86 | user_id = iter.next()? 87 | CommandUtil.read_string_as_metadata(metadata, iter.next()?) 88 | if iter.has_next() then error end 89 | 90 | fun as_message(): Message => // TODO: test commutativity 91 | let out = recover trn Message end 92 | out.push(version) 93 | out.push(id) 94 | out.push(status_code) 95 | out.push(status_text) 96 | out.push(user_id) 97 | out.push(CommandUtil.write_string_as_metadata(metadata)) 98 | out 99 | 100 | interface tag ZapRequestNotifiable 101 | be handle_zap_request(req: ZapRequest, respond: ZapRespond) 102 | 103 | interface val ZapRespond 104 | fun val apply(zap: ZapResponse) 105 | --------------------------------------------------------------------------------