├── .gitignore ├── .travis.yml ├── AUTHORS ├── LICENSE ├── Makefile.am ├── README.md ├── autogen.sh ├── clients ├── Makefile.am ├── codec_libzmtp.gsl ├── libzbroker_cli.pc.in ├── license.xml ├── selftest ├── valgrind.supp ├── zchunk.c ├── zchunk.h ├── zpipes_client.c ├── zpipes_client.h ├── zpipes_msg.c ├── zpipes_msg.h ├── zpipes_msg.xml ├── zpipes_selftest.c └── zpipes_test_client.c ├── configure.ac ├── doc ├── Makefile.am ├── asciidoc.conf ├── mkman ├── zpipes.1 ├── zpipes_client.txt ├── zpipes_msg.txt └── zpipes_server.txt ├── include ├── zbroker.h ├── zpipes_client.h ├── zpipes_msg.h └── zpipes_server.h ├── src ├── Makefile.am ├── libzbroker.pc.in ├── libzpipesclient.pc.in ├── license.xml ├── selftest ├── valgrind.supp ├── vg ├── zbroker-daemon.cfg ├── zbroker.c ├── zbroker.cfg ├── zbroker_classes.h ├── zbroker_daemon ├── zbroker_selftest.c ├── zpipes_client.c ├── zpipes_dump.c ├── zpipes_msg.bnf ├── zpipes_msg.c ├── zpipes_msg.xml ├── zpipes_server.c ├── zpipes_server.xml ├── zpipes_server_engine.inc └── zpipes_test_cluster.c └── version.sh /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | 5 | # Libraries 6 | *.lib 7 | *.a 8 | 9 | # Shared objects (inc. Windows DLLs) 10 | *.dll 11 | *.so 12 | *.so.* 13 | *.dylib 14 | *.lo 15 | 16 | # Executables 17 | *.exe 18 | *.out 19 | *.app 20 | 21 | Makefile 22 | Makefile.in 23 | aclocal.m4 24 | autom4te.cache/ 25 | config.log 26 | config.status 27 | config/ 28 | configure 29 | doc/Makefile 30 | doc/Makefile.in 31 | doc/*.3 32 | doc/*.7 33 | libtool 34 | .deps 35 | .libs 36 | src/Makefile 37 | src/Makefile.in 38 | src/zbroker 39 | src/platform.h 40 | src/platform.h.in 41 | src/platform.h.in~ 42 | src/stamp-h1 43 | src/test-suite.log 44 | src/zbroker_selftest 45 | src/zbroker_selftest.log 46 | src/zbroker_selftest.trs 47 | src/zpipes_test_cluster 48 | doit* 49 | *.la 50 | *.pc 51 | zpipes_test_cluster.log 52 | zpipes_test_cluster.trs 53 | core 54 | clients/zpipes_test_client 55 | clients/zpipes_selftest 56 | 57 | 58 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Travis CI script 2 | 3 | language: c 4 | 5 | # Build-check-install all subprojects 6 | before_script: 7 | - sudo apt-get install uuid-dev 8 | 9 | # libsodium 10 | - git clone git://github.com/jedisct1/libsodium.git 11 | - ( cd libsodium; ./autogen.sh; ./configure; make check; sudo make install; sudo ldconfig ) 12 | 13 | # libzmtp 14 | - git clone git://github.com/zeromq/libzmtp.git 15 | - ( cd libzmtp; ./autogen.sh; ./configure; make check; sudo make install; sudo ldconfig ) 16 | 17 | # libzmq 18 | - git clone git://github.com/zeromq/libzmq.git 19 | - ( cd libzmq; ./autogen.sh; ./configure; make check; sudo make install; sudo ldconfig ) 20 | 21 | # CZMQ 22 | - git clone git://github.com/zeromq/czmq.git 23 | - ( cd czmq; ./autogen.sh; ./configure; make check; sudo make install; sudo ldconfig ) 24 | 25 | # Zyre 26 | - git clone git://github.com/zeromq/zyre.git 27 | - ( cd zyre; ./autogen.sh; ./configure; make check; sudo make install; sudo ldconfig ) 28 | 29 | # Build and check this project 30 | script: 31 | - ./autogen.sh && ./configure && make && make check 32 | - sudo make install 33 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Contributors 2 | ============ 3 | 4 | Pieter Hintjens 5 | -------------------------------------------------------------------------------- /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.am: -------------------------------------------------------------------------------- 1 | ACLOCAL_AMFLAGS = -I config 2 | 3 | SUBDIRS = src doc clients 4 | 5 | DIST_SUBDIRS = src doc clients 6 | 7 | EXTRA_DIST = 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # zbroker - the ZeroMQ broker project 2 | 3 | The zbroker project is a container for arbitrary ZeroMQ-based messaging services. The current list of messaging services is: 4 | 5 | * ZPIPES - reliable, distributed named pipes 6 | 7 | ## General Operation 8 | 9 | To build zbroker: 10 | 11 | git clone git://github.com/jedisct1/libsodium.git 12 | for project in libzmq czmq zyre zbroker; do 13 | git clone git://github.com/zeromq/$project.git 14 | done 15 | for project in libsodium libzmq czmq zyre zbroker; do 16 | cd $project 17 | ./autogen.sh 18 | ./configure && make check 19 | sudo make install 20 | sudo ldconfig 21 | cd .. 22 | done 23 | 24 | To run zbroker: 25 | 26 | zbroker [broker-name] 27 | 28 | Where 'broker-name' is a string that is unique on any given host. The default broker name is 'local'. To end the broker, send a TERM or INT signal (Ctrl-C). 29 | 30 | ## ZPIPES Overview 31 | 32 | ### The ZPIPES Protocol 33 | 34 | The following ABNF grammar defines the ZPIPES protocol: 35 | 36 | ZPIPES = reader | writer 37 | 38 | reader = input-command *( read-command | ping-command ) 39 | close-command 40 | input-command = c:input ( s:input-ok | s:input-failed ) 41 | read-command = c:read ( s:read-ok | s:read-end 42 | | s:read-timeout | s:read-failed ) 43 | close-command = c:close ( s:close-ok | s:close-failed ) 44 | 45 | writer = output-command *write-command close-command 46 | output-command = c:output ( s:output-ok | s:output-failed ) 47 | write-command = c:write ( s:write-ok 48 | | s:write-timeout | s:write-failed ) 49 | ping-command = c:ping s:ping-ok 50 | 51 | ; Create a new pipe for reading 52 | input = signature %d1 pipename 53 | signature = %xAA %xA0 ; two octets 54 | pipename = string ; Name of pipe 55 | 56 | ; Input request was successful 57 | input_ok = signature %d2 58 | 59 | ; Input request failed 60 | input_failed = signature %d3 reason 61 | reason = string ; Reason for failure 62 | 63 | ; Create a new pipe for writing 64 | output = signature %d4 pipename 65 | pipename = string ; Name of pipe 66 | 67 | ; Output request was successful 68 | output_ok = signature %d5 69 | 70 | ; Output request failed 71 | output_failed = signature %d6 reason 72 | reason = string ; Reason for failure 73 | 74 | ; Read a chunk of data from pipe 75 | read = signature %d7 size timeout 76 | size = number-4 ; Number of bytes to read 77 | timeout = number-4 ; Timeout, msecs, or zero 78 | 79 | ; Read was successful 80 | read_ok = signature %d8 chunk 81 | chunk = chunk ; Chunk of data 82 | 83 | ; Pipe is closed, no more data 84 | read_end = signature %d9 85 | 86 | ; Read ended with timeout 87 | read_timeout = signature %d10 88 | 89 | ; Read failed due to error 90 | read_failed = signature %d11 reason 91 | reason = string ; Reason for failure 92 | 93 | ; Write chunk of data to pipe 94 | write = signature %d12 chunk timeout 95 | chunk = chunk ; Chunk of data 96 | timeout = number-4 ; Timeout, msecs, or zero 97 | 98 | ; Write was successful 99 | write_ok = signature %d13 100 | 101 | ; Write ended with timeout 102 | write_timeout = signature %d14 103 | 104 | ; Read failed due to error 105 | write_failed = signature %d15 reason 106 | reason = string ; Reason for failure 107 | 108 | ; Close pipe 109 | close = signature %d16 110 | 111 | ; Close was successful 112 | close_ok = signature %d17 113 | 114 | ; Close failed due to error 115 | close_failed = signature %d18 reason 116 | reason = string ; Reason for failure 117 | 118 | ; Signal liveness 119 | ping = signature %d19 120 | 121 | ; Respond to ping 122 | ping_ok = signature %d20 123 | 124 | ; Command was invalid at this time 125 | invalid = signature %d21 126 | 127 | ; A chunk has 4-octet length + binary contents 128 | chunk = number-4 *OCTET 129 | 130 | ; Strings are always length + text contents 131 | string = number-1 *VCHAR 132 | 133 | ; Numbers are unsigned integers in network byte order 134 | number-1 = 1OCTET 135 | number-4 = 4OCTET 136 | 137 | ### The ZPIPES API 138 | 139 | The zpipes_client class provides the public API. 140 | 141 | ## Ownership and Contributing 142 | 143 | The contributors are listed in AUTHORS. This project uses the MPL v2 license, see LICENSE. 144 | 145 | The contribution policy is the standard ZeroMQ [C4.1 process](http://rfc.zeromq.org/spec:22). Please read this RFC if you have never contributed to a ZeroMQ project. 146 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Script to generate all required files from fresh git checkout. 4 | 5 | command -v libtool >/dev/null 2>&1 6 | if [ $? -ne 0 ]; then 7 | echo "autogen.sh: error: could not find libtool. libtool is required to run autogen.sh." 1>&2 8 | exit 1 9 | fi 10 | 11 | command -v autoreconf >/dev/null 2>&1 12 | if [ $? -ne 0 ]; then 13 | echo "autogen.sh: error: could not find autoreconf. autoconf and automake are required to run autogen.sh." 1>&2 14 | exit 1 15 | fi 16 | 17 | mkdir -p ./config 18 | if [ $? -ne 0 ]; then 19 | echo "autogen.sh: error: could not create directory: ./config." 1>&2 20 | exit 1 21 | fi 22 | 23 | autoreconf --install --force --verbose -I config 24 | if [ $? -ne 0 ]; then 25 | echo "autogen.sh: error: autoreconf exited with status $?" 1>&2 26 | exit 1 27 | fi 28 | -------------------------------------------------------------------------------- /clients/Makefile.am: -------------------------------------------------------------------------------- 1 | lib_LTLIBRARIES = libzbroker_cli.la 2 | 3 | pkgconfigdir = $(libdir)/pkgconfig 4 | pkgconfig_DATA = libzbroker_cli.pc 5 | 6 | include_HEADERS = \ 7 | zpipes_client.h 8 | 9 | libzbroker_cli_la_SOURCES = \ 10 | zchunk.c \ 11 | zchunk.h \ 12 | zpipes_msg.h \ 13 | zpipes_msg.c \ 14 | zpipes_client.c 15 | 16 | AM_CFLAGS = -g 17 | AM_CPPFLAGS = 18 | noinst_PROGRAMS = zpipes_selftest 19 | 20 | zpipes_selftest_SOURCES = zpipes_selftest.c 21 | zpipes_selftest_LDADD = libzbroker_cli.la -lzmtp 22 | 23 | libzbroker_cli_la_LDFLAGS = -version-info @LTVER@ 24 | 25 | # Selftest isn't working yet 26 | # TESTS = zpipes_selftest 27 | 28 | # Produce generated models; do this manually in src directory 29 | code: 30 | gsl -q zpipes_msg.xml 31 | -------------------------------------------------------------------------------- /clients/libzbroker_cli.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=@exec_prefix@ 3 | libdir=@libdir@ 4 | includedir=@includedir@ 5 | 6 | Name: libzbroker_cli 7 | Description: ZeroMQ broker project 8 | Version: @VERSION@ 9 | Requires: libzmtp 10 | Libs: -L${libdir} -lzbroker_cli 11 | Cflags: -I${includedir} 12 | -------------------------------------------------------------------------------- /clients/license.xml: -------------------------------------------------------------------------------- 1 | 2 | Copyright (c) the Contributors as noted in the AUTHORS file. 3 | This file is part of zbroker, the ZeroMQ broker project. 4 | 5 | This Source Code Form is subject to the terms of the Mozilla Public 6 | License, v. 2.0. If a copy of the MPL was not distributed with this 7 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | -------------------------------------------------------------------------------- /clients/selftest: -------------------------------------------------------------------------------- 1 | MAIN=zpipes_test_client 2 | VG="valgrind --tool=memcheck --leak-check=full --show-reachable=yes --suppressions=valgrind.supp" 3 | 4 | make code 5 | gcc -g -o $MAIN \ 6 | $MAIN.c \ 7 | zpipes_msg.c zpipes_client.c zchunk.c \ 8 | -lzmtp 9 | test $? -ne 0 && exit 10 | $VG ./$MAIN 11 | rm -f vgcore.* 12 | -------------------------------------------------------------------------------- /clients/valgrind.supp: -------------------------------------------------------------------------------- 1 | { 2 | 3 | Memcheck:Param 4 | socketcall.sendto(msg) 5 | fun:send 6 | ... 7 | } 8 | { 9 | 10 | Memcheck:Param 11 | socketcall.send(msg) 12 | fun:send 13 | ... 14 | } 15 | -------------------------------------------------------------------------------- /clients/zchunk.c: -------------------------------------------------------------------------------- 1 | /* ========================================================================= 2 | zchunk - work with memory chunks 3 | 4 | This file is part of zbroker, the ZeroMQ broker project. 5 | 6 | Copyright (c) the Contributors as noted in the AUTHORS file. 7 | This file is part of CZMQ, the high-level C binding for 0MQ: 8 | http://czmq.zeromq.org. 9 | 10 | This Source Code Form is subject to the terms of the Mozilla Public 11 | License, v. 2.0. If a copy of the MPL was not distributed with this 12 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 13 | =========================================================================*/ 14 | 15 | /* 16 | @header 17 | The zchunk class works with variable sized blobs. Not as efficient as 18 | ØMQ's messages but they do less weirdness and so are easier to understand. 19 | The chunk class has methods to read and write chunks from disk. 20 | @discuss 21 | @end 22 | */ 23 | 24 | #include 25 | #include "zchunk.h" 26 | 27 | // zchunk_t instances always have this tag as the first 4 octets of 28 | // their data, which lets us do runtime object typing & validation. 29 | #define ZCHUNK_TAG 0x0001cafe 30 | 31 | // Structure of our class 32 | 33 | struct _zchunk_t { 34 | uint32_t tag; // Object tag for runtime detection 35 | size_t size; // Current size of data part 36 | size_t max_size; // Maximum allocated size 37 | size_t consumed; // Amount already consumed 38 | byte *data; // Data part follows here 39 | }; 40 | 41 | 42 | // -------------------------------------------------------------------------- 43 | // Constructor 44 | 45 | zchunk_t * 46 | zchunk_new (const void *data, size_t size) 47 | { 48 | zchunk_t *self = (zchunk_t *) zmalloc (sizeof (zchunk_t) + size); 49 | if (self) { 50 | self->tag = ZCHUNK_TAG; 51 | self->max_size = size; 52 | self->data = (byte *) self + sizeof (zchunk_t); 53 | if (data) { 54 | self->size = size; 55 | memcpy (self->data, data, size); 56 | } 57 | } 58 | return self; 59 | } 60 | 61 | 62 | // -------------------------------------------------------------------------- 63 | // Destroy a chunk 64 | 65 | void 66 | zchunk_destroy (zchunk_t **self_p) 67 | { 68 | assert (self_p); 69 | if (*self_p) { 70 | zchunk_t *self = *self_p; 71 | assert (zchunk_is (self)); 72 | // If data was reallocated independently, free it independently 73 | if (self->data != (byte *) self + sizeof (zchunk_t)) 74 | free (self->data); 75 | self->tag = 0xDeadBeef; 76 | free (self); 77 | *self_p = NULL; 78 | } 79 | } 80 | 81 | 82 | // -------------------------------------------------------------------------- 83 | // Resizes chunk max_size as requested; chunk size is set to zero 84 | 85 | void 86 | zchunk_resize (zchunk_t *self, size_t size) 87 | { 88 | assert (self); 89 | assert (zchunk_is (self)); 90 | 91 | // If data was reallocated independently, free it independently 92 | if (self->data != (byte *) self + sizeof (zchunk_t)) 93 | free (self->data); 94 | 95 | self->data = (byte *) zmalloc (size); 96 | self->max_size = size; 97 | self->size = 0; 98 | } 99 | 100 | 101 | // -------------------------------------------------------------------------- 102 | // Return chunk current size 103 | 104 | size_t 105 | zchunk_size (zchunk_t *self) 106 | { 107 | assert (self); 108 | assert (zchunk_is (self)); 109 | return self->size; 110 | } 111 | 112 | 113 | // -------------------------------------------------------------------------- 114 | // Return chunk max size 115 | 116 | size_t 117 | zchunk_max_size (zchunk_t *self) 118 | { 119 | assert (self); 120 | assert (zchunk_is (self)); 121 | return self->max_size; 122 | } 123 | 124 | 125 | // -------------------------------------------------------------------------- 126 | // Return chunk data 127 | 128 | byte * 129 | zchunk_data (zchunk_t *self) 130 | { 131 | assert (self); 132 | assert (zchunk_is (self)); 133 | return self->data; 134 | } 135 | 136 | 137 | // -------------------------------------------------------------------------- 138 | // Set chunk data from user-supplied data; truncate if too large. Data may 139 | // be null. Returns actual size of chunk 140 | 141 | size_t 142 | zchunk_set (zchunk_t *self, const void *data, size_t size) 143 | { 144 | assert (self); 145 | assert (zchunk_is (self)); 146 | 147 | if (size > self->max_size) 148 | size = self->max_size; 149 | if (data) 150 | memcpy (self->data, data, size); 151 | 152 | self->size = size; 153 | return size; 154 | } 155 | 156 | 157 | // -------------------------------------------------------------------------- 158 | // Fill chunk data from user-supplied octet 159 | // Returns actual size of chunk 160 | 161 | size_t 162 | zchunk_fill (zchunk_t *self, byte filler, size_t size) 163 | { 164 | assert (self); 165 | assert (zchunk_is (self)); 166 | 167 | if (size > self->max_size) 168 | size = self->max_size; 169 | 170 | memset (self->data, filler, size); 171 | self->size = size; 172 | return size; 173 | } 174 | 175 | 176 | // -------------------------------------------------------------------------- 177 | // Append user-supplied data to chunk, return resulting chunk size 178 | 179 | size_t 180 | zchunk_append (zchunk_t *self, const void *data, size_t size) 181 | { 182 | assert (self); 183 | assert (zchunk_is (self)); 184 | 185 | if (self->size + size > self->max_size) 186 | size = self->max_size - self->size; 187 | 188 | memcpy (self->data + self->size, data, size); 189 | self->size += size; 190 | return self->size; 191 | } 192 | 193 | 194 | // -------------------------------------------------------------------------- 195 | // Copy as much data from 'source' into the chunk as possible; returns the 196 | // new size of chunk. If all data from 'source' is used, returns exhausted 197 | // on the source chunk. Source can be consumed as many times as needed until 198 | // it is exhausted. If source was already exhausted, does not change chunk. 199 | 200 | size_t 201 | zchunk_consume (zchunk_t *self, zchunk_t *source) 202 | { 203 | assert (self); 204 | assert (zchunk_is (self)); 205 | assert (source); 206 | assert (zchunk_is (source)); 207 | 208 | // We can take at most this many bytes from source 209 | size_t size = source->size - source->consumed; 210 | 211 | // And we can store at most this many bytes in chunk 212 | if (self->size + size > self->max_size) 213 | size = self->max_size - self->size; 214 | 215 | memcpy (self->data + self->size, source->data + source->consumed, size); 216 | source->consumed += size; 217 | self->size += size; 218 | return self->size; 219 | } 220 | 221 | 222 | // -------------------------------------------------------------------------- 223 | // Returns true if the chunk was exhausted by consume methods, or if the 224 | // chunk has a size of zero. 225 | 226 | bool 227 | zchunk_exhausted (zchunk_t *self) 228 | { 229 | assert (self); 230 | assert (zchunk_is (self)); 231 | 232 | assert (self->consumed <= self->size); 233 | return self->consumed == self->size; 234 | } 235 | 236 | 237 | // -------------------------------------------------------------------------- 238 | // Read chunk from an open file descriptor 239 | 240 | zchunk_t * 241 | zchunk_read (FILE *handle, size_t bytes) 242 | { 243 | assert (handle); 244 | 245 | zchunk_t *self = zchunk_new (NULL, bytes); 246 | self->size = fread (self->data, 1, bytes, handle); 247 | return self; 248 | } 249 | 250 | 251 | // -------------------------------------------------------------------------- 252 | // Write chunk to an open file descriptor 253 | 254 | int 255 | zchunk_write (zchunk_t *self, FILE *handle) 256 | { 257 | assert (self); 258 | assert (zchunk_is (self)); 259 | 260 | size_t items = fwrite (self->data, 1, self->size, handle); 261 | int rc = (items < self->size)? -1: 0; 262 | return rc; 263 | } 264 | 265 | 266 | // -------------------------------------------------------------------------- 267 | // Create copy of chunk, as new chunk object. Returns a fresh zchunk_t 268 | // object, or NULL if there was not enough heap memory. 269 | 270 | zchunk_t * 271 | zchunk_dup (zchunk_t *self) 272 | { 273 | assert (self); 274 | assert (zchunk_is (self)); 275 | 276 | return zchunk_new (self->data, self->max_size); 277 | } 278 | 279 | 280 | // -------------------------------------------------------------------------- 281 | // Dump chunk to FILE stream, for debugging and tracing. 282 | 283 | void 284 | zchunk_fprint (zchunk_t *self, FILE *file) 285 | { 286 | assert (self); 287 | assert (zchunk_is (self)); 288 | 289 | fprintf (file, "--------------------------------------\n"); 290 | if (!self) { 291 | fprintf (file, "NULL"); 292 | return; 293 | } 294 | assert (self); 295 | int is_bin = 0; 296 | uint char_nbr; 297 | for (char_nbr = 0; char_nbr < self->size; char_nbr++) 298 | if (self->data [char_nbr] < 9 || self->data [char_nbr] > 127) 299 | is_bin = 1; 300 | 301 | fprintf (file, "[%03d] ", (int) self->size); 302 | for (char_nbr = 0; char_nbr < self->size; char_nbr++) { 303 | if (is_bin) { 304 | fprintf (file, "%02X", (unsigned char) self->data [char_nbr]); 305 | if (char_nbr > 35) { 306 | fprintf (file, "..."); 307 | break; 308 | } 309 | } 310 | else { 311 | fprintf (file, "%c", self->data [char_nbr]); 312 | if (char_nbr > 70) { 313 | fprintf (file, "..."); 314 | break; 315 | } 316 | } 317 | } 318 | fprintf (file, "\n"); 319 | } 320 | 321 | 322 | 323 | // -------------------------------------------------------------------------- 324 | // Dump message to stderr, for debugging and tracing. 325 | // See zchunk_fprint for details 326 | 327 | void 328 | zchunk_print (zchunk_t *self) 329 | { 330 | assert (self); 331 | assert (zchunk_is (self)); 332 | 333 | zchunk_fprint (self, stderr); 334 | } 335 | 336 | 337 | // -------------------------------------------------------------------------- 338 | // Probe the supplied object, and report if it looks like a zchunk_t. 339 | 340 | bool 341 | zchunk_is (void *self) 342 | { 343 | assert (self); 344 | return ((zchunk_t *) self)->tag == ZCHUNK_TAG; 345 | } 346 | 347 | 348 | // -------------------------------------------------------------------------- 349 | // Self test of this class 350 | int 351 | zchunk_test (bool verbose) 352 | { 353 | printf (" * zchunk: "); 354 | 355 | // @selftest 356 | zchunk_t *chunk = zchunk_new ("1234567890", 10); 357 | assert (chunk); 358 | assert (zchunk_size (chunk) == 10); 359 | assert (memcmp (zchunk_data (chunk), "1234567890", 10) == 0); 360 | zchunk_destroy (&chunk); 361 | 362 | chunk = zchunk_new (NULL, 10); 363 | zchunk_append (chunk, "12345678", 8); 364 | zchunk_append (chunk, "90ABCDEF", 8); 365 | zchunk_append (chunk, "GHIJKLMN", 8); 366 | assert (memcmp (zchunk_data (chunk), "1234567890", 10) == 0); 367 | assert (zchunk_size (chunk) == 10); 368 | 369 | zchunk_t *copy = zchunk_dup (chunk); 370 | assert (memcmp (zchunk_data (copy), "1234567890", 10) == 0); 371 | assert (zchunk_size (copy) == 10); 372 | zchunk_destroy (©); 373 | zchunk_destroy (&chunk); 374 | 375 | copy = zchunk_new ("1234567890abcdefghij", 20); 376 | chunk = zchunk_new (NULL, 8); 377 | zchunk_consume (chunk, copy); 378 | assert (!zchunk_exhausted (copy)); 379 | assert (memcmp (zchunk_data (chunk), "12345678", 8) == 0); 380 | zchunk_set (chunk, NULL, 0); 381 | zchunk_consume (chunk, copy); 382 | assert (!zchunk_exhausted (copy)); 383 | assert (memcmp (zchunk_data (chunk), "90abcdef", 8) == 0); 384 | zchunk_set (chunk, NULL, 0); 385 | zchunk_consume (chunk, copy); 386 | assert (zchunk_exhausted (copy)); 387 | assert (zchunk_size (chunk) == 4); 388 | assert (memcmp (zchunk_data (chunk), "ghij", 4) == 0); 389 | zchunk_destroy (©); 390 | zchunk_destroy (&chunk); 391 | // @end 392 | 393 | printf ("OK\n"); 394 | return 0; 395 | } 396 | -------------------------------------------------------------------------------- /clients/zchunk.h: -------------------------------------------------------------------------------- 1 | /* ========================================================================= 2 | zchunk - work with memory chunks 3 | 4 | This file is part of zbroker, the ZeroMQ broker project. 5 | 6 | Copyright (c) the Contributors as noted in the AUTHORS file. 7 | This file is part of CZMQ, the high-level C binding for 0MQ: 8 | http://czmq.zeromq.org. 9 | 10 | This Source Code Form is subject to the terms of the Mozilla Public 11 | License, v. 2.0. If a copy of the MPL was not distributed with this 12 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 13 | ========================================================================= 14 | */ 15 | 16 | #ifndef __ZCHUNK_H_INCLUDED__ 17 | #define __ZCHUNK_H_INCLUDED__ 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | // @interface 24 | typedef struct _zchunk_t zchunk_t; 25 | 26 | // Create new chunk 27 | zchunk_t * 28 | zchunk_new (const void *data, size_t size); 29 | 30 | // Destroy a chunk 31 | void 32 | zchunk_destroy (zchunk_t **self_p); 33 | 34 | // Resizes chunk max_size as requested; chunk_cur size is set to zero 35 | void 36 | zchunk_resize (zchunk_t *self, size_t size); 37 | 38 | // Return chunk cur size 39 | size_t 40 | zchunk_size (zchunk_t *self); 41 | 42 | // Return chunk max size 43 | size_t 44 | zchunk_max_size (zchunk_t *self); 45 | 46 | // Return chunk data 47 | byte * 48 | zchunk_data (zchunk_t *self); 49 | 50 | // Set chunk data from user-supplied data; truncate if too large. Data may 51 | // be null. Returns actual size of chunk 52 | size_t 53 | zchunk_set (zchunk_t *self, const void *data, size_t size); 54 | 55 | // Fill chunk data from user-supplied octet 56 | size_t 57 | zchunk_fill (zchunk_t *self, byte filler, size_t size); 58 | 59 | // Append user-supplied data to chunk, return resulting chunk size 60 | size_t 61 | zchunk_append (zchunk_t *self, const void *data, size_t size); 62 | 63 | // Copy as much data from 'source' into the chunk as possible; returns the 64 | // new size of chunk. If all data from 'source' is used, returns exhausted 65 | // on the source chunk. Source can be consumed as many times as needed until 66 | // it is exhausted. If source was already exhausted, does not change chunk. 67 | size_t 68 | zchunk_consume (zchunk_t *self, zchunk_t *source); 69 | 70 | // Returns true if the chunk was exhausted by consume methods, or if the 71 | // chunk has a size of zero. 72 | bool 73 | zchunk_exhausted (zchunk_t *self); 74 | 75 | // Read chunk from an open file descriptor 76 | zchunk_t * 77 | zchunk_read (FILE *handle, size_t bytes); 78 | 79 | // Write chunk to an open file descriptor 80 | int 81 | zchunk_write (zchunk_t *self, FILE *handle); 82 | 83 | // Create copy of chunk, as new chunk object. Returns a fresh zchunk_t 84 | // object, or NULL if there was not enough heap memory. 85 | zchunk_t * 86 | zchunk_dup (zchunk_t *self); 87 | 88 | // Dump chunk to FILE stream, for debugging and tracing. 89 | void 90 | zchunk_fprint (zchunk_t *self, FILE *file); 91 | 92 | // Dump message to stderr, for debugging and tracing. 93 | // See zchunk_fprint for details 94 | void 95 | zchunk_print (zchunk_t *self); 96 | 97 | // Probe the supplied object, and report if it looks like a zchunk_t. 98 | bool 99 | zchunk_is (void *self); 100 | 101 | // Self test of this class 102 | int 103 | zchunk_test (bool verbose); 104 | // @end 105 | 106 | #ifdef __cplusplus 107 | } 108 | #endif 109 | 110 | #endif 111 | 112 | -------------------------------------------------------------------------------- /clients/zpipes_client.c: -------------------------------------------------------------------------------- 1 | /* ========================================================================= 2 | zpipes_client.c - API for zpipes client applications 3 | 4 | Copyright (c) the Contributors as noted in the AUTHORS file. 5 | This file is part of zbroker, the ZeroMQ server project. 6 | 7 | This Source Code Form is subject to the terms of the Mozilla Public 8 | License, v. 2.0. If a copy of the MPL was not distributed with this 9 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 10 | ========================================================================= 11 | */ 12 | 13 | /* 14 | @header 15 | Provides an API to the ZPIPES infrastructure. 16 | @discuss 17 | @end 18 | */ 19 | 20 | #include 21 | #include "zchunk.h" 22 | #include "zpipes_msg.h" 23 | #include "zpipes_client.h" 24 | 25 | 26 | // --------------------------------------------------------------------- 27 | // Structure of zpipes_client class 28 | 29 | struct _zpipes_client_t { 30 | zmtp_dealer_t *dealer; // Dealer socket to zpipes server 31 | int error; // Last error cause 32 | }; 33 | 34 | 35 | // Return 0 if the reply from the broker is what we expect, else return 36 | // -1. This includes interrupts. 37 | // TODO: implement timeout when broker doesn't reply at all 38 | // TODO: this loop should also PING the broker every second 39 | 40 | static int 41 | s_expect_reply (zpipes_client_t *self, int message_id) 42 | { 43 | zpipes_msg_t *reply = zpipes_msg_recv (self->dealer); 44 | if (!reply) 45 | return -1; 46 | int rc = zpipes_msg_id (reply) == message_id? 0: -1; 47 | zpipes_msg_destroy (&reply); 48 | return rc; 49 | } 50 | 51 | 52 | // --------------------------------------------------------------------- 53 | // Constructor; open ">pipename" for writing, "pipename" for reading 54 | // Returns a new client instance, or NULL if there was an error (e.g. 55 | // two readers trying to access same pipe). 56 | 57 | zpipes_client_t * 58 | zpipes_client_new (const char *server_name, const char *pipe_name) 59 | { 60 | // Create new pipe API instance 61 | zpipes_client_t *self = (zpipes_client_t *) zmalloc (sizeof (zpipes_client_t)); 62 | assert (self); 63 | 64 | // Create dealer socket and connect to server IPC port 65 | self->dealer = zmtp_dealer_new (); 66 | assert (self->dealer); 67 | 68 | // libzmtp does not yet support abstract IPC endpoints 69 | // so for now we need to use this style, also in zbroker.cfg 70 | // See https://github.com/zeromq/libzmtp/issues/31 71 | char endpoint [256]; 72 | snprintf (endpoint, 255, "@/zpipes/%s", server_name); 73 | endpoint [255] = 0; 74 | int rc = zmtp_dealer_ipc_connect (self->dealer, endpoint); 75 | assert (rc == 0); 76 | 77 | // Open pipe for reading or writing 78 | if (*pipe_name == '>') { 79 | zpipes_msg_send_output (self->dealer, pipe_name + 1); 80 | if (s_expect_reply (self, ZPIPES_MSG_OUTPUT_OK)) 81 | zpipes_client_destroy (&self); 82 | } 83 | else { 84 | zpipes_msg_send_input (self->dealer, pipe_name); 85 | if (s_expect_reply (self, ZPIPES_MSG_INPUT_OK)) 86 | zpipes_client_destroy (&self); 87 | } 88 | return self; 89 | } 90 | 91 | 92 | // --------------------------------------------------------------------- 93 | // Destructor 94 | 95 | void 96 | zpipes_client_destroy (zpipes_client_t **self_p) 97 | { 98 | assert (self_p); 99 | if (*self_p) { 100 | zpipes_client_t *self = *self_p; 101 | if (self->dealer) { 102 | // Send CLOSE to the server to drop any pipes the client 103 | // might have been using. We ignore the reply, which may 104 | // be ok, error, or null (if the process was interrupted). 105 | zpipes_msg_send_close (self->dealer); 106 | zpipes_msg_t *reply = zpipes_msg_recv (self->dealer); 107 | zpipes_msg_destroy (&reply); 108 | zmtp_dealer_destroy (&self->dealer); 109 | } 110 | free (self); 111 | *self_p = NULL; 112 | } 113 | } 114 | 115 | 116 | // --------------------------------------------------------------------- 117 | // Write chunk of data to pipe; returns number of bytes written, or -1 118 | // in case of error. To get the actual error code, call 119 | // zpipes_client_error(), which will be EINTR, EAGAIN, or EBADF. 120 | 121 | ssize_t 122 | zpipes_client_write (zpipes_client_t *self, void *data, size_t size, int timeout) 123 | { 124 | assert (self); 125 | zchunk_t *chunk = zchunk_new (data, size); 126 | assert (chunk); 127 | zpipes_msg_t *request = zpipes_msg_new (ZPIPES_MSG_WRITE); 128 | zpipes_msg_set_chunk (request, &chunk); 129 | zpipes_msg_set_timeout (request, timeout); 130 | zpipes_msg_send (&request, self->dealer); 131 | 132 | zpipes_msg_t *reply = zpipes_msg_recv (self->dealer); 133 | if (!reply) { 134 | self->error = EINTR; 135 | return -1; // Interrupted 136 | } 137 | ssize_t rc = size; 138 | if (zpipes_msg_id (reply) == ZPIPES_MSG_WRITE_TIMEOUT) { 139 | self->error = EAGAIN; 140 | rc = -1; 141 | } 142 | else 143 | if (zpipes_msg_id (reply) == ZPIPES_MSG_WRITE_FAILED) { 144 | // TODO: better error code? 145 | // This happens if we close a pipe while there's a pending write 146 | self->error = EINTR; 147 | rc = -1; 148 | } 149 | else 150 | if (zpipes_msg_id (reply) == ZPIPES_MSG_INVALID) { 151 | self->error = EBADF; 152 | rc = -1; 153 | } 154 | zpipes_msg_destroy (&reply); 155 | return rc; 156 | } 157 | 158 | 159 | // --------------------------------------------------------------------- 160 | // Read from the pipe. If the timeout is non-zero, waits at most that 161 | // many msecs for data. Returns number of bytes read, or zero if the 162 | // pipe was closed by the writer, and no more data is available. On a 163 | // timeout or interrupt, returns -1. To get the actual error code, call 164 | // zpipes_client_error(), which will be EINTR, EAGAIN, or EBADF. 165 | 166 | ssize_t 167 | zpipes_client_read (zpipes_client_t *self, void *data, size_t size, int timeout) 168 | { 169 | assert (self); 170 | 171 | zpipes_msg_send_read (self->dealer, size, timeout); 172 | zpipes_msg_t *reply = zpipes_msg_recv (self->dealer); 173 | if (!reply) { 174 | self->error = EINTR; 175 | return -1; // Interrupted 176 | } 177 | ssize_t rc = 0; 178 | if (zpipes_msg_id (reply) == ZPIPES_MSG_READ_OK) { 179 | zchunk_t *chunk = zpipes_msg_chunk (reply); 180 | ssize_t bytes = zchunk_size (chunk); 181 | assert (bytes <= size); 182 | memcpy (data, zchunk_data (chunk), bytes); 183 | rc = bytes; 184 | } 185 | else 186 | if (zpipes_msg_id (reply) == ZPIPES_MSG_READ_END) 187 | rc = 0; 188 | else 189 | if (zpipes_msg_id (reply) == ZPIPES_MSG_READ_TIMEOUT) { 190 | self->error = EAGAIN; 191 | rc = -1; 192 | } 193 | else 194 | if (zpipes_msg_id (reply) == ZPIPES_MSG_READ_FAILED) { 195 | // TODO: better error code? 196 | // This happens if we close a pipe while there's a pending read 197 | self->error = EINTR; 198 | rc = -1; 199 | } 200 | else 201 | if (zpipes_msg_id (reply) == ZPIPES_MSG_INVALID) { 202 | self->error = EBADF; 203 | rc = -1; 204 | } 205 | zpipes_msg_destroy (&reply); 206 | return rc; 207 | } 208 | 209 | 210 | // --------------------------------------------------------------------- 211 | // Returns last error number, if any 212 | 213 | int 214 | zpipes_client_error (zpipes_client_t *self) 215 | { 216 | assert (self); 217 | return self->error; 218 | } 219 | 220 | 221 | // --------------------------------------------------------------------- 222 | // Self test of this class 223 | 224 | void 225 | zpipes_client_test (bool verbose) 226 | { 227 | printf (" * zpipes_client: "); 228 | // @selftest 229 | // Cannot do a selftest here as we can't start the broker from 230 | // inside this library... see stand-alone zpipes_test_client.c. 231 | // @end 232 | printf ("OK\n"); 233 | } 234 | -------------------------------------------------------------------------------- /clients/zpipes_client.h: -------------------------------------------------------------------------------- 1 | /* ========================================================================= 2 | zpipes_client.h - simple API for zpipes client applications 3 | 4 | Copyright (c) the Contributors as noted in the AUTHORS file. 5 | This file is part of zbroker, the ZeroMQ broker project. 6 | 7 | This Source Code Form is subject to the terms of the Mozilla Public 8 | License, v. 2.0. If a copy of the MPL was not distributed with this 9 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 10 | ========================================================================= 11 | */ 12 | 13 | #ifndef __ZPIPES_CLIENT_H_INCLUDED__ 14 | #define __ZPIPES_CLIENT_H_INCLUDED__ 15 | 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif 19 | 20 | typedef struct _zpipes_client_t zpipes_client_t; 21 | 22 | // @interface 23 | // Constructor; open ">pipename" for writing, "pipename" for reading 24 | zpipes_client_t * 25 | zpipes_client_new (const char *broker_name, const char *pipe_name); 26 | 27 | // Destructor; closes pipe 28 | void 29 | zpipes_client_destroy (zpipes_client_t **self_p); 30 | 31 | // Write chunk of data to pipe; returns number of bytes written, or -1 32 | // in case of error, and then sets zpipes_client_error() to EBADF. 33 | ssize_t 34 | zpipes_client_write (zpipes_client_t *self, 35 | void *data, size_t size, int timeout); 36 | 37 | // Read chunk of data from pipe. If timeout is non zero, waits at most 38 | // that many msecs for data. Returns number of bytes read, or zero if the 39 | // pipe was closed by the writer, and no more data is available. On a 40 | // timeout or interrupt, returns -1. To get the actual error code, call 41 | // zpipes_client_error(), which will be EINTR, EAGAIN, or EBADF. 42 | ssize_t 43 | zpipes_client_read (zpipes_client_t *self, 44 | void *data, size_t max_size, int timeout); 45 | 46 | // Returns last error number, if any 47 | int 48 | zpipes_client_error (zpipes_client_t *self); 49 | 50 | // Self test of this class 51 | void 52 | zpipes_client_test (bool verbose); 53 | // @end 54 | 55 | #ifdef __cplusplus 56 | } 57 | #endif 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /clients/zpipes_msg.h: -------------------------------------------------------------------------------- 1 | /* ========================================================================= 2 | zpipes_msg - ZPIPES protocol 3 | 4 | Codec header for zpipes_msg. 5 | 6 | ** WARNING ************************************************************* 7 | THIS SOURCE FILE IS 100% GENERATED. If you edit this file, you will lose 8 | your changes at the next build cycle. This is great for temporary printf 9 | statements. DO NOT MAKE ANY CHANGES YOU WISH TO KEEP. The correct places 10 | for commits are: 11 | 12 | * The XML model used for this code generation: zpipes_msg.xml 13 | * The code generation script that built this file: codec_libzmtp 14 | ************************************************************************ 15 | Copyright (c) the Contributors as noted in the AUTHORS file. 16 | This file is part of zbroker, the ZeroMQ broker project. 17 | 18 | This Source Code Form is subject to the terms of the Mozilla Public 19 | License, v. 2.0. If a copy of the MPL was not distributed with this 20 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 21 | ========================================================================= 22 | */ 23 | 24 | #ifndef __ZPIPES_MSG_H_INCLUDED__ 25 | #define __ZPIPES_MSG_H_INCLUDED__ 26 | 27 | /* These are the zpipes_msg messages: 28 | 29 | INPUT - Create a new pipe for reading 30 | pipename string Name of pipe 31 | 32 | INPUT_OK - Input request was successful 33 | 34 | INPUT_FAILED - Input request failed 35 | reason string Reason for failure 36 | 37 | OUTPUT - Create a new pipe for writing 38 | pipename string Name of pipe 39 | 40 | OUTPUT_OK - Output request was successful 41 | 42 | OUTPUT_FAILED - Output request failed 43 | reason string Reason for failure 44 | 45 | READ - Read a chunk of data from pipe 46 | size number 4 Number of bytes to read 47 | timeout number 4 Timeout, msecs, or zero 48 | 49 | READ_OK - Read was successful 50 | chunk chunk Chunk of data 51 | 52 | READ_END - Pipe is closed, no more data 53 | 54 | READ_TIMEOUT - Read ended with timeout 55 | 56 | READ_FAILED - Read failed due to error 57 | reason string Reason for failure 58 | 59 | WRITE - Write chunk of data to pipe 60 | chunk chunk Chunk of data 61 | timeout number 4 Timeout, msecs, or zero 62 | 63 | WRITE_OK - Write was successful 64 | 65 | WRITE_TIMEOUT - Write ended with timeout 66 | 67 | WRITE_FAILED - Read failed due to error 68 | reason string Reason for failure 69 | 70 | CLOSE - Close pipe 71 | 72 | CLOSE_OK - Close was successful 73 | 74 | CLOSE_FAILED - Close failed due to error 75 | reason string Reason for failure 76 | 77 | PING - Signal liveness 78 | 79 | PING_OK - Respond to ping 80 | 81 | INVALID - Command was invalid at this time 82 | */ 83 | 84 | 85 | #define ZPIPES_MSG_INPUT 1 86 | #define ZPIPES_MSG_INPUT_OK 2 87 | #define ZPIPES_MSG_INPUT_FAILED 3 88 | #define ZPIPES_MSG_OUTPUT 4 89 | #define ZPIPES_MSG_OUTPUT_OK 5 90 | #define ZPIPES_MSG_OUTPUT_FAILED 6 91 | #define ZPIPES_MSG_READ 7 92 | #define ZPIPES_MSG_READ_OK 8 93 | #define ZPIPES_MSG_READ_END 9 94 | #define ZPIPES_MSG_READ_TIMEOUT 10 95 | #define ZPIPES_MSG_READ_FAILED 11 96 | #define ZPIPES_MSG_WRITE 12 97 | #define ZPIPES_MSG_WRITE_OK 13 98 | #define ZPIPES_MSG_WRITE_TIMEOUT 14 99 | #define ZPIPES_MSG_WRITE_FAILED 15 100 | #define ZPIPES_MSG_CLOSE 16 101 | #define ZPIPES_MSG_CLOSE_OK 17 102 | #define ZPIPES_MSG_CLOSE_FAILED 18 103 | #define ZPIPES_MSG_PING 19 104 | #define ZPIPES_MSG_PING_OK 20 105 | #define ZPIPES_MSG_INVALID 21 106 | 107 | #ifdef __cplusplus 108 | extern "C" { 109 | #endif 110 | 111 | // Opaque class structure 112 | typedef struct _zpipes_msg_t zpipes_msg_t; 113 | 114 | // @interface 115 | // Create a new zpipes_msg 116 | zpipes_msg_t * 117 | zpipes_msg_new (int id); 118 | 119 | // Destroy the zpipes_msg 120 | void 121 | zpipes_msg_destroy (zpipes_msg_t **self_p); 122 | 123 | // Parse a zpipes_msg from zmtp_msg_t. Returns a new object, or NULL 124 | // if the message could not be parsed, or was NULL. Nullifies the msg 125 | // reference. 126 | zpipes_msg_t * 127 | zpipes_msg_decode (zmtp_msg_t **msg_p); 128 | 129 | // Encode zpipes_msg into a message. Returns a newly created object 130 | // or NULL if error. Use when not in control of sending the message. 131 | // Destroys the zpipes_msg_t instance. 132 | zmtp_msg_t * 133 | zpipes_msg_encode (zpipes_msg_t **self_p); 134 | 135 | // Receive and parse a zpipes_msg from the socket. Returns new object, 136 | // or NULL if error. Will block if there's no message waiting. 137 | zpipes_msg_t * 138 | zpipes_msg_recv (zmtp_dealer_t *input); 139 | 140 | // Send the zpipes_msg to the output, and destroy it 141 | int 142 | zpipes_msg_send (zpipes_msg_t **self_p, zmtp_dealer_t *output); 143 | 144 | // Send the INPUT to the output in one step 145 | int 146 | zpipes_msg_send_input (zmtp_dealer_t *output, 147 | const char *pipename); 148 | 149 | // Send the INPUT_OK to the output in one step 150 | int 151 | zpipes_msg_send_input_ok (zmtp_dealer_t *output); 152 | 153 | // Send the INPUT_FAILED to the output in one step 154 | int 155 | zpipes_msg_send_input_failed (zmtp_dealer_t *output, 156 | const char *reason); 157 | 158 | // Send the OUTPUT to the output in one step 159 | int 160 | zpipes_msg_send_output (zmtp_dealer_t *output, 161 | const char *pipename); 162 | 163 | // Send the OUTPUT_OK to the output in one step 164 | int 165 | zpipes_msg_send_output_ok (zmtp_dealer_t *output); 166 | 167 | // Send the OUTPUT_FAILED to the output in one step 168 | int 169 | zpipes_msg_send_output_failed (zmtp_dealer_t *output, 170 | const char *reason); 171 | 172 | // Send the READ to the output in one step 173 | int 174 | zpipes_msg_send_read (zmtp_dealer_t *output, 175 | uint32_t size, 176 | uint32_t timeout); 177 | 178 | // Send the READ_OK to the output in one step 179 | int 180 | zpipes_msg_send_read_ok (zmtp_dealer_t *output, 181 | zchunk_t *chunk); 182 | 183 | // Send the READ_END to the output in one step 184 | int 185 | zpipes_msg_send_read_end (zmtp_dealer_t *output); 186 | 187 | // Send the READ_TIMEOUT to the output in one step 188 | int 189 | zpipes_msg_send_read_timeout (zmtp_dealer_t *output); 190 | 191 | // Send the READ_FAILED to the output in one step 192 | int 193 | zpipes_msg_send_read_failed (zmtp_dealer_t *output, 194 | const char *reason); 195 | 196 | // Send the WRITE to the output in one step 197 | int 198 | zpipes_msg_send_write (zmtp_dealer_t *output, 199 | zchunk_t *chunk, 200 | uint32_t timeout); 201 | 202 | // Send the WRITE_OK to the output in one step 203 | int 204 | zpipes_msg_send_write_ok (zmtp_dealer_t *output); 205 | 206 | // Send the WRITE_TIMEOUT to the output in one step 207 | int 208 | zpipes_msg_send_write_timeout (zmtp_dealer_t *output); 209 | 210 | // Send the WRITE_FAILED to the output in one step 211 | int 212 | zpipes_msg_send_write_failed (zmtp_dealer_t *output, 213 | const char *reason); 214 | 215 | // Send the CLOSE to the output in one step 216 | int 217 | zpipes_msg_send_close (zmtp_dealer_t *output); 218 | 219 | // Send the CLOSE_OK to the output in one step 220 | int 221 | zpipes_msg_send_close_ok (zmtp_dealer_t *output); 222 | 223 | // Send the CLOSE_FAILED to the output in one step 224 | int 225 | zpipes_msg_send_close_failed (zmtp_dealer_t *output, 226 | const char *reason); 227 | 228 | // Send the PING to the output in one step 229 | int 230 | zpipes_msg_send_ping (zmtp_dealer_t *output); 231 | 232 | // Send the PING_OK to the output in one step 233 | int 234 | zpipes_msg_send_ping_ok (zmtp_dealer_t *output); 235 | 236 | // Send the INVALID to the output in one step 237 | int 238 | zpipes_msg_send_invalid (zmtp_dealer_t *output); 239 | 240 | // Duplicate the zpipes_msg message 241 | zpipes_msg_t * 242 | zpipes_msg_dup (zpipes_msg_t *self); 243 | 244 | // Print contents of message to stdout 245 | void 246 | zpipes_msg_dump (zpipes_msg_t *self); 247 | 248 | // Get the zpipes_msg id and printable command 249 | int 250 | zpipes_msg_id (zpipes_msg_t *self); 251 | void 252 | zpipes_msg_set_id (zpipes_msg_t *self, int id); 253 | const char * 254 | zpipes_msg_command (zpipes_msg_t *self); 255 | 256 | // Get/set the pipename field 257 | const char * 258 | zpipes_msg_pipename (zpipes_msg_t *self); 259 | void 260 | zpipes_msg_set_pipename (zpipes_msg_t *self, const char *format, ...); 261 | 262 | // Get/set the reason field 263 | const char * 264 | zpipes_msg_reason (zpipes_msg_t *self); 265 | void 266 | zpipes_msg_set_reason (zpipes_msg_t *self, const char *format, ...); 267 | 268 | // Get/set the size field 269 | uint32_t 270 | zpipes_msg_size (zpipes_msg_t *self); 271 | void 272 | zpipes_msg_set_size (zpipes_msg_t *self, uint32_t size); 273 | 274 | // Get/set the timeout field 275 | uint32_t 276 | zpipes_msg_timeout (zpipes_msg_t *self); 277 | void 278 | zpipes_msg_set_timeout (zpipes_msg_t *self, uint32_t timeout); 279 | 280 | // Get a copy of the chunk field 281 | zchunk_t * 282 | zpipes_msg_chunk (zpipes_msg_t *self); 283 | // Get the chunk field and transfer ownership to caller 284 | zchunk_t * 285 | zpipes_msg_get_chunk (zpipes_msg_t *self); 286 | // Set the chunk field, transferring ownership from caller 287 | void 288 | zpipes_msg_set_chunk (zpipes_msg_t *self, zchunk_t **chunk_p); 289 | 290 | // Self test of this class 291 | int 292 | zpipes_msg_test (bool verbose); 293 | // @end 294 | 295 | #ifdef __cplusplus 296 | } 297 | #endif 298 | 299 | #endif 300 | -------------------------------------------------------------------------------- /clients/zpipes_msg.xml: -------------------------------------------------------------------------------- 1 | 6 | This is a codec for the ZPIPES protocol (RFC tbd) 7 | 8 | 9 | 10 | ZPIPES = reader | writer 11 | 12 | reader = input-command *( read-command | ping-command ) 13 | close-command 14 | input-command = c:input ( s:input-ok | s:input-failed ) 15 | read-command = c:read ( s:read-ok | s:read-end 16 | | s:read-timeout | s:read-failed ) 17 | close-command = c:close ( s:close-ok | s:close-failed ) 18 | 19 | writer = output-command *write-command close-command 20 | output-command = c:output ( s:output-ok | s:output-failed ) 21 | write-command = c:write ( s:write-ok 22 | | s:write-timeout | s:write-failed ) 23 | ping-command = c:ping s:ping-ok 24 | 25 | 26 | 27 | Create a new pipe for reading 28 | Name of pipe 29 | 30 | 31 | 32 | Input request was successful 33 | 34 | 35 | 36 | Input request failed 37 | Reason for failure 38 | 39 | 40 | 41 | Create a new pipe for writing 42 | Name of pipe 43 | 44 | 45 | 46 | Output request was successful 47 | 48 | 49 | 50 | Output request failed 51 | Reason for failure 52 | 53 | 54 | 55 | Read a chunk of data from pipe 56 | Number of bytes to read 57 | Timeout, msecs, or zero 58 | 59 | 60 | 61 | Read was successful 62 | Chunk of data 63 | 64 | 65 | 66 | Pipe is closed, no more data 67 | 68 | 69 | 70 | Read ended with timeout 71 | 72 | 73 | 74 | Read failed due to error 75 | Reason for failure 76 | 77 | 78 | 79 | Write chunk of data to pipe 80 | Chunk of data 81 | Timeout, msecs, or zero 82 | 83 | 84 | 85 | Write was successful 86 | 87 | 88 | 89 | Write ended with timeout 90 | 91 | 92 | 93 | Read failed due to error 94 | Reason for failure 95 | 96 | 97 | 98 | Close pipe 99 | 100 | 101 | 102 | Close was successful 103 | 104 | 105 | 106 | Close failed due to error 107 | Reason for failure 108 | 109 | 110 | 111 | Signal liveness 112 | 113 | 114 | 115 | Respond to ping 116 | 117 | 118 | 119 | Command was invalid at this time 120 | 121 | 122 | -------------------------------------------------------------------------------- /clients/zpipes_selftest.c: -------------------------------------------------------------------------------- 1 | /* ========================================================================= 2 | selftest - run self tests 3 | 4 | ------------------------------------------------------------------------- 5 | Copyright (c) the Contributors as noted in the AUTHORS file. 6 | This file is part of zbroker, the ZeroMQ broker project. 7 | 8 | This Source Code Form is subject to the terms of the Mozilla Public 9 | License, v. 2.0. If a copy of the MPL was not distributed with this 10 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 11 | ========================================================================= 12 | */ 13 | 14 | #include 15 | #include "zchunk.h" 16 | #include "zpipes_msg.h" 17 | #include "zpipes_client.h" 18 | 19 | int main (int argc, char *argv []) 20 | { 21 | bool verbose; 22 | if (argc == 2 && streq (argv [1], "-v")) 23 | verbose = true; 24 | else 25 | verbose = false; 26 | 27 | printf ("Running self tests...\n"); 28 | zpipes_msg_test (verbose); 29 | zpipes_client_test (verbose); 30 | printf ("Tests passed OK\n"); 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /clients/zpipes_test_client.c: -------------------------------------------------------------------------------- 1 | /* ========================================================================= 2 | zpipes_test_client.c - stand-alone test case for thin client 3 | 4 | Copyright (c) the Contributors as noted in the AUTHORS file. 5 | This file is part of zbroker, the ZeroMQ broker project. 6 | 7 | This Source Code Form is subject to the terms of the Mozilla Public 8 | License, v. 2.0. If a copy of the MPL was not distributed with this 9 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 10 | ========================================================================= 11 | */ 12 | 13 | 14 | #include 15 | #include "zchunk.h" 16 | #include "zpipes_msg.h" 17 | #include "zpipes_client.h" 18 | 19 | int main (void) 20 | { 21 | puts ("Please start zbroker and press [Enter]"); 22 | getchar (); 23 | 24 | zpipes_client_t *reader = zpipes_client_new ("local", "test pipe"); 25 | zpipes_client_t *writer = zpipes_client_new ("local", ">test pipe"); 26 | 27 | byte buffer [100]; 28 | ssize_t bytes; 29 | 30 | // Expect timeout error, EAGAIN 31 | bytes = zpipes_client_read (reader, buffer, 6, 100); 32 | assert (bytes == -1); 33 | assert (zpipes_client_error (reader) == EAGAIN); 34 | 35 | bytes = zpipes_client_write (writer, "CHUNK1", 6, 100); 36 | assert (bytes == 6); 37 | bytes = zpipes_client_write (writer, "CHUNK2", 6, 100); 38 | assert (bytes == 6); 39 | bytes = zpipes_client_write (writer, "CHUNK3", 6, 100); 40 | assert (bytes == 6); 41 | 42 | bytes = zpipes_client_read (reader, buffer, 1, 100); 43 | assert (bytes == 1); 44 | bytes = zpipes_client_read (reader, buffer, 10, 100); 45 | assert (bytes == 10); 46 | 47 | // Now close writer 48 | zpipes_client_destroy (&writer); 49 | 50 | // Expect end of pipe (short read) 51 | bytes = zpipes_client_read (reader, buffer, 50, 100); 52 | assert (bytes == 7); 53 | 54 | // Expect end of pipe (empty chunk) 55 | bytes = zpipes_client_read (reader, buffer, 50, 100); 56 | assert (bytes == 0); 57 | 58 | // Expect illegal action (EBADF) writing on reader 59 | bytes = zpipes_client_write (reader, "CHUNK1", 6, 100); 60 | assert (bytes == -1); 61 | assert (zpipes_client_error (reader) == EBADF); 62 | 63 | zpipes_client_destroy (&reader); 64 | return 0; 65 | } 66 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # -*- Autoconf -*- 2 | # Process this file with autoconf to produce a configure script. 3 | AC_PREREQ(2.61) 4 | # 5 | # The version number is extracted from include/zbroker.h using 6 | # the version.sh script. Hence, it should be updated there. 7 | # The version in git should reflect the *next* version planned. 8 | # 9 | AC_INIT([zbroker],[m4_esyscmd([./version.sh zbroker])],[zeromq-dev@lists.zeromq.org]) 10 | 11 | AC_CONFIG_AUX_DIR(config) 12 | AC_CONFIG_MACRO_DIR(config) 13 | AC_CONFIG_HEADERS([src/platform.h]) 14 | AM_INIT_AUTOMAKE([tar-ustar foreign]) 15 | m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) 16 | 17 | # This defines PACKAGE_VERSION_... in src/platform.h 18 | PV_MAJOR=`echo $PACKAGE_VERSION | cut -d . -f 1` 19 | PV_MINOR=`echo $PACKAGE_VERSION | cut -d . -f 2` 20 | PV_PATCH=`echo $PACKAGE_VERSION | cut -d . -f 3` 21 | AC_DEFINE_UNQUOTED([PACKAGE_VERSION_MAJOR],[$PV_MAJOR], 22 | [ZBROKER major version]) 23 | AC_DEFINE_UNQUOTED([PACKAGE_VERSION_MINOR],[$PV_MINOR], 24 | [ZBROKER minor version]) 25 | AC_DEFINE_UNQUOTED([PACKAGE_VERSION_PATCH],[$PV_PATCH], 26 | [ZBROKER patchlevel]) 27 | # This lets us use PACKAGE_VERSION in Makefiles 28 | AC_SUBST(PACKAGE_VERSION) 29 | 30 | # 31 | # Libtool -version-info (ABI version) 32 | # 33 | # Currently 0.0.0. Don't change this unless you know 34 | # exactly what you're doing, and have read and understand 35 | # http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html 36 | # 37 | # libzbroker -version-info 38 | LTVER="0:0:0" 39 | 40 | # libzpipesclient -version-info 41 | CLIENT_LTVER="0:0:0" 42 | 43 | AC_SUBST(LTVER) 44 | AC_SUBST(CLIENT_LTVER) 45 | 46 | # Capture c flags 47 | ZBROKER_ORIG_CFLAGS="${CFLAGS:-none}" 48 | 49 | # Checks for programs 50 | AC_PROG_CC 51 | AC_PROG_CC_C99 52 | AM_PROG_CC_C_O 53 | AC_LIBTOOL_WIN32_DLL 54 | AC_PROG_LIBTOOL 55 | AC_PROG_SED 56 | AC_PROG_AWK 57 | 58 | # Code coverage 59 | AC_ARG_WITH(gcov, [AS_HELP_STRING([--with-gcov=yes/no], 60 | [With GCC Code Coverage reporting.])], 61 | [ZBROKER_GCOV="$withval"]) 62 | 63 | if test "x${ZBROKER_GCOV}" == "xyes"; then 64 | CFLAGS="-O0 -g -fprofile-arcs -ftest-coverage" 65 | 66 | if test "x${ZBROKER_ORIG_CFLAGS}" != "xnone"; then 67 | CFLAGS="${CFLAGS} ${ZBROKER_ORIG_CFLAGS}" 68 | fi 69 | fi 70 | 71 | # libzmq integration 72 | AC_ARG_WITH([libzmq], 73 | [AS_HELP_STRING([--with-libzmq], 74 | [Specify libzmq prefix])], 75 | [search_libzmq="yes"], 76 | []) 77 | 78 | if test "x$search_libzmq" = "xyes"; then 79 | if test -r "${with_libzmq}/include/zmq.h"; then 80 | CFLAGS="-I${with_libzmq}/include ${CFLAGS}" 81 | LDFLAGS="-L${with_libzmq}/lib ${LDFLAGS}" 82 | else 83 | AC_MSG_ERROR([${with_libzmq}/include/zmq.h not found. Please check libzmq prefix]) 84 | fi 85 | fi 86 | 87 | AC_CHECK_LIB(zmq, zmq_init, 88 | LIBS="-lzmq $LIBS", 89 | [AC_MSG_ERROR([cannot link with -lzmq, install libzmq.])]) 90 | 91 | AC_MSG_CHECKING([whether libzmq installation works]) 92 | AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], 93 | [zmq_init(1);]) ], 94 | [AC_MSG_RESULT([yes])], 95 | [AC_MSG_ERROR([no. Please specify libzmq installation prefix using --with-libzmq])]) 96 | 97 | # libczmq integration 98 | AC_ARG_WITH([libczmq], 99 | [AS_HELP_STRING([--with-libczmq], 100 | [Specify libczmq prefix])], 101 | [search_libczmq="yes"], []) 102 | 103 | if test "x$search_libczmq" = "xyes"; then 104 | if test -r "${with_libczmq}/include/czmq.h"; then 105 | CFLAGS="-I${with_libczmq}/include ${CFLAGS}" 106 | LDFLAGS="-L${with_libczmq}/lib ${LDFLAGS}" 107 | else 108 | AC_MSG_ERROR([${with_libczmq}/include/czmq.h not found. Please check libczmq prefix]) 109 | fi 110 | fi 111 | 112 | AC_CHECK_LIB(czmq, zctx_test, 113 | LIBS="-lczmq $LIBS", 114 | [AC_MSG_ERROR([cannot link with -lczmq, install libczmq.])]) 115 | 116 | AC_MSG_CHECKING([whether libczmq installation works]) 117 | AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], 118 | [zctx_test (0);]) ], 119 | [AC_MSG_RESULT([yes])], 120 | [AC_MSG_ERROR([no. Please specify libczmq installation prefix using --with-czmq])]) 121 | 122 | # libzyre integration 123 | AC_ARG_WITH([libzyre], 124 | [AS_HELP_STRING([--with-libzyre], 125 | [Specify libzyre prefix])], 126 | [search_libzyre="yes"], []) 127 | 128 | if test "x$search_libzyre" = "xyes"; then 129 | if test -r "${with_libzyre}/include/zyre.h"; then 130 | CFLAGS="-I${with_libzyre}/include ${CFLAGS}" 131 | LDFLAGS="-L${with_libzyre}/lib ${LDFLAGS}" 132 | else 133 | AC_MSG_ERROR([${with_libzyre}/include/zyre.h not found. Please check libzyre prefix]) 134 | fi 135 | fi 136 | 137 | AC_CHECK_LIB(zyre, zctx_test, 138 | LIBS="-lzyre $LIBS", 139 | [AC_MSG_ERROR([cannot link with -lzyre, install libzyre.])]) 140 | 141 | AC_MSG_CHECKING([whether libzyre installation works]) 142 | AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], 143 | [zctx_test (0);]) ], 144 | [AC_MSG_RESULT([yes])], 145 | [AC_MSG_ERROR([no. Please specify libzyre installation prefix using --with-zyre])]) 146 | 147 | 148 | # Platform specific checks 149 | zbroker_on_mingw32="no" 150 | 151 | # Host speciffic checks 152 | AC_CANONICAL_HOST 153 | 154 | # Determine whether or not documentation should be built and installed. 155 | zbroker_build_doc="yes" 156 | zbroker_install_man="yes" 157 | 158 | # Check for asciidoc and xmlto and don't build the docs if these are not installed. 159 | AC_CHECK_PROG(zbroker_have_asciidoc, asciidoc, yes, no) 160 | AC_CHECK_PROG(zbroker_have_xmlto, xmlto, yes, no) 161 | if test "x$zbroker_have_asciidoc" = "xno" -o "x$zbroker_have_xmlto" = "xno"; then 162 | zbroker_build_doc="no" 163 | # Tarballs built with 'make dist' ship with prebuilt documentation. 164 | if ! test -f doc/zbroker.7; then 165 | zbroker_install_man="no" 166 | AC_MSG_WARN([You are building an unreleased version of zbroker and asciidoc or xmlto are not installed.]) 167 | AC_MSG_WARN([Documentation will not be built and manual pages will not be installed.]) 168 | fi 169 | fi 170 | AC_MSG_CHECKING([whether to build documentation]) 171 | AC_MSG_RESULT([$zbroker_build_doc]) 172 | AC_MSG_CHECKING([whether to install manpages]) 173 | AC_MSG_RESULT([$zbroker_install_man]) 174 | 175 | # Set some default features required by zbroker code. 176 | CPPFLAGS="-D_REENTRANT -D_THREAD_SAFE $CPPFLAGS" 177 | 178 | # OS-specific tests 179 | case "${host_os}" in 180 | *linux*) 181 | # Define on Linux to enable all library features 182 | CPPFLAGS="-D_GNU_SOURCE -DLINUX $CPPFLAGS" 183 | AC_DEFINE(ZBROKER_HAVE_LINUX, 1, [Have Linux OS]) 184 | ;; 185 | *solaris*) 186 | # Define on Solaris to enable all library features 187 | CPPFLAGS="-D_PTHREADS $CPPFLAGS" 188 | AC_DEFINE(ZBROKER_HAVE_SOLARIS, 1, [Have Solaris OS]) 189 | CFLAGS="${CFLAGS} -lsocket -lssp" 190 | ;; 191 | *freebsd*) 192 | # Define on FreeBSD to enable all library features 193 | CPPFLAGS="-D__BSD_VISIBLE $CPPFLAGS" 194 | AC_DEFINE(ZBROKER_HAVE_FREEBSD, 1, [Have FreeBSD OS]) 195 | ;; 196 | *darwin*) 197 | # Define on Darwin to enable all library features 198 | CPPFLAGS="-D_DARWIN_C_SOURCE $CPPFLAGS" 199 | AC_DEFINE(ZBROKER_HAVE_OSX, 1, [Have DarwinOSX OS]) 200 | ;; 201 | *netbsd*) 202 | # Define on NetBSD to enable all library features 203 | CPPFLAGS="-D_NETBSD_SOURCE $CPPFLAGS" 204 | AC_DEFINE(ZBROKER_HAVE_NETBSD, 1, [Have NetBSD OS]) 205 | ;; 206 | *openbsd*) 207 | # Define on OpenBSD to enable all library features 208 | CPPFLAGS="-D_BSD_SOURCE $CPPFLAGS" 209 | AC_DEFINE(ZBROKER_HAVE_OPENBSD, 1, [Have OpenBSD OS]) 210 | ;; 211 | *nto-qnx*) 212 | AC_DEFINE(ZBROKER_HAVE_QNXNTO, 1, [Have QNX Neutrino OS]) 213 | ;; 214 | *aix*) 215 | AC_DEFINE(ZBROKER_HAVE_AIX, 1, [Have AIX OS]) 216 | ;; 217 | *hpux*) 218 | # Define on HP-UX to enable all library features 219 | CPPFLAGS="-D_POSIX_C_SOURCE=200112L" 220 | AC_DEFINE(ZBROKER_HAVE_HPUX, 1, [Have HPUX OS]) 221 | ;; 222 | *mingw32*) 223 | AC_DEFINE(ZBROKER_HAVE_WINDOWS, 1, [Have Windows OS]) 224 | AC_DEFINE(ZBROKER_HAVE_MINGW32, 1, [Have MinGW32]) 225 | AC_CHECK_HEADERS(windows.h) 226 | zbroker_on_mingw32="yes" 227 | zbroker_install_man="no" 228 | ;; 229 | *cygwin*) 230 | # Define on Cygwin to enable all library features 231 | CPPFLAGS="-D_GNU_SOURCE $CPPFLAGS" 232 | AC_DEFINE(ZBROKER_HAVE_CYGWIN, 1, [Have Cygwin]) 233 | ;; 234 | *) 235 | AC_MSG_ERROR([unsupported system: ${host_os}.]) 236 | ;; 237 | esac 238 | 239 | # Check for libsodium 240 | AC_CHECK_LIB([sodium], [sodium_init],,AC_MSG_WARN(libsodium is needed for CURVE security)) 241 | 242 | # Checks for header files. 243 | AC_HEADER_STDC 244 | AC_CHECK_HEADERS(errno.h arpa/inet.h netinet/tcp.h netinet/in.h stddef.h \ 245 | stdlib.h string.h sys/socket.h sys/time.h unistd.h limits.h ifaddrs.h) 246 | AC_CHECK_HEADERS([net/if.h net/if_media.h linux/wireless.h], [], [], 247 | [ 248 | #ifdef HAVE_SYS_SOCKET_H 249 | # include 250 | #endif 251 | #include 252 | ]) 253 | 254 | # Checks for typedefs, structures, and compiler characteristics. 255 | AC_HEADER_STDBOOL 256 | AC_C_CONST 257 | AC_C_INLINE 258 | AC_TYPE_SIZE_T 259 | AC_TYPE_SSIZE_T 260 | AC_HEADER_TIME 261 | AC_TYPE_UINT32_T 262 | AC_C_VOLATILE 263 | 264 | # These options are GNU compiler specific. 265 | if test "x$GCC" = "xyes"; then 266 | CPPFLAGS="-pedantic -Werror -Wall ${CPPFLAGS}" 267 | fi 268 | 269 | AM_CONDITIONAL(ON_MINGW, test "x$zbroker_on_mingw32" = "xyes") 270 | AM_CONDITIONAL(INSTALL_MAN, test "x$zbroker_install_man" = "xyes") 271 | AM_CONDITIONAL(BUILD_DOC, test "x$zbroker_build_doc" = "xyes") 272 | 273 | # Checks for library functions. 274 | AC_TYPE_SIGNAL 275 | AC_CHECK_FUNCS(perror gettimeofday memset getifaddrs freeifaddrs) 276 | 277 | # Specify output files 278 | AC_CONFIG_FILES([ 279 | Makefile 280 | src/Makefile 281 | src/libzbroker.pc 282 | clients/Makefile 283 | clients/libzbroker_cli.pc 284 | doc/Makefile]) 285 | AC_OUTPUT 286 | -------------------------------------------------------------------------------- /doc/Makefile.am: -------------------------------------------------------------------------------- 1 | MAN1 = 2 | MAN3 = zpipes_server.3 zpipes_client.3 zpipes_msg.3 3 | MAN7 = 4 | MAN_DOC = $(MAN1) $(MAN3) $(MAN7) 5 | 6 | MAN_TXT = $(MAN1:%.1=%.txt) 7 | MAN_TXT += $(MAN3:%.3=%.txt) 8 | MAN_TXT += $(MAN7:%.7=%.txt) 9 | 10 | if INSTALL_MAN 11 | dist_man_MANS = $(MAN_DOC) 12 | endif 13 | 14 | EXTRA_DIST = asciidoc.conf $(MAN_TXT) 15 | 16 | MAINTAINERCLEANFILES = $(MAN_DOC) 17 | 18 | dist-hook : $(MAN_DOC) 19 | 20 | if BUILD_DOC 21 | SUFFIXES=.txt .xml .1 .3 .7 22 | 23 | .txt.xml: 24 | asciidoc -d manpage -b docbook -f $(srcdir)/asciidoc.conf \ 25 | -azpipes_version=@PACKAGE_VERSION@ -o$@ $< 26 | .xml.1: 27 | xmlto man $< 28 | .xml.3: 29 | xmlto man $< 30 | .xml.7: 31 | xmlto man $< 32 | endif 33 | 34 | -------------------------------------------------------------------------------- /doc/asciidoc.conf: -------------------------------------------------------------------------------- 1 | [paradef-default] 2 | literal-style=template="literalparagraph" 3 | 4 | [macros] 5 | (?su)[\\]?(?Plinkzpipes):(?P\S*?)\[(?P.*?)\]= 6 | 7 | ifdef::backend-docbook[] 8 | [linkzpipes-inlinemacro] 9 | {0%{target}} 10 | {0#} 11 | {0#{target}{0}} 12 | {0#} 13 | endif::backend-docbook[] 14 | 15 | ifdef::backend-xhtml11[] 16 | [linkzpipes-inlinemacro] 17 | {target}{0?({0})} 18 | endif::backend-xhtml11[] 19 | 20 | ifdef::doctype-manpage[] 21 | ifdef::backend-docbook[] 22 | [header] 23 | template::[header-declarations] 24 | 25 | 26 | {mantitle} 27 | {manvolnum} 28 | zpipes 29 | {zpipes_version} 30 | zpipes Manual 31 | 32 | 33 | {manname} 34 | {manpurpose} 35 | 36 | [footer] 37 | 38 | AUTHORS 39 | The zpipes manual was written by Pieter Hintjens<ph@imatix.com>. 40 | 41 | 42 | RESOURCES 43 | Main web site: http://zyre.org 44 | Report bugs to the 0MQ development mailing list: <zeromq-dev@lists.zeromq.org> 45 | 46 | 47 | COPYRIGHT 48 | Copyright the Contributors. License TBD 49 | 50 | 51 | endif::backend-docbook[] 52 | endif::doctype-manpage[] 53 | 54 | [replacements] 55 | ifdef::backend-xhtml11[] 56 | 0MQ=ØMQ 57 | endif::backend-xhtml11[] 58 | -------------------------------------------------------------------------------- /doc/mkman: -------------------------------------------------------------------------------- 1 | #! /usr/bin/perl 2 | # 3 | # mkman - Generates man pages from C source and header files. 4 | # 5 | # Syntax: 'mkman classname', in doc subdirectory. 6 | # 7 | # Copyright (c) 1996-2013 iMatix Corporation 8 | # 9 | # This is free software; you can redistribute it and/or modify it under the 10 | # terms of the GNU General Public License as published by the Free Software 11 | # Foundation; either version 3 of the License, or (at your option) any later 12 | # version. 13 | # 14 | # This software is distributed in the hope that it will be useful, but 15 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABIL- 16 | # ITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 17 | # License for more details. 18 | # 19 | # You should have received a copy of the GNU General Public License along 20 | # with this program. If not, see . 21 | # 22 | use File::Basename; 23 | 24 | $class = $ARGV [0]; 25 | $class = $1 if $class =~ /(\w+)\.\w+/; 26 | $top_srcdir = ".."; 27 | 28 | # Look for class title in 2nd line of source 29 | # If there's no class file, leave hand-written man page alone 30 | exit unless open (SOURCE, "$top_srcdir/src/$class.c"); 31 | $_ = ; 32 | $_ = ; 33 | $title = "no title found"; 34 | $title = $1 if (/ \w+ - (.*)/); 35 | close (SOURCE); 36 | 37 | # Open output file 38 | die "Can't create $class.txt: $!" 39 | unless open (OUTPUT, ">$class.txt"); 40 | 41 | printf "Generating $class.txt...\n"; 42 | $underline = "=" x (length ($class) + 3); 43 | 44 | $template = <<"END"; 45 | $class(3) 46 | $underline 47 | 48 | NAME 49 | ---- 50 | $class - $title 51 | 52 | SYNOPSIS 53 | -------- 54 | ---- 55 | pull $top_srcdir/include/$class.h\@interface 56 | ---- 57 | 58 | DESCRIPTION 59 | ----------- 60 | 61 | pull $top_srcdir/src/$class.c\@header,left 62 | 63 | pull $top_srcdir/src/$class.c\@discuss,left 64 | 65 | EXAMPLE 66 | ------- 67 | .From $class\_test method 68 | ---- 69 | pull $top_srcdir/src/$class.c\@selftest 70 | ---- 71 | 72 | SEE ALSO 73 | -------- 74 | linkzpipes:zpipes[7] 75 | END 76 | 77 | # Now process template 78 | for (split /^/, $template) { 79 | if (/^pull (.*)(@[a-zA-Z0-9]+)(,(.*)\s*)?/) { 80 | $source = $1; 81 | $tag = $2; 82 | $opts = $4; 83 | die "Can't read $source: $!" 84 | unless open (SOURCE, $source); 85 | while () { 86 | if (/$tag/) { 87 | while () { 88 | last if /@[a-zA-Z0-9]+/; 89 | $_ = " $_" if ($opts eq "code"); 90 | s/^ // if ($opts eq "left"); 91 | print OUTPUT $_; 92 | } 93 | } 94 | } 95 | close (SOURCE); 96 | } 97 | else { 98 | print OUTPUT $_; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /doc/zpipes.1: -------------------------------------------------------------------------------- 1 | '\" t 2 | .\" Title: zpipes 3 | .\" Author: [see the "AUTHORS" section] 4 | .\" Generator: DocBook XSL Stylesheets v1.76.1 5 | .\" Date: 01/22/2014 6 | .\" Manual: zpipes Manual 7 | .\" Source: zpipes 0.0.2 8 | .\" Language: English 9 | .\" 10 | .TH "ZPIPES" "1" "01/22/2014" "zpipes 0\&.0\&.2" "zpipes Manual" 11 | .\" ----------------------------------------------------------------- 12 | .\" * Define some portability stuff 13 | .\" ----------------------------------------------------------------- 14 | .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 15 | .\" http://bugs.debian.org/507673 16 | .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html 17 | .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 18 | .ie \n(.g .ds Aq \(aq 19 | .el .ds Aq ' 20 | .\" ----------------------------------------------------------------- 21 | .\" * set default formatting 22 | .\" ----------------------------------------------------------------- 23 | .\" disable hyphenation 24 | .nh 25 | .\" disable justification (adjust text to left margin only) 26 | .ad l 27 | .\" ----------------------------------------------------------------- 28 | .\" * MAIN CONTENT STARTS HERE * 29 | .\" ----------------------------------------------------------------- 30 | .SH "NAME" 31 | zpipes \- reliable, distributed named pipes 32 | .SH "SYNOPSIS" 33 | .sp 34 | .nf 35 | zpipes [name] 36 | .fi 37 | .SH "DESCRIPTION" 38 | .SS "Overview" 39 | .sp 40 | The zpipes broker provides a reliable named pipes service\&. A pipe is a one\-directional stream of data "chunks" between applications\&. 41 | .sp 42 | .RS 4 43 | .ie n \{\ 44 | \h'-04'\(bu\h'+03'\c 45 | .\} 46 | .el \{\ 47 | .sp -1 48 | .IP \(bu 2.3 49 | .\} 50 | Currently, all applications must be on the same machine instance\&. 51 | .RE 52 | .sp 53 | .RS 4 54 | .ie n \{\ 55 | \h'-04'\(bu\h'+03'\c 56 | .\} 57 | .el \{\ 58 | .sp -1 59 | .IP \(bu 2.3 60 | .\} 61 | Currently, a pipe accepts multiple writers, and a single reader\&. 62 | .RE 63 | .sp 64 | .RS 4 65 | .ie n \{\ 66 | \h'-04'\(bu\h'+03'\c 67 | .\} 68 | .el \{\ 69 | .sp -1 70 | .IP \(bu 2.3 71 | .\} 72 | Pipes are named using any convention that suits the application\&. 73 | .RE 74 | .sp 75 | .RS 4 76 | .ie n \{\ 77 | \h'-04'\(bu\h'+03'\c 78 | .\} 79 | .el \{\ 80 | .sp -1 81 | .IP \(bu 2.3 82 | .\} 83 | The application is responsible for properly closing pipes, thus releasing resources\&. 84 | .RE 85 | .SS "Command Line Syntax" 86 | .sp 87 | When run without arguments, the zpipes broker uses the name "default"\&. You may run at most one broker with the same name, on a single machine instance\&. If you wish to use multiple brokers, e\&.g\&. for testing, you must use a different name for each\&. 88 | .sp 89 | To end a zpipes broker, send a TERM or INT signal (Ctrl\-C)\&. 90 | .SS "IPC Command Interface" 91 | .sp 92 | The zpipes broker accepts ZeroMQ ipc:// connections on the "ipc://@/zpipes/local" endpoint, which is an abstract IPC endpoint\&. The sole interface between applications and the broker is across such IPC connections\&. The command interface has these commands, consisting of multiframe data: 93 | .sp 94 | .RS 4 95 | .ie n \{\ 96 | \h'-04'\(bu\h'+03'\c 97 | .\} 98 | .el \{\ 99 | .sp -1 100 | .IP \(bu 2.3 101 | .\} 102 | "OPEN" / pipename \(em opens a named pipe, for reading or writing\&. 103 | .RE 104 | .sp 105 | .RS 4 106 | .ie n \{\ 107 | \h'-04'\(bu\h'+03'\c 108 | .\} 109 | .el \{\ 110 | .sp -1 111 | .IP \(bu 2.3 112 | .\} 113 | "CLOSE" / pipename \(em closes a named pipe\&. 114 | .RE 115 | .sp 116 | .RS 4 117 | .ie n \{\ 118 | \h'-04'\(bu\h'+03'\c 119 | .\} 120 | .el \{\ 121 | .sp -1 122 | .IP \(bu 2.3 123 | .\} 124 | "READ" / pipename \(em reads next chunk of data from the specified pipe\&. 125 | .RE 126 | .sp 127 | .RS 4 128 | .ie n \{\ 129 | \h'-04'\(bu\h'+03'\c 130 | .\} 131 | .el \{\ 132 | .sp -1 133 | .IP \(bu 2.3 134 | .\} 135 | "WRITE" / pipename / chunk \(em writes a chunk of data to the specified pipe\&. 136 | .RE 137 | .sp 138 | The broker replies to valid OPEN, CLOSE, and WRITE commands with a single frame containing "OK"\&. 139 | .sp 140 | The broker replies to a valid READ command with a single frame containing the chunk of data\&. If there is no data available, the READ command will block until data is available\&. 141 | .sp 142 | The application can pipeline commands, e\&.g\&. sending multiple WRITE commands, before reading the responses\&. 143 | .SS "Reliability" 144 | .sp 145 | The zpipes broker does not store chunks on disk, so if the broker process crashes or is killed, data may be lost\&. However pipes and the chunks they contain will survive the stop/restart of application processes\&. Thus one process may write to a pipe, then exit, and then another process may start up, and read from the pipe\&. 146 | .SS "End of Stream" 147 | .sp 148 | If the application wants to signal the end of the stream it must send a recognizable chunk to indicate that\&. The zpipes model treats pipes as infinite streams\&. 149 | .SS "Multiple Writers" 150 | .sp 151 | Multiple applications can write to the same pipe\&. Chunks will then be fair\-queued from writers, so that heavy writers do not block lighter ones\&. 152 | .SS "Ownership and Contributing" 153 | .sp 154 | To be defined\&. 155 | .SH "AUTHORS" 156 | .sp 157 | The zpipes manual was written by Pieter Hintjens<\m[blue]\fBph@imatix\&.com\fR\m[]\&\s-2\u[1]\d\s+2>\&. 158 | .SH "RESOURCES" 159 | .sp 160 | Main web site: \m[blue]\fBhttp://zyre\&.org\fR\m[] 161 | .sp 162 | Report bugs to the 0MQ development mailing list: <\m[blue]\fBzeromq\-dev@lists\&.zeromq\&.org\fR\m[]\&\s-2\u[2]\d\s+2> 163 | .SH "COPYRIGHT" 164 | .sp 165 | Copyright the Contributors\&. License TBD 166 | .SH "NOTES" 167 | .IP " 1." 4 168 | ph@imatix.com 169 | .RS 4 170 | \%mailto:ph@imatix.com 171 | .RE 172 | .IP " 2." 4 173 | zeromq-dev@lists.zeromq.org 174 | .RS 4 175 | \%mailto:zeromq-dev@lists.zeromq.org 176 | .RE 177 | -------------------------------------------------------------------------------- /doc/zpipes_client.txt: -------------------------------------------------------------------------------- 1 | zpipes_client(3) 2 | ================ 3 | 4 | NAME 5 | ---- 6 | zpipes_client - no title found 7 | 8 | SYNOPSIS 9 | -------- 10 | ---- 11 | // Constructor; open ">pipename" for writing, "pipename" for reading 12 | CZMQ_EXPORT zpipes_client_t * 13 | zpipes_client_new (const char *broker_name, const char *pipe_name); 14 | 15 | // Destructor; closes pipe 16 | CZMQ_EXPORT void 17 | zpipes_client_destroy (zpipes_client_t **self_p); 18 | 19 | // Write chunk of data to pipe; returns number of bytes written, or -1 20 | // in case of error, and then sets zpipes_client_error() to EBADF. 21 | CZMQ_EXPORT ssize_t 22 | zpipes_client_write (zpipes_client_t *self, 23 | void *data, size_t size, int timeout); 24 | 25 | // Read chunk of data from pipe. If timeout is non zero, waits at most 26 | // that many msecs for data. Returns number of bytes read, or zero if the 27 | // pipe was closed by the writer, and no more data is available. On a 28 | // timeout or interrupt, returns -1. To get the actual error code, call 29 | // zpipes_client_error(), which will be EINTR, EAGAIN, or EBADF. 30 | CZMQ_EXPORT ssize_t 31 | zpipes_client_read (zpipes_client_t *self, 32 | void *data, size_t max_size, int timeout); 33 | 34 | // Returns last error number, if any 35 | CZMQ_EXPORT int 36 | zpipes_client_error (zpipes_client_t *self); 37 | 38 | // Self test of this class 39 | CZMQ_EXPORT void 40 | zpipes_client_test (bool verbose); 41 | ---- 42 | 43 | DESCRIPTION 44 | ----------- 45 | 46 | Provides an API to the ZPIPES infrastructure. 47 | 48 | 49 | EXAMPLE 50 | ------- 51 | .From zpipes_client_test method 52 | ---- 53 | zactor_t *server = zactor_new (zpipes_server, NULL); 54 | zstr_sendx (server, "SET", "server/animate", verbose? "1": "0", NULL); 55 | zstr_sendx (server, "BIND", "ipc://@/zpipes/local", NULL); 56 | 57 | zpipes_client_t *reader = zpipes_client_new ("local", "test pipe"); 58 | zpipes_client_t *writer = zpipes_client_new ("local", ">test pipe"); 59 | 60 | byte buffer [100]; 61 | ssize_t bytes; 62 | 63 | // Expect timeout error, EAGAIN 64 | bytes = zpipes_client_read (reader, buffer, 6, 100); 65 | assert (bytes == -1); 66 | assert (zpipes_client_error (reader) == EAGAIN); 67 | 68 | bytes = zpipes_client_write (writer, "CHUNK1", 6, 100); 69 | assert (bytes == 6); 70 | bytes = zpipes_client_write (writer, "CHUNK2", 6, 100); 71 | assert (bytes == 6); 72 | bytes = zpipes_client_write (writer, "CHUNK3", 6, 100); 73 | assert (bytes == 6); 74 | 75 | bytes = zpipes_client_read (reader, buffer, 1, 100); 76 | assert (bytes == 1); 77 | bytes = zpipes_client_read (reader, buffer, 10, 100); 78 | assert (bytes == 10); 79 | 80 | // Now close writer 81 | zpipes_client_destroy (&writer); 82 | 83 | // Expect end of pipe (short read) 84 | bytes = zpipes_client_read (reader, buffer, 50, 100); 85 | assert (bytes == 7); 86 | 87 | // Expect end of pipe (empty chunk) 88 | bytes = zpipes_client_read (reader, buffer, 50, 100); 89 | assert (bytes == 0); 90 | 91 | // Expect illegal action (EBADF) writing on reader 92 | bytes = zpipes_client_write (reader, "CHUNK1", 6, 100); 93 | assert (bytes == -1); 94 | assert (zpipes_client_error (reader) == EBADF); 95 | 96 | zpipes_client_destroy (&reader); 97 | zpipes_client_destroy (&writer); 98 | zactor_destroy (&server); 99 | 100 | ---- 101 | 102 | SEE ALSO 103 | -------- 104 | linkzpipes:zpipes[7] 105 | -------------------------------------------------------------------------------- /doc/zpipes_msg.txt: -------------------------------------------------------------------------------- 1 | zpipes_msg(3) 2 | ============= 3 | 4 | NAME 5 | ---- 6 | zpipes_msg - ZPIPES protocol 7 | 8 | SYNOPSIS 9 | -------- 10 | ---- 11 | // Create a new zpipes_msg 12 | CZMQ_EXPORT zpipes_msg_t * 13 | zpipes_msg_new (int id); 14 | 15 | // Destroy the zpipes_msg 16 | CZMQ_EXPORT void 17 | zpipes_msg_destroy (zpipes_msg_t **self_p); 18 | 19 | // Parse a zpipes_msg from zmsg_t. Returns a new object, or NULL if 20 | // the message could not be parsed, or was NULL. If the socket type is 21 | // ZMQ_ROUTER, then parses the first frame as a routing_id. Destroys msg 22 | // and nullifies the msg refernce. 23 | CZMQ_EXPORT zpipes_msg_t * 24 | zpipes_msg_decode (zmsg_t **msg_p); 25 | 26 | // Encode zpipes_msg into zmsg and destroy it. Returns a newly created 27 | // object or NULL if error. Use when not in control of sending the message. 28 | // If the socket_type is ZMQ_ROUTER, then stores the routing_id as the 29 | // first frame of the resulting message. 30 | CZMQ_EXPORT zmsg_t * 31 | zpipes_msg_encode (zpipes_msg_t **self_p); 32 | 33 | // Receive and parse a zpipes_msg from the socket. Returns new object, 34 | // or NULL if error. Will block if there's no message waiting. 35 | CZMQ_EXPORT zpipes_msg_t * 36 | zpipes_msg_recv (void *input); 37 | 38 | // Receive and parse a zpipes_msg from the socket. Returns new object, 39 | // or NULL either if there was no input waiting, or the recv was interrupted. 40 | CZMQ_EXPORT zpipes_msg_t * 41 | zpipes_msg_recv_nowait (void *input); 42 | 43 | // Send the zpipes_msg to the output, and destroy it 44 | CZMQ_EXPORT int 45 | zpipes_msg_send (zpipes_msg_t **self_p, void *output); 46 | 47 | // Send the zpipes_msg to the output, and do not destroy it 48 | CZMQ_EXPORT int 49 | zpipes_msg_send_again (zpipes_msg_t *self, void *output); 50 | 51 | // Encode the INPUT 52 | CZMQ_EXPORT zmsg_t * 53 | zpipes_msg_encode_input ( 54 | const char *pipename); 55 | 56 | // Encode the INPUT_OK 57 | CZMQ_EXPORT zmsg_t * 58 | zpipes_msg_encode_input_ok ( 59 | ); 60 | 61 | // Encode the INPUT_FAILED 62 | CZMQ_EXPORT zmsg_t * 63 | zpipes_msg_encode_input_failed ( 64 | const char *reason); 65 | 66 | // Encode the OUTPUT 67 | CZMQ_EXPORT zmsg_t * 68 | zpipes_msg_encode_output ( 69 | const char *pipename); 70 | 71 | // Encode the OUTPUT_OK 72 | CZMQ_EXPORT zmsg_t * 73 | zpipes_msg_encode_output_ok ( 74 | ); 75 | 76 | // Encode the OUTPUT_FAILED 77 | CZMQ_EXPORT zmsg_t * 78 | zpipes_msg_encode_output_failed ( 79 | const char *reason); 80 | 81 | // Encode the READ 82 | CZMQ_EXPORT zmsg_t * 83 | zpipes_msg_encode_read ( 84 | uint32_t size, 85 | uint32_t timeout); 86 | 87 | // Encode the READ_OK 88 | CZMQ_EXPORT zmsg_t * 89 | zpipes_msg_encode_read_ok ( 90 | zchunk_t *chunk); 91 | 92 | // Encode the READ_END 93 | CZMQ_EXPORT zmsg_t * 94 | zpipes_msg_encode_read_end ( 95 | ); 96 | 97 | // Encode the READ_TIMEOUT 98 | CZMQ_EXPORT zmsg_t * 99 | zpipes_msg_encode_read_timeout ( 100 | ); 101 | 102 | // Encode the READ_FAILED 103 | CZMQ_EXPORT zmsg_t * 104 | zpipes_msg_encode_read_failed ( 105 | const char *reason); 106 | 107 | // Encode the WRITE 108 | CZMQ_EXPORT zmsg_t * 109 | zpipes_msg_encode_write ( 110 | zchunk_t *chunk, 111 | uint32_t timeout); 112 | 113 | // Encode the WRITE_OK 114 | CZMQ_EXPORT zmsg_t * 115 | zpipes_msg_encode_write_ok ( 116 | ); 117 | 118 | // Encode the WRITE_TIMEOUT 119 | CZMQ_EXPORT zmsg_t * 120 | zpipes_msg_encode_write_timeout ( 121 | ); 122 | 123 | // Encode the WRITE_FAILED 124 | CZMQ_EXPORT zmsg_t * 125 | zpipes_msg_encode_write_failed ( 126 | const char *reason); 127 | 128 | // Encode the CLOSE 129 | CZMQ_EXPORT zmsg_t * 130 | zpipes_msg_encode_close ( 131 | ); 132 | 133 | // Encode the CLOSE_OK 134 | CZMQ_EXPORT zmsg_t * 135 | zpipes_msg_encode_close_ok ( 136 | ); 137 | 138 | // Encode the CLOSE_FAILED 139 | CZMQ_EXPORT zmsg_t * 140 | zpipes_msg_encode_close_failed ( 141 | const char *reason); 142 | 143 | // Encode the PING 144 | CZMQ_EXPORT zmsg_t * 145 | zpipes_msg_encode_ping ( 146 | ); 147 | 148 | // Encode the PING_OK 149 | CZMQ_EXPORT zmsg_t * 150 | zpipes_msg_encode_ping_ok ( 151 | ); 152 | 153 | // Encode the INVALID 154 | CZMQ_EXPORT zmsg_t * 155 | zpipes_msg_encode_invalid ( 156 | ); 157 | 158 | 159 | // Send the INPUT to the output in one step 160 | // WARNING, this call will fail if output is of type ZMQ_ROUTER. 161 | CZMQ_EXPORT int 162 | zpipes_msg_send_input (void *output, 163 | const char *pipename); 164 | 165 | // Send the INPUT_OK to the output in one step 166 | // WARNING, this call will fail if output is of type ZMQ_ROUTER. 167 | CZMQ_EXPORT int 168 | zpipes_msg_send_input_ok (void *output); 169 | 170 | // Send the INPUT_FAILED to the output in one step 171 | // WARNING, this call will fail if output is of type ZMQ_ROUTER. 172 | CZMQ_EXPORT int 173 | zpipes_msg_send_input_failed (void *output, 174 | const char *reason); 175 | 176 | // Send the OUTPUT to the output in one step 177 | // WARNING, this call will fail if output is of type ZMQ_ROUTER. 178 | CZMQ_EXPORT int 179 | zpipes_msg_send_output (void *output, 180 | const char *pipename); 181 | 182 | // Send the OUTPUT_OK to the output in one step 183 | // WARNING, this call will fail if output is of type ZMQ_ROUTER. 184 | CZMQ_EXPORT int 185 | zpipes_msg_send_output_ok (void *output); 186 | 187 | // Send the OUTPUT_FAILED to the output in one step 188 | // WARNING, this call will fail if output is of type ZMQ_ROUTER. 189 | CZMQ_EXPORT int 190 | zpipes_msg_send_output_failed (void *output, 191 | const char *reason); 192 | 193 | // Send the READ to the output in one step 194 | // WARNING, this call will fail if output is of type ZMQ_ROUTER. 195 | CZMQ_EXPORT int 196 | zpipes_msg_send_read (void *output, 197 | uint32_t size, 198 | uint32_t timeout); 199 | 200 | // Send the READ_OK to the output in one step 201 | // WARNING, this call will fail if output is of type ZMQ_ROUTER. 202 | CZMQ_EXPORT int 203 | zpipes_msg_send_read_ok (void *output, 204 | zchunk_t *chunk); 205 | 206 | // Send the READ_END to the output in one step 207 | // WARNING, this call will fail if output is of type ZMQ_ROUTER. 208 | CZMQ_EXPORT int 209 | zpipes_msg_send_read_end (void *output); 210 | 211 | // Send the READ_TIMEOUT to the output in one step 212 | // WARNING, this call will fail if output is of type ZMQ_ROUTER. 213 | CZMQ_EXPORT int 214 | zpipes_msg_send_read_timeout (void *output); 215 | 216 | // Send the READ_FAILED to the output in one step 217 | // WARNING, this call will fail if output is of type ZMQ_ROUTER. 218 | CZMQ_EXPORT int 219 | zpipes_msg_send_read_failed (void *output, 220 | const char *reason); 221 | 222 | // Send the WRITE to the output in one step 223 | // WARNING, this call will fail if output is of type ZMQ_ROUTER. 224 | CZMQ_EXPORT int 225 | zpipes_msg_send_write (void *output, 226 | zchunk_t *chunk, 227 | uint32_t timeout); 228 | 229 | // Send the WRITE_OK to the output in one step 230 | // WARNING, this call will fail if output is of type ZMQ_ROUTER. 231 | CZMQ_EXPORT int 232 | zpipes_msg_send_write_ok (void *output); 233 | 234 | // Send the WRITE_TIMEOUT to the output in one step 235 | // WARNING, this call will fail if output is of type ZMQ_ROUTER. 236 | CZMQ_EXPORT int 237 | zpipes_msg_send_write_timeout (void *output); 238 | 239 | // Send the WRITE_FAILED to the output in one step 240 | // WARNING, this call will fail if output is of type ZMQ_ROUTER. 241 | CZMQ_EXPORT int 242 | zpipes_msg_send_write_failed (void *output, 243 | const char *reason); 244 | 245 | // Send the CLOSE to the output in one step 246 | // WARNING, this call will fail if output is of type ZMQ_ROUTER. 247 | CZMQ_EXPORT int 248 | zpipes_msg_send_close (void *output); 249 | 250 | // Send the CLOSE_OK to the output in one step 251 | // WARNING, this call will fail if output is of type ZMQ_ROUTER. 252 | CZMQ_EXPORT int 253 | zpipes_msg_send_close_ok (void *output); 254 | 255 | // Send the CLOSE_FAILED to the output in one step 256 | // WARNING, this call will fail if output is of type ZMQ_ROUTER. 257 | CZMQ_EXPORT int 258 | zpipes_msg_send_close_failed (void *output, 259 | const char *reason); 260 | 261 | // Send the PING to the output in one step 262 | // WARNING, this call will fail if output is of type ZMQ_ROUTER. 263 | CZMQ_EXPORT int 264 | zpipes_msg_send_ping (void *output); 265 | 266 | // Send the PING_OK to the output in one step 267 | // WARNING, this call will fail if output is of type ZMQ_ROUTER. 268 | CZMQ_EXPORT int 269 | zpipes_msg_send_ping_ok (void *output); 270 | 271 | // Send the INVALID to the output in one step 272 | // WARNING, this call will fail if output is of type ZMQ_ROUTER. 273 | CZMQ_EXPORT int 274 | zpipes_msg_send_invalid (void *output); 275 | 276 | // Duplicate the zpipes_msg message 277 | CZMQ_EXPORT zpipes_msg_t * 278 | zpipes_msg_dup (zpipes_msg_t *self); 279 | 280 | // Print contents of message to stdout 281 | CZMQ_EXPORT void 282 | zpipes_msg_print (zpipes_msg_t *self); 283 | 284 | // Get/set the message routing id 285 | CZMQ_EXPORT zframe_t * 286 | zpipes_msg_routing_id (zpipes_msg_t *self); 287 | CZMQ_EXPORT void 288 | zpipes_msg_set_routing_id (zpipes_msg_t *self, zframe_t *routing_id); 289 | 290 | // Get the zpipes_msg id and printable command 291 | CZMQ_EXPORT int 292 | zpipes_msg_id (zpipes_msg_t *self); 293 | CZMQ_EXPORT void 294 | zpipes_msg_set_id (zpipes_msg_t *self, int id); 295 | CZMQ_EXPORT const char * 296 | zpipes_msg_command (zpipes_msg_t *self); 297 | 298 | // Get/set the pipename field 299 | CZMQ_EXPORT const char * 300 | zpipes_msg_pipename (zpipes_msg_t *self); 301 | CZMQ_EXPORT void 302 | zpipes_msg_set_pipename (zpipes_msg_t *self, const char *format, ...); 303 | 304 | // Get/set the reason field 305 | CZMQ_EXPORT const char * 306 | zpipes_msg_reason (zpipes_msg_t *self); 307 | CZMQ_EXPORT void 308 | zpipes_msg_set_reason (zpipes_msg_t *self, const char *format, ...); 309 | 310 | // Get/set the size field 311 | CZMQ_EXPORT uint32_t 312 | zpipes_msg_size (zpipes_msg_t *self); 313 | CZMQ_EXPORT void 314 | zpipes_msg_set_size (zpipes_msg_t *self, uint32_t size); 315 | 316 | // Get/set the timeout field 317 | CZMQ_EXPORT uint32_t 318 | zpipes_msg_timeout (zpipes_msg_t *self); 319 | CZMQ_EXPORT void 320 | zpipes_msg_set_timeout (zpipes_msg_t *self, uint32_t timeout); 321 | 322 | // Get a copy of the chunk field 323 | CZMQ_EXPORT zchunk_t * 324 | zpipes_msg_chunk (zpipes_msg_t *self); 325 | // Get the chunk field and transfer ownership to caller 326 | CZMQ_EXPORT zchunk_t * 327 | zpipes_msg_get_chunk (zpipes_msg_t *self); 328 | // Set the chunk field, transferring ownership from caller 329 | CZMQ_EXPORT void 330 | zpipes_msg_set_chunk (zpipes_msg_t *self, zchunk_t **chunk_p); 331 | 332 | // Self test of this class 333 | CZMQ_EXPORT int 334 | zpipes_msg_test (bool verbose); 335 | ---- 336 | 337 | DESCRIPTION 338 | ----------- 339 | 340 | zpipes_msg - ZPIPES protocol 341 | 342 | 343 | EXAMPLE 344 | ------- 345 | .From zpipes_msg_test method 346 | ---- 347 | // Simple create/destroy test 348 | zpipes_msg_t *self = zpipes_msg_new (0); 349 | assert (self); 350 | zpipes_msg_destroy (&self); 351 | 352 | // Create pair of sockets we can send through 353 | zsock_t *input = zsock_new (ZMQ_ROUTER); 354 | assert (input); 355 | zsock_connect (input, "inproc://selftest-zpipes_msg"); 356 | 357 | zsock_t *output = zsock_new (ZMQ_DEALER); 358 | assert (output); 359 | zsock_bind (output, "inproc://selftest-zpipes_msg"); 360 | 361 | // Encode/send/decode and verify each message type 362 | int instance; 363 | zpipes_msg_t *copy; 364 | self = zpipes_msg_new (ZPIPES_MSG_INPUT); 365 | 366 | // Check that _dup works on empty message 367 | copy = zpipes_msg_dup (self); 368 | assert (copy); 369 | zpipes_msg_destroy (©); 370 | 371 | zpipes_msg_set_pipename (self, "Life is short but Now lasts for ever"); 372 | // Send twice from same object 373 | zpipes_msg_send_again (self, output); 374 | zpipes_msg_send (&self, output); 375 | 376 | for (instance = 0; instance < 2; instance++) { 377 | self = zpipes_msg_recv (input); 378 | assert (self); 379 | assert (zpipes_msg_routing_id (self)); 380 | 381 | assert (streq (zpipes_msg_pipename (self), "Life is short but Now lasts for ever")); 382 | zpipes_msg_destroy (&self); 383 | } 384 | self = zpipes_msg_new (ZPIPES_MSG_INPUT_OK); 385 | 386 | // Check that _dup works on empty message 387 | copy = zpipes_msg_dup (self); 388 | assert (copy); 389 | zpipes_msg_destroy (©); 390 | 391 | // Send twice from same object 392 | zpipes_msg_send_again (self, output); 393 | zpipes_msg_send (&self, output); 394 | 395 | for (instance = 0; instance < 2; instance++) { 396 | self = zpipes_msg_recv (input); 397 | assert (self); 398 | assert (zpipes_msg_routing_id (self)); 399 | 400 | zpipes_msg_destroy (&self); 401 | } 402 | self = zpipes_msg_new (ZPIPES_MSG_INPUT_FAILED); 403 | 404 | // Check that _dup works on empty message 405 | copy = zpipes_msg_dup (self); 406 | assert (copy); 407 | zpipes_msg_destroy (©); 408 | 409 | zpipes_msg_set_reason (self, "Life is short but Now lasts for ever"); 410 | // Send twice from same object 411 | zpipes_msg_send_again (self, output); 412 | zpipes_msg_send (&self, output); 413 | 414 | for (instance = 0; instance < 2; instance++) { 415 | self = zpipes_msg_recv (input); 416 | assert (self); 417 | assert (zpipes_msg_routing_id (self)); 418 | 419 | assert (streq (zpipes_msg_reason (self), "Life is short but Now lasts for ever")); 420 | zpipes_msg_destroy (&self); 421 | } 422 | self = zpipes_msg_new (ZPIPES_MSG_OUTPUT); 423 | 424 | // Check that _dup works on empty message 425 | copy = zpipes_msg_dup (self); 426 | assert (copy); 427 | zpipes_msg_destroy (©); 428 | 429 | zpipes_msg_set_pipename (self, "Life is short but Now lasts for ever"); 430 | // Send twice from same object 431 | zpipes_msg_send_again (self, output); 432 | zpipes_msg_send (&self, output); 433 | 434 | for (instance = 0; instance < 2; instance++) { 435 | self = zpipes_msg_recv (input); 436 | assert (self); 437 | assert (zpipes_msg_routing_id (self)); 438 | 439 | assert (streq (zpipes_msg_pipename (self), "Life is short but Now lasts for ever")); 440 | zpipes_msg_destroy (&self); 441 | } 442 | self = zpipes_msg_new (ZPIPES_MSG_OUTPUT_OK); 443 | 444 | // Check that _dup works on empty message 445 | copy = zpipes_msg_dup (self); 446 | assert (copy); 447 | zpipes_msg_destroy (©); 448 | 449 | // Send twice from same object 450 | zpipes_msg_send_again (self, output); 451 | zpipes_msg_send (&self, output); 452 | 453 | for (instance = 0; instance < 2; instance++) { 454 | self = zpipes_msg_recv (input); 455 | assert (self); 456 | assert (zpipes_msg_routing_id (self)); 457 | 458 | zpipes_msg_destroy (&self); 459 | } 460 | self = zpipes_msg_new (ZPIPES_MSG_OUTPUT_FAILED); 461 | 462 | // Check that _dup works on empty message 463 | copy = zpipes_msg_dup (self); 464 | assert (copy); 465 | zpipes_msg_destroy (©); 466 | 467 | zpipes_msg_set_reason (self, "Life is short but Now lasts for ever"); 468 | // Send twice from same object 469 | zpipes_msg_send_again (self, output); 470 | zpipes_msg_send (&self, output); 471 | 472 | for (instance = 0; instance < 2; instance++) { 473 | self = zpipes_msg_recv (input); 474 | assert (self); 475 | assert (zpipes_msg_routing_id (self)); 476 | 477 | assert (streq (zpipes_msg_reason (self), "Life is short but Now lasts for ever")); 478 | zpipes_msg_destroy (&self); 479 | } 480 | self = zpipes_msg_new (ZPIPES_MSG_READ); 481 | 482 | // Check that _dup works on empty message 483 | copy = zpipes_msg_dup (self); 484 | assert (copy); 485 | zpipes_msg_destroy (©); 486 | 487 | zpipes_msg_set_size (self, 123); 488 | zpipes_msg_set_timeout (self, 123); 489 | // Send twice from same object 490 | zpipes_msg_send_again (self, output); 491 | zpipes_msg_send (&self, output); 492 | 493 | for (instance = 0; instance < 2; instance++) { 494 | self = zpipes_msg_recv (input); 495 | assert (self); 496 | assert (zpipes_msg_routing_id (self)); 497 | 498 | assert (zpipes_msg_size (self) == 123); 499 | assert (zpipes_msg_timeout (self) == 123); 500 | zpipes_msg_destroy (&self); 501 | } 502 | self = zpipes_msg_new (ZPIPES_MSG_READ_OK); 503 | 504 | // Check that _dup works on empty message 505 | copy = zpipes_msg_dup (self); 506 | assert (copy); 507 | zpipes_msg_destroy (©); 508 | 509 | zchunk_t *read_ok_chunk = zchunk_new ("Captcha Diem", 12); 510 | zpipes_msg_set_chunk (self, &read_ok_chunk); 511 | // Send twice from same object 512 | zpipes_msg_send_again (self, output); 513 | zpipes_msg_send (&self, output); 514 | 515 | for (instance = 0; instance < 2; instance++) { 516 | self = zpipes_msg_recv (input); 517 | assert (self); 518 | assert (zpipes_msg_routing_id (self)); 519 | 520 | assert (memcmp (zchunk_data (zpipes_msg_chunk (self)), "Captcha Diem", 12) == 0); 521 | zpipes_msg_destroy (&self); 522 | } 523 | self = zpipes_msg_new (ZPIPES_MSG_READ_END); 524 | 525 | // Check that _dup works on empty message 526 | copy = zpipes_msg_dup (self); 527 | assert (copy); 528 | zpipes_msg_destroy (©); 529 | 530 | // Send twice from same object 531 | zpipes_msg_send_again (self, output); 532 | zpipes_msg_send (&self, output); 533 | 534 | for (instance = 0; instance < 2; instance++) { 535 | self = zpipes_msg_recv (input); 536 | assert (self); 537 | assert (zpipes_msg_routing_id (self)); 538 | 539 | zpipes_msg_destroy (&self); 540 | } 541 | self = zpipes_msg_new (ZPIPES_MSG_READ_TIMEOUT); 542 | 543 | // Check that _dup works on empty message 544 | copy = zpipes_msg_dup (self); 545 | assert (copy); 546 | zpipes_msg_destroy (©); 547 | 548 | // Send twice from same object 549 | zpipes_msg_send_again (self, output); 550 | zpipes_msg_send (&self, output); 551 | 552 | for (instance = 0; instance < 2; instance++) { 553 | self = zpipes_msg_recv (input); 554 | assert (self); 555 | assert (zpipes_msg_routing_id (self)); 556 | 557 | zpipes_msg_destroy (&self); 558 | } 559 | self = zpipes_msg_new (ZPIPES_MSG_READ_FAILED); 560 | 561 | // Check that _dup works on empty message 562 | copy = zpipes_msg_dup (self); 563 | assert (copy); 564 | zpipes_msg_destroy (©); 565 | 566 | zpipes_msg_set_reason (self, "Life is short but Now lasts for ever"); 567 | // Send twice from same object 568 | zpipes_msg_send_again (self, output); 569 | zpipes_msg_send (&self, output); 570 | 571 | for (instance = 0; instance < 2; instance++) { 572 | self = zpipes_msg_recv (input); 573 | assert (self); 574 | assert (zpipes_msg_routing_id (self)); 575 | 576 | assert (streq (zpipes_msg_reason (self), "Life is short but Now lasts for ever")); 577 | zpipes_msg_destroy (&self); 578 | } 579 | self = zpipes_msg_new (ZPIPES_MSG_WRITE); 580 | 581 | // Check that _dup works on empty message 582 | copy = zpipes_msg_dup (self); 583 | assert (copy); 584 | zpipes_msg_destroy (©); 585 | 586 | zchunk_t *write_chunk = zchunk_new ("Captcha Diem", 12); 587 | zpipes_msg_set_chunk (self, &write_chunk); 588 | zpipes_msg_set_timeout (self, 123); 589 | // Send twice from same object 590 | zpipes_msg_send_again (self, output); 591 | zpipes_msg_send (&self, output); 592 | 593 | for (instance = 0; instance < 2; instance++) { 594 | self = zpipes_msg_recv (input); 595 | assert (self); 596 | assert (zpipes_msg_routing_id (self)); 597 | 598 | assert (memcmp (zchunk_data (zpipes_msg_chunk (self)), "Captcha Diem", 12) == 0); 599 | assert (zpipes_msg_timeout (self) == 123); 600 | zpipes_msg_destroy (&self); 601 | } 602 | self = zpipes_msg_new (ZPIPES_MSG_WRITE_OK); 603 | 604 | // Check that _dup works on empty message 605 | copy = zpipes_msg_dup (self); 606 | assert (copy); 607 | zpipes_msg_destroy (©); 608 | 609 | // Send twice from same object 610 | zpipes_msg_send_again (self, output); 611 | zpipes_msg_send (&self, output); 612 | 613 | for (instance = 0; instance < 2; instance++) { 614 | self = zpipes_msg_recv (input); 615 | assert (self); 616 | assert (zpipes_msg_routing_id (self)); 617 | 618 | zpipes_msg_destroy (&self); 619 | } 620 | self = zpipes_msg_new (ZPIPES_MSG_WRITE_TIMEOUT); 621 | 622 | // Check that _dup works on empty message 623 | copy = zpipes_msg_dup (self); 624 | assert (copy); 625 | zpipes_msg_destroy (©); 626 | 627 | // Send twice from same object 628 | zpipes_msg_send_again (self, output); 629 | zpipes_msg_send (&self, output); 630 | 631 | for (instance = 0; instance < 2; instance++) { 632 | self = zpipes_msg_recv (input); 633 | assert (self); 634 | assert (zpipes_msg_routing_id (self)); 635 | 636 | zpipes_msg_destroy (&self); 637 | } 638 | self = zpipes_msg_new (ZPIPES_MSG_WRITE_FAILED); 639 | 640 | // Check that _dup works on empty message 641 | copy = zpipes_msg_dup (self); 642 | assert (copy); 643 | zpipes_msg_destroy (©); 644 | 645 | zpipes_msg_set_reason (self, "Life is short but Now lasts for ever"); 646 | // Send twice from same object 647 | zpipes_msg_send_again (self, output); 648 | zpipes_msg_send (&self, output); 649 | 650 | for (instance = 0; instance < 2; instance++) { 651 | self = zpipes_msg_recv (input); 652 | assert (self); 653 | assert (zpipes_msg_routing_id (self)); 654 | 655 | assert (streq (zpipes_msg_reason (self), "Life is short but Now lasts for ever")); 656 | zpipes_msg_destroy (&self); 657 | } 658 | self = zpipes_msg_new (ZPIPES_MSG_CLOSE); 659 | 660 | // Check that _dup works on empty message 661 | copy = zpipes_msg_dup (self); 662 | assert (copy); 663 | zpipes_msg_destroy (©); 664 | 665 | // Send twice from same object 666 | zpipes_msg_send_again (self, output); 667 | zpipes_msg_send (&self, output); 668 | 669 | for (instance = 0; instance < 2; instance++) { 670 | self = zpipes_msg_recv (input); 671 | assert (self); 672 | assert (zpipes_msg_routing_id (self)); 673 | 674 | zpipes_msg_destroy (&self); 675 | } 676 | self = zpipes_msg_new (ZPIPES_MSG_CLOSE_OK); 677 | 678 | // Check that _dup works on empty message 679 | copy = zpipes_msg_dup (self); 680 | assert (copy); 681 | zpipes_msg_destroy (©); 682 | 683 | // Send twice from same object 684 | zpipes_msg_send_again (self, output); 685 | zpipes_msg_send (&self, output); 686 | 687 | for (instance = 0; instance < 2; instance++) { 688 | self = zpipes_msg_recv (input); 689 | assert (self); 690 | assert (zpipes_msg_routing_id (self)); 691 | 692 | zpipes_msg_destroy (&self); 693 | } 694 | self = zpipes_msg_new (ZPIPES_MSG_CLOSE_FAILED); 695 | 696 | // Check that _dup works on empty message 697 | copy = zpipes_msg_dup (self); 698 | assert (copy); 699 | zpipes_msg_destroy (©); 700 | 701 | zpipes_msg_set_reason (self, "Life is short but Now lasts for ever"); 702 | // Send twice from same object 703 | zpipes_msg_send_again (self, output); 704 | zpipes_msg_send (&self, output); 705 | 706 | for (instance = 0; instance < 2; instance++) { 707 | self = zpipes_msg_recv (input); 708 | assert (self); 709 | assert (zpipes_msg_routing_id (self)); 710 | 711 | assert (streq (zpipes_msg_reason (self), "Life is short but Now lasts for ever")); 712 | zpipes_msg_destroy (&self); 713 | } 714 | self = zpipes_msg_new (ZPIPES_MSG_PING); 715 | 716 | // Check that _dup works on empty message 717 | copy = zpipes_msg_dup (self); 718 | assert (copy); 719 | zpipes_msg_destroy (©); 720 | 721 | // Send twice from same object 722 | zpipes_msg_send_again (self, output); 723 | zpipes_msg_send (&self, output); 724 | 725 | for (instance = 0; instance < 2; instance++) { 726 | self = zpipes_msg_recv (input); 727 | assert (self); 728 | assert (zpipes_msg_routing_id (self)); 729 | 730 | zpipes_msg_destroy (&self); 731 | } 732 | self = zpipes_msg_new (ZPIPES_MSG_PING_OK); 733 | 734 | // Check that _dup works on empty message 735 | copy = zpipes_msg_dup (self); 736 | assert (copy); 737 | zpipes_msg_destroy (©); 738 | 739 | // Send twice from same object 740 | zpipes_msg_send_again (self, output); 741 | zpipes_msg_send (&self, output); 742 | 743 | for (instance = 0; instance < 2; instance++) { 744 | self = zpipes_msg_recv (input); 745 | assert (self); 746 | assert (zpipes_msg_routing_id (self)); 747 | 748 | zpipes_msg_destroy (&self); 749 | } 750 | self = zpipes_msg_new (ZPIPES_MSG_INVALID); 751 | 752 | // Check that _dup works on empty message 753 | copy = zpipes_msg_dup (self); 754 | assert (copy); 755 | zpipes_msg_destroy (©); 756 | 757 | // Send twice from same object 758 | zpipes_msg_send_again (self, output); 759 | zpipes_msg_send (&self, output); 760 | 761 | for (instance = 0; instance < 2; instance++) { 762 | self = zpipes_msg_recv (input); 763 | assert (self); 764 | assert (zpipes_msg_routing_id (self)); 765 | 766 | zpipes_msg_destroy (&self); 767 | } 768 | 769 | zsock_destroy (&input); 770 | zsock_destroy (&output); 771 | ---- 772 | 773 | SEE ALSO 774 | -------- 775 | linkzpipes:zpipes[7] 776 | -------------------------------------------------------------------------------- /doc/zpipes_server.txt: -------------------------------------------------------------------------------- 1 | zpipes_server(3) 2 | ================ 3 | 4 | NAME 5 | ---- 6 | zpipes_server - ZPIPES server 7 | 8 | SYNOPSIS 9 | -------- 10 | ---- 11 | // This is zpipes_server, implemented as a CZMQ zactor task 12 | void 13 | zpipes_server (zsock_t *pipe, void *args); 14 | 15 | // Self test of this class 16 | void 17 | zpipes_server_test (bool verbose); 18 | ---- 19 | 20 | DESCRIPTION 21 | ----------- 22 | 23 | Description of class for man page. 24 | 25 | Detailed discussion of the class, if any. 26 | 27 | EXAMPLE 28 | ------- 29 | .From zpipes_server_test method 30 | ---- 31 | // Prepare test cases 32 | zactor_t *server = zactor_new (zpipes_server, NULL); 33 | zstr_sendx (server, "SET", "server/animate", verbose? "1": "0", NULL); 34 | zstr_sendx (server, "BIND", "ipc://@/zpipes/local", NULL); 35 | 36 | zsock_t *writer = zsock_new (ZMQ_DEALER); 37 | assert (writer); 38 | zsock_connect (writer, "ipc://@/zpipes/local"); 39 | 40 | zsock_t *writer2 = zsock_new (ZMQ_DEALER); 41 | assert (writer2); 42 | zsock_connect (writer2, "ipc://@/zpipes/local"); 43 | 44 | zsock_t *reader = zsock_new (ZMQ_DEALER); 45 | assert (reader); 46 | zsock_connect (reader, "ipc://@/zpipes/local"); 47 | 48 | zsock_t *reader2 = zsock_new (ZMQ_DEALER); 49 | assert (reader2); 50 | zsock_connect (reader2, "ipc://@/zpipes/local"); 51 | 52 | zchunk_t *chunk = zchunk_new ("Hello, World", 12); 53 | int32_t timeout = 100; 54 | 55 | // -------------------------------------------------------------------- 56 | // Basic tests 57 | 58 | // Open writer on pipe 59 | zpipes_msg_send_output (writer, "test pipe"); 60 | if (s_expect_reply (writer, ZPIPES_MSG_OUTPUT_OK)) 61 | assert (false); 62 | 63 | // Write will timeout if there's no reader 64 | zpipes_msg_send_write (writer, chunk, timeout); 65 | if (s_expect_reply (writer, ZPIPES_MSG_WRITE_TIMEOUT)) 66 | assert (false); 67 | 68 | // Now open reader on pipe 69 | zpipes_msg_send_input (reader, "test pipe"); 70 | if (s_expect_reply (reader, ZPIPES_MSG_INPUT_OK)) 71 | assert (false); 72 | 73 | // Read will timeout if there's no data 74 | zpipes_msg_send_read (reader, 12, timeout); 75 | if (s_expect_reply (reader, ZPIPES_MSG_READ_TIMEOUT)) 76 | assert (false); 77 | 78 | // Write should now be successful 79 | zpipes_msg_send_write (writer, chunk, 0); 80 | if (s_expect_reply (writer, ZPIPES_MSG_WRITE_OK)) 81 | assert (false); 82 | 83 | // Read should now be successful 84 | zpipes_msg_send_read (reader, 12, 0); 85 | if (s_expect_reply (reader, ZPIPES_MSG_READ_OK)) 86 | assert (false); 87 | 88 | // Zero read request returns "end of pipe" 89 | zpipes_msg_send_read (reader, 0, 0); 90 | if (s_expect_reply (reader, ZPIPES_MSG_READ_END)) 91 | assert (false); 92 | 93 | // Close writer 94 | zpipes_msg_send_close (writer); 95 | if (s_expect_reply (writer, ZPIPES_MSG_CLOSE_OK)) 96 | assert (false); 97 | 98 | // Any read request returns "end of pipe" 99 | zpipes_msg_send_read (reader, 12, timeout); 100 | if (s_expect_reply (reader, ZPIPES_MSG_READ_END)) 101 | assert (false); 102 | 103 | // Close reader 104 | zpipes_msg_send_close (reader); 105 | if (s_expect_reply (reader, ZPIPES_MSG_CLOSE_OK)) 106 | assert (false); 107 | 108 | // -------------------------------------------------------------------- 109 | // Test pipelining (request queuing & filtering) 110 | 111 | // Open reader on pipe 112 | zpipes_msg_send_input (reader, "test pipe"); 113 | if (s_expect_reply (reader, ZPIPES_MSG_INPUT_OK)) 114 | assert (false); 115 | 116 | // Open writer on pipe 117 | zpipes_msg_send_output (writer, "test pipe"); 118 | if (s_expect_reply (writer, ZPIPES_MSG_OUTPUT_OK)) 119 | assert (false); 120 | 121 | // Pipeline three read requests 122 | zpipes_msg_send_read (reader, 12, timeout); 123 | zpipes_msg_send_read (reader, 12, timeout); 124 | zpipes_msg_send_read (reader, 12, timeout); 125 | 126 | // First read will return with a timeout 127 | if (s_expect_reply (reader, ZPIPES_MSG_READ_TIMEOUT)) 128 | assert (false); 129 | 130 | // Write chunk to pipe 131 | zpipes_msg_send_write (writer, chunk, 0); 132 | if (s_expect_reply (writer, ZPIPES_MSG_WRITE_OK)) 133 | assert (false); 134 | 135 | // Second read will succeed 136 | if (s_expect_reply (reader, ZPIPES_MSG_READ_OK)) 137 | assert (false); 138 | 139 | // Send PING, expect PING-OK back 140 | zpipes_msg_send_ping (reader); 141 | if (s_expect_reply (reader, ZPIPES_MSG_PING_OK)) 142 | assert (false); 143 | 144 | // Close writer 145 | zpipes_msg_send_close (writer); 146 | if (s_expect_reply (writer, ZPIPES_MSG_CLOSE_OK)) 147 | assert (false); 148 | 149 | // Third read will report end of pipe 150 | if (s_expect_reply (reader, ZPIPES_MSG_READ_END)) 151 | assert (false); 152 | 153 | // Close reader 154 | zpipes_msg_send_close (reader); 155 | if (s_expect_reply (reader, ZPIPES_MSG_CLOSE_OK)) 156 | assert (false); 157 | 158 | // Read now fails as pipe is closed 159 | zpipes_msg_send_read (reader, 12, timeout); 160 | if (s_expect_reply (reader, ZPIPES_MSG_INVALID)) 161 | assert (false); 162 | 163 | // Closing an already closed pipe is an error 164 | zpipes_msg_send_close (reader); 165 | if (s_expect_reply (reader, ZPIPES_MSG_INVALID)) 166 | assert (false); 167 | 168 | // -------------------------------------------------------------------- 169 | // Test read/close pipelining 170 | 171 | // Open reader on pipe 172 | zpipes_msg_send_input (reader, "test pipe"); 173 | if (s_expect_reply (reader, ZPIPES_MSG_INPUT_OK)) 174 | assert (false); 175 | 176 | // Open writer on pipe 177 | zpipes_msg_send_output (writer, "test pipe"); 178 | if (s_expect_reply (writer, ZPIPES_MSG_OUTPUT_OK)) 179 | assert (false); 180 | 181 | // Pipeline two read requests 182 | zpipes_msg_send_read (reader, 12, timeout); 183 | zpipes_msg_send_read (reader, 12, timeout); 184 | 185 | // Send PING, expect PING-OK back 186 | zpipes_msg_send_ping (reader); 187 | if (s_expect_reply (reader, ZPIPES_MSG_PING_OK)) 188 | assert (false); 189 | 190 | // Close reader 191 | zpipes_msg_send_close (reader); 192 | 193 | // First read now fails 194 | if (s_expect_reply (reader, ZPIPES_MSG_READ_FAILED)) 195 | assert (false); 196 | 197 | if (s_expect_reply (reader, ZPIPES_MSG_CLOSE_OK)) 198 | assert (false); 199 | 200 | // Second read is now invalid 201 | if (s_expect_reply (reader, ZPIPES_MSG_INVALID)) 202 | assert (false); 203 | 204 | // Close writer 205 | zpipes_msg_send_close (writer); 206 | if (s_expect_reply (writer, ZPIPES_MSG_CLOSE_OK)) 207 | assert (false); 208 | 209 | // -------------------------------------------------------------------- 210 | // Test reads and writes of different sizes 211 | 212 | // Open reader on pipe 213 | zpipes_msg_send_input (reader, "test pipe"); 214 | if (s_expect_reply (reader, ZPIPES_MSG_INPUT_OK)) 215 | assert (false); 216 | 217 | // Open writer on pipe 218 | zpipes_msg_send_output (writer, "test pipe"); 219 | if (s_expect_reply (writer, ZPIPES_MSG_OUTPUT_OK)) 220 | assert (false); 221 | 222 | // Write chunk to pipe 223 | zpipes_msg_send_write (writer, chunk, 0); 224 | if (s_expect_reply (writer, ZPIPES_MSG_WRITE_OK)) 225 | assert (false); 226 | 227 | // Close writer 228 | zpipes_msg_send_close (writer); 229 | if (s_expect_reply (writer, ZPIPES_MSG_CLOSE_OK)) 230 | assert (false); 231 | 232 | // Read back in several steps 233 | zpipes_msg_send_read (reader, 1, 0); 234 | if (s_expect_reply (reader, ZPIPES_MSG_READ_OK)) 235 | assert (false); 236 | zpipes_msg_send_read (reader, 2, 0); 237 | if (s_expect_reply (reader, ZPIPES_MSG_READ_OK)) 238 | assert (false); 239 | zpipes_msg_send_read (reader, 3, 0); 240 | if (s_expect_reply (reader, ZPIPES_MSG_READ_OK)) 241 | assert (false); 242 | zpipes_msg_send_read (reader, 3, 0); 243 | if (s_expect_reply (reader, ZPIPES_MSG_READ_OK)) 244 | assert (false); 245 | 246 | // We get a short read (3 bytes) 247 | zpipes_msg_send_read (reader, 100, 0); 248 | if (s_expect_reply (reader, ZPIPES_MSG_READ_OK)) 249 | assert (false); 250 | 251 | // Pipe is now empty 252 | zpipes_msg_send_read (reader, 100, 0); 253 | if (s_expect_reply (reader, ZPIPES_MSG_READ_END)) 254 | assert (false); 255 | 256 | // Close reader 257 | zpipes_msg_send_close (reader); 258 | if (s_expect_reply (reader, ZPIPES_MSG_CLOSE_OK)) 259 | assert (false); 260 | 261 | // -------------------------------------------------------------------- 262 | // Test connection expiry 263 | 264 | // Set connection timeout to 200 msecs 265 | zstr_sendx (server, "SET", "server/timeout", "200", NULL); 266 | 267 | // Open reader on pipe 268 | zpipes_msg_send_input (reader, "test pipe"); 269 | if (s_expect_reply (reader, ZPIPES_MSG_INPUT_OK)) 270 | assert (false); 271 | 272 | // Read will expire, we don't expect any response for this command 273 | zpipes_msg_send_read (reader, 12, 0); 274 | 275 | // Do nothing for long enough for the timeout to hit 276 | zclock_sleep (300); 277 | 278 | // Try again, server should now treat the client as disconnected 279 | zpipes_msg_send_read (reader, 12, 0); 280 | if (s_expect_reply (reader, ZPIPES_MSG_INVALID)) 281 | assert (false); 282 | 283 | // Now check that disconnection erases pipe contents 284 | 285 | // Open reader on pipe 286 | zpipes_msg_send_input (reader, "test pipe"); 287 | if (s_expect_reply (reader, ZPIPES_MSG_INPUT_OK)) 288 | assert (false); 289 | 290 | // Open writer on pipe 291 | zpipes_msg_send_output (writer, "test pipe"); 292 | if (s_expect_reply (writer, ZPIPES_MSG_OUTPUT_OK)) 293 | assert (false); 294 | 295 | // Write chunk to pipe 296 | zpipes_msg_send_write (writer, chunk, 0); 297 | if (s_expect_reply (writer, ZPIPES_MSG_WRITE_OK)) 298 | assert (false); 299 | 300 | // Do nothing for long enough for the timeout to hit 301 | // Both writer and reader should be disconnected 302 | zclock_sleep (300); 303 | 304 | // Open reader on pipe 305 | zpipes_msg_send_input (reader, "test pipe"); 306 | if (s_expect_reply (reader, ZPIPES_MSG_INPUT_OK)) 307 | assert (false); 308 | 309 | // Open writer on pipe 310 | zpipes_msg_send_output (writer, "test pipe"); 311 | if (s_expect_reply (writer, ZPIPES_MSG_OUTPUT_OK)) 312 | assert (false); 313 | 314 | // This read should timeout, as pipe is empty 315 | zpipes_msg_send_read (reader, 12, timeout); 316 | if (s_expect_reply (reader, ZPIPES_MSG_READ_TIMEOUT)) 317 | assert (false); 318 | 319 | // Close writer 320 | zpipes_msg_send_close (writer); 321 | if (s_expect_reply (writer, ZPIPES_MSG_CLOSE_OK)) 322 | assert (false); 323 | 324 | // Close reader 325 | zpipes_msg_send_close (reader); 326 | if (s_expect_reply (reader, ZPIPES_MSG_CLOSE_OK)) 327 | assert (false); 328 | 329 | // -------------------------------------------------------------------- 330 | // Test writer closing while reader still active 331 | 332 | // Open writer on pipe 333 | zpipes_msg_send_output (writer, "test pipe"); 334 | if (s_expect_reply (writer, ZPIPES_MSG_OUTPUT_OK)) 335 | assert (false); 336 | 337 | // Open reader on pipe 338 | zpipes_msg_send_input (reader, "test pipe"); 339 | if (s_expect_reply (reader, ZPIPES_MSG_INPUT_OK)) 340 | assert (false); 341 | 342 | // Write one chunk to pipe 343 | zpipes_msg_send_write (writer, chunk, 0); 344 | if (s_expect_reply (writer, ZPIPES_MSG_WRITE_OK)) 345 | assert (false); 346 | 347 | // Close writer, before reader has read data 348 | zpipes_msg_send_close (writer); 349 | if (s_expect_reply (writer, ZPIPES_MSG_CLOSE_OK)) 350 | assert (false); 351 | 352 | // Open writer on same pipe name 353 | zpipes_msg_send_output (writer, "test pipe"); 354 | if (s_expect_reply (writer, ZPIPES_MSG_OUTPUT_OK)) 355 | assert (false); 356 | 357 | // Read should still be successful 358 | zpipes_msg_send_read (reader, 12, 0); 359 | if (s_expect_reply (reader, ZPIPES_MSG_READ_OK)) 360 | assert (false); 361 | 362 | // Create second reader and open pipe for input 363 | zpipes_msg_send_input (reader2, "test pipe"); 364 | if (s_expect_reply (reader2, ZPIPES_MSG_INPUT_OK)) 365 | assert (false); 366 | 367 | // Write one chunk to pipe, will go to second instance 368 | zpipes_msg_send_write (writer, chunk, 0); 369 | if (s_expect_reply (writer, ZPIPES_MSG_WRITE_OK)) 370 | assert (false); 371 | 372 | // Pipe is terminated and empty 373 | zpipes_msg_send_read (reader, 0, 0); 374 | if (s_expect_reply (reader, ZPIPES_MSG_READ_END)) 375 | assert (false); 376 | 377 | // Reader2 should be successful 378 | zpipes_msg_send_read (reader2, 12, 0); 379 | if (s_expect_reply (reader2, ZPIPES_MSG_READ_OK)) 380 | assert (false); 381 | 382 | // Close reader 383 | zpipes_msg_send_close (reader); 384 | if (s_expect_reply (reader, ZPIPES_MSG_CLOSE_OK)) 385 | assert (false); 386 | 387 | // Close writer 388 | zpipes_msg_send_close (writer); 389 | if (s_expect_reply (writer, ZPIPES_MSG_CLOSE_OK)) 390 | assert (false); 391 | 392 | // Pipe is terminated and empty 393 | zpipes_msg_send_read (reader2, 0, 0); 394 | if (s_expect_reply (reader2, ZPIPES_MSG_READ_END)) 395 | assert (false); 396 | 397 | // Do that again to be sure it wasn't a coincidence :) 398 | zpipes_msg_send_read (reader2, 0, 0); 399 | if (s_expect_reply (reader2, ZPIPES_MSG_READ_END)) 400 | assert (false); 401 | 402 | // Close reader2 403 | zpipes_msg_send_close (reader2); 404 | if (s_expect_reply (reader2, ZPIPES_MSG_CLOSE_OK)) 405 | assert (false); 406 | 407 | // -------------------------------------------------------------------- 408 | // Test reader closing while writer still active 409 | 410 | // Open writer on pipe 411 | zpipes_msg_send_output (writer, "test pipe"); 412 | if (s_expect_reply (writer, ZPIPES_MSG_OUTPUT_OK)) 413 | assert (false); 414 | 415 | // Open reader on pipe 416 | zpipes_msg_send_input (reader, "test pipe"); 417 | if (s_expect_reply (reader, ZPIPES_MSG_INPUT_OK)) 418 | assert (false); 419 | 420 | // Write one chunk to pipe 421 | zpipes_msg_send_write (writer, chunk, 0); 422 | if (s_expect_reply (writer, ZPIPES_MSG_WRITE_OK)) 423 | assert (false); 424 | 425 | // Read should be successful 426 | zpipes_msg_send_read (reader, 12, 0); 427 | if (s_expect_reply (reader, ZPIPES_MSG_READ_OK)) 428 | assert (false); 429 | 430 | // Close reader 431 | zpipes_msg_send_close (reader); 432 | if (s_expect_reply (reader, ZPIPES_MSG_CLOSE_OK)) 433 | assert (false); 434 | 435 | // Write should fail 436 | zpipes_msg_send_write (writer, chunk, 0); 437 | if (s_expect_reply (writer, ZPIPES_MSG_WRITE_FAILED)) 438 | assert (false); 439 | 440 | // Close writer 441 | zpipes_msg_send_close (writer); 442 | if (s_expect_reply (writer, ZPIPES_MSG_CLOSE_OK)) 443 | assert (false); 444 | 445 | // -------------------------------------------------------------------- 446 | // Two readers or writers on same pipe are not allowed 447 | 448 | // Open writer on pipe 449 | zpipes_msg_send_output (writer, "test pipe"); 450 | if (s_expect_reply (writer, ZPIPES_MSG_OUTPUT_OK)) 451 | assert (false); 452 | 453 | // Open second writer on pipe 454 | zpipes_msg_send_output (writer2, "test pipe"); 455 | if (s_expect_reply (writer2, ZPIPES_MSG_OUTPUT_FAILED)) 456 | assert (false); 457 | 458 | // Open reader on pipe 459 | zpipes_msg_send_input (reader, "test pipe"); 460 | if (s_expect_reply (reader, ZPIPES_MSG_INPUT_OK)) 461 | assert (false); 462 | 463 | // Open second reader on pipe 464 | zpipes_msg_send_input (reader2, "test pipe"); 465 | if (s_expect_reply (reader2, ZPIPES_MSG_INPUT_FAILED)) 466 | assert (false); 467 | 468 | // Close reader 469 | zpipes_msg_send_close (reader); 470 | if (s_expect_reply (reader, ZPIPES_MSG_CLOSE_OK)) 471 | assert (false); 472 | 473 | // Close writer 474 | zpipes_msg_send_close (writer); 475 | if (s_expect_reply (writer, ZPIPES_MSG_CLOSE_OK)) 476 | assert (false); 477 | 478 | // -------------------------------------------------------------------- 479 | // Test short read when writer closes 480 | 481 | // Open writer on pipe 482 | zpipes_msg_send_output (writer, "test pipe"); 483 | if (s_expect_reply (writer, ZPIPES_MSG_OUTPUT_OK)) 484 | assert (false); 485 | 486 | // Open reader on pipe 487 | zpipes_msg_send_input (reader, "test pipe"); 488 | if (s_expect_reply (reader, ZPIPES_MSG_INPUT_OK)) 489 | assert (false); 490 | 491 | // Write one chunk to pipe 492 | zpipes_msg_send_write (writer, chunk, 0); 493 | if (s_expect_reply (writer, ZPIPES_MSG_WRITE_OK)) 494 | assert (false); 495 | 496 | // Try to read large amount of data, will block 497 | zpipes_msg_send_read (reader, 1000, 0); 498 | 499 | // Close writer 500 | zpipes_msg_send_close (writer); 501 | if (s_expect_reply (writer, ZPIPES_MSG_CLOSE_OK)) 502 | assert (false); 503 | 504 | // Reader should now return short read 505 | if (s_expect_reply (reader, ZPIPES_MSG_READ_OK)) 506 | assert (false); 507 | 508 | // Pipe is terminated and empty 509 | zpipes_msg_send_read (reader, 0, 0); 510 | if (s_expect_reply (reader, ZPIPES_MSG_READ_END)) 511 | assert (false); 512 | 513 | // Close reader 514 | zpipes_msg_send_close (reader); 515 | if (s_expect_reply (reader, ZPIPES_MSG_CLOSE_OK)) 516 | assert (false); 517 | 518 | // -------------------------------------------------------------------- 519 | zchunk_destroy (&chunk); 520 | zactor_destroy (&server); 521 | zsock_destroy (&reader); 522 | zsock_destroy (&writer); 523 | zsock_destroy (&reader2); 524 | zsock_destroy (&writer2); 525 | ---- 526 | 527 | SEE ALSO 528 | -------- 529 | linkzpipes:zpipes[7] 530 | -------------------------------------------------------------------------------- /include/zbroker.h: -------------------------------------------------------------------------------- 1 | /* ========================================================================= 2 | zbroker - ZeroMQ broker project public API 3 | 4 | Copyright (c) the Contributors as noted in the AUTHORS file. 5 | This file is part of zbroker, the ZeroMQ broker project. 6 | 7 | This Source Code Form is subject to the terms of the Mozilla Public 8 | License, v. 2.0. If a copy of the MPL was not distributed with this 9 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 10 | =========================================================================*/ 11 | 12 | #ifndef __ZBROKER_H_INCLUDED__ 13 | #define __ZBROKER_H_INCLUDED__ 14 | 15 | // ZBROKER version macros for compile-time API detection 16 | 17 | #define ZBROKER_VERSION_MAJOR 0 18 | #define ZBROKER_VERSION_MINOR 0 19 | #define ZBROKER_VERSION_PATCH 3 20 | 21 | #define ZBROKER_MAKE_VERSION(major, minor, patch) \ 22 | ((major) * 10000 + (minor) * 100 + (patch)) 23 | #define ZBROKER_VERSION \ 24 | ZBROKER_MAKE_VERSION(ZBROKER_VERSION_MAJOR, ZBROKER_VERSION_MINOR, ZBROKER_VERSION_PATCH) 25 | 26 | #include 27 | #if CZMQ_VERSION < 20200 28 | # error "zbroker needs CZMQ/2.2.0 or later" 29 | #endif 30 | 31 | #include 32 | #if ZYRE_VERSION < 10100 33 | # error "zbroker needs Zyre/1.1.0 or later" 34 | #endif 35 | 36 | // Public API 37 | #include "zpipes_msg.h" 38 | #include "zpipes_server.h" 39 | #include "zpipes_client.h" 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /include/zpipes_client.h: -------------------------------------------------------------------------------- 1 | /* ========================================================================= 2 | zpipes_client.h - simple API for zpipes client applications 3 | 4 | Copyright (c) the Contributors as noted in the AUTHORS file. 5 | This file is part of zbroker, the ZeroMQ broker project. 6 | 7 | This Source Code Form is subject to the terms of the Mozilla Public 8 | License, v. 2.0. If a copy of the MPL was not distributed with this 9 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 10 | ========================================================================= 11 | */ 12 | 13 | #ifndef __ZPIPES_CLIENT_H_INCLUDED__ 14 | #define __ZPIPES_CLIENT_H_INCLUDED__ 15 | 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif 19 | 20 | typedef struct _zpipes_client_t zpipes_client_t; 21 | 22 | // @interface 23 | // Constructor; open ">pipename" for writing, "pipename" for reading 24 | CZMQ_EXPORT zpipes_client_t * 25 | zpipes_client_new (const char *broker_name, const char *pipe_name); 26 | 27 | // Destructor; closes pipe 28 | CZMQ_EXPORT void 29 | zpipes_client_destroy (zpipes_client_t **self_p); 30 | 31 | // Write chunk of data to pipe; returns number of bytes written, or -1 32 | // in case of error, and then sets zpipes_client_error() to EBADF. 33 | CZMQ_EXPORT ssize_t 34 | zpipes_client_write (zpipes_client_t *self, 35 | void *data, size_t size, int timeout); 36 | 37 | // Read chunk of data from pipe. If timeout is non zero, waits at most 38 | // that many msecs for data. Returns number of bytes read, or zero if the 39 | // pipe was closed by the writer, and no more data is available. On a 40 | // timeout or interrupt, returns -1. To get the actual error code, call 41 | // zpipes_client_error(), which will be EINTR, EAGAIN, or EBADF. 42 | CZMQ_EXPORT ssize_t 43 | zpipes_client_read (zpipes_client_t *self, 44 | void *data, size_t max_size, int timeout); 45 | 46 | // Returns last error number, if any 47 | CZMQ_EXPORT int 48 | zpipes_client_error (zpipes_client_t *self); 49 | 50 | // Self test of this class 51 | CZMQ_EXPORT void 52 | zpipes_client_test (bool verbose); 53 | // @end 54 | 55 | #ifdef __cplusplus 56 | } 57 | #endif 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /include/zpipes_msg.h: -------------------------------------------------------------------------------- 1 | /* ========================================================================= 2 | zpipes_msg - ZPIPES protocol 3 | 4 | Codec header for zpipes_msg. 5 | 6 | ** WARNING ************************************************************* 7 | THIS SOURCE FILE IS 100% GENERATED. If you edit this file, you will lose 8 | your changes at the next build cycle. This is great for temporary printf 9 | statements. DO NOT MAKE ANY CHANGES YOU WISH TO KEEP. The correct places 10 | for commits are: 11 | 12 | * The XML model used for this code generation: zpipes_msg.xml 13 | * The code generation script that built this file: zproto_codec_c 14 | ************************************************************************ 15 | Copyright (c) the Contributors as noted in the AUTHORS file. 16 | This file is part of zbroker, the ZeroMQ broker project. 17 | 18 | This Source Code Form is subject to the terms of the Mozilla Public 19 | License, v. 2.0. If a copy of the MPL was not distributed with this 20 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 21 | ========================================================================= 22 | */ 23 | 24 | #ifndef __ZPIPES_MSG_H_INCLUDED__ 25 | #define __ZPIPES_MSG_H_INCLUDED__ 26 | 27 | /* These are the zpipes_msg messages: 28 | 29 | INPUT - Create a new pipe for reading 30 | pipename string Name of pipe 31 | 32 | INPUT_OK - Input request was successful 33 | 34 | INPUT_FAILED - Input request failed 35 | reason string Reason for failure 36 | 37 | OUTPUT - Create a new pipe for writing 38 | pipename string Name of pipe 39 | 40 | OUTPUT_OK - Output request was successful 41 | 42 | OUTPUT_FAILED - Output request failed 43 | reason string Reason for failure 44 | 45 | READ - Read a chunk of data from pipe 46 | size number 4 Number of bytes to read 47 | timeout number 4 Timeout, msecs, or zero 48 | 49 | READ_OK - Read was successful 50 | chunk chunk Chunk of data 51 | 52 | READ_END - Pipe is closed, no more data 53 | 54 | READ_TIMEOUT - Read ended with timeout 55 | 56 | READ_FAILED - Read failed due to error 57 | reason string Reason for failure 58 | 59 | WRITE - Write chunk of data to pipe 60 | chunk chunk Chunk of data 61 | timeout number 4 Timeout, msecs, or zero 62 | 63 | WRITE_OK - Write was successful 64 | 65 | WRITE_TIMEOUT - Write ended with timeout 66 | 67 | WRITE_FAILED - Read failed due to error 68 | reason string Reason for failure 69 | 70 | CLOSE - Close pipe 71 | 72 | CLOSE_OK - Close was successful 73 | 74 | CLOSE_FAILED - Close failed due to error 75 | reason string Reason for failure 76 | 77 | PING - Signal liveness 78 | 79 | PING_OK - Respond to ping 80 | 81 | INVALID - Command was invalid at this time 82 | */ 83 | 84 | 85 | #define ZPIPES_MSG_INPUT 1 86 | #define ZPIPES_MSG_INPUT_OK 2 87 | #define ZPIPES_MSG_INPUT_FAILED 3 88 | #define ZPIPES_MSG_OUTPUT 4 89 | #define ZPIPES_MSG_OUTPUT_OK 5 90 | #define ZPIPES_MSG_OUTPUT_FAILED 6 91 | #define ZPIPES_MSG_READ 7 92 | #define ZPIPES_MSG_READ_OK 8 93 | #define ZPIPES_MSG_READ_END 9 94 | #define ZPIPES_MSG_READ_TIMEOUT 10 95 | #define ZPIPES_MSG_READ_FAILED 11 96 | #define ZPIPES_MSG_WRITE 12 97 | #define ZPIPES_MSG_WRITE_OK 13 98 | #define ZPIPES_MSG_WRITE_TIMEOUT 14 99 | #define ZPIPES_MSG_WRITE_FAILED 15 100 | #define ZPIPES_MSG_CLOSE 16 101 | #define ZPIPES_MSG_CLOSE_OK 17 102 | #define ZPIPES_MSG_CLOSE_FAILED 18 103 | #define ZPIPES_MSG_PING 19 104 | #define ZPIPES_MSG_PING_OK 20 105 | #define ZPIPES_MSG_INVALID 21 106 | 107 | #ifdef __cplusplus 108 | extern "C" { 109 | #endif 110 | 111 | // Opaque class structure 112 | typedef struct _zpipes_msg_t zpipes_msg_t; 113 | 114 | // @interface 115 | // Create a new zpipes_msg 116 | zpipes_msg_t * 117 | zpipes_msg_new (int id); 118 | 119 | // Destroy the zpipes_msg 120 | void 121 | zpipes_msg_destroy (zpipes_msg_t **self_p); 122 | 123 | // Parse a zpipes_msg from zmsg_t. Returns a new object, or NULL if 124 | // the message could not be parsed, or was NULL. Destroys msg and 125 | // nullifies the msg reference. 126 | zpipes_msg_t * 127 | zpipes_msg_decode (zmsg_t **msg_p); 128 | 129 | // Encode zpipes_msg into zmsg and destroy it. Returns a newly created 130 | // object or NULL if error. Use when not in control of sending the message. 131 | zmsg_t * 132 | zpipes_msg_encode (zpipes_msg_t **self_p); 133 | 134 | // Receive and parse a zpipes_msg from the socket. Returns new object, 135 | // or NULL if error. Will block if there's no message waiting. 136 | zpipes_msg_t * 137 | zpipes_msg_recv (void *input); 138 | 139 | // Receive and parse a zpipes_msg from the socket. Returns new object, 140 | // or NULL either if there was no input waiting, or the recv was interrupted. 141 | zpipes_msg_t * 142 | zpipes_msg_recv_nowait (void *input); 143 | 144 | // Send the zpipes_msg to the output, and destroy it 145 | int 146 | zpipes_msg_send (zpipes_msg_t **self_p, void *output); 147 | 148 | // Send the zpipes_msg to the output, and do not destroy it 149 | int 150 | zpipes_msg_send_again (zpipes_msg_t *self, void *output); 151 | 152 | // Encode the INPUT 153 | zmsg_t * 154 | zpipes_msg_encode_input ( 155 | const char *pipename); 156 | 157 | // Encode the INPUT_OK 158 | zmsg_t * 159 | zpipes_msg_encode_input_ok ( 160 | ); 161 | 162 | // Encode the INPUT_FAILED 163 | zmsg_t * 164 | zpipes_msg_encode_input_failed ( 165 | const char *reason); 166 | 167 | // Encode the OUTPUT 168 | zmsg_t * 169 | zpipes_msg_encode_output ( 170 | const char *pipename); 171 | 172 | // Encode the OUTPUT_OK 173 | zmsg_t * 174 | zpipes_msg_encode_output_ok ( 175 | ); 176 | 177 | // Encode the OUTPUT_FAILED 178 | zmsg_t * 179 | zpipes_msg_encode_output_failed ( 180 | const char *reason); 181 | 182 | // Encode the READ 183 | zmsg_t * 184 | zpipes_msg_encode_read ( 185 | uint32_t size, 186 | uint32_t timeout); 187 | 188 | // Encode the READ_OK 189 | zmsg_t * 190 | zpipes_msg_encode_read_ok ( 191 | zchunk_t *chunk); 192 | 193 | // Encode the READ_END 194 | zmsg_t * 195 | zpipes_msg_encode_read_end ( 196 | ); 197 | 198 | // Encode the READ_TIMEOUT 199 | zmsg_t * 200 | zpipes_msg_encode_read_timeout ( 201 | ); 202 | 203 | // Encode the READ_FAILED 204 | zmsg_t * 205 | zpipes_msg_encode_read_failed ( 206 | const char *reason); 207 | 208 | // Encode the WRITE 209 | zmsg_t * 210 | zpipes_msg_encode_write ( 211 | zchunk_t *chunk, 212 | uint32_t timeout); 213 | 214 | // Encode the WRITE_OK 215 | zmsg_t * 216 | zpipes_msg_encode_write_ok ( 217 | ); 218 | 219 | // Encode the WRITE_TIMEOUT 220 | zmsg_t * 221 | zpipes_msg_encode_write_timeout ( 222 | ); 223 | 224 | // Encode the WRITE_FAILED 225 | zmsg_t * 226 | zpipes_msg_encode_write_failed ( 227 | const char *reason); 228 | 229 | // Encode the CLOSE 230 | zmsg_t * 231 | zpipes_msg_encode_close ( 232 | ); 233 | 234 | // Encode the CLOSE_OK 235 | zmsg_t * 236 | zpipes_msg_encode_close_ok ( 237 | ); 238 | 239 | // Encode the CLOSE_FAILED 240 | zmsg_t * 241 | zpipes_msg_encode_close_failed ( 242 | const char *reason); 243 | 244 | // Encode the PING 245 | zmsg_t * 246 | zpipes_msg_encode_ping ( 247 | ); 248 | 249 | // Encode the PING_OK 250 | zmsg_t * 251 | zpipes_msg_encode_ping_ok ( 252 | ); 253 | 254 | // Encode the INVALID 255 | zmsg_t * 256 | zpipes_msg_encode_invalid ( 257 | ); 258 | 259 | 260 | // Send the INPUT to the output in one step 261 | // WARNING, this call will fail if output is of type ZMQ_ROUTER. 262 | int 263 | zpipes_msg_send_input (void *output, 264 | const char *pipename); 265 | 266 | // Send the INPUT_OK to the output in one step 267 | // WARNING, this call will fail if output is of type ZMQ_ROUTER. 268 | int 269 | zpipes_msg_send_input_ok (void *output); 270 | 271 | // Send the INPUT_FAILED to the output in one step 272 | // WARNING, this call will fail if output is of type ZMQ_ROUTER. 273 | int 274 | zpipes_msg_send_input_failed (void *output, 275 | const char *reason); 276 | 277 | // Send the OUTPUT to the output in one step 278 | // WARNING, this call will fail if output is of type ZMQ_ROUTER. 279 | int 280 | zpipes_msg_send_output (void *output, 281 | const char *pipename); 282 | 283 | // Send the OUTPUT_OK to the output in one step 284 | // WARNING, this call will fail if output is of type ZMQ_ROUTER. 285 | int 286 | zpipes_msg_send_output_ok (void *output); 287 | 288 | // Send the OUTPUT_FAILED to the output in one step 289 | // WARNING, this call will fail if output is of type ZMQ_ROUTER. 290 | int 291 | zpipes_msg_send_output_failed (void *output, 292 | const char *reason); 293 | 294 | // Send the READ to the output in one step 295 | // WARNING, this call will fail if output is of type ZMQ_ROUTER. 296 | int 297 | zpipes_msg_send_read (void *output, 298 | uint32_t size, 299 | uint32_t timeout); 300 | 301 | // Send the READ_OK to the output in one step 302 | // WARNING, this call will fail if output is of type ZMQ_ROUTER. 303 | int 304 | zpipes_msg_send_read_ok (void *output, 305 | zchunk_t *chunk); 306 | 307 | // Send the READ_END to the output in one step 308 | // WARNING, this call will fail if output is of type ZMQ_ROUTER. 309 | int 310 | zpipes_msg_send_read_end (void *output); 311 | 312 | // Send the READ_TIMEOUT to the output in one step 313 | // WARNING, this call will fail if output is of type ZMQ_ROUTER. 314 | int 315 | zpipes_msg_send_read_timeout (void *output); 316 | 317 | // Send the READ_FAILED to the output in one step 318 | // WARNING, this call will fail if output is of type ZMQ_ROUTER. 319 | int 320 | zpipes_msg_send_read_failed (void *output, 321 | const char *reason); 322 | 323 | // Send the WRITE to the output in one step 324 | // WARNING, this call will fail if output is of type ZMQ_ROUTER. 325 | int 326 | zpipes_msg_send_write (void *output, 327 | zchunk_t *chunk, 328 | uint32_t timeout); 329 | 330 | // Send the WRITE_OK to the output in one step 331 | // WARNING, this call will fail if output is of type ZMQ_ROUTER. 332 | int 333 | zpipes_msg_send_write_ok (void *output); 334 | 335 | // Send the WRITE_TIMEOUT to the output in one step 336 | // WARNING, this call will fail if output is of type ZMQ_ROUTER. 337 | int 338 | zpipes_msg_send_write_timeout (void *output); 339 | 340 | // Send the WRITE_FAILED to the output in one step 341 | // WARNING, this call will fail if output is of type ZMQ_ROUTER. 342 | int 343 | zpipes_msg_send_write_failed (void *output, 344 | const char *reason); 345 | 346 | // Send the CLOSE to the output in one step 347 | // WARNING, this call will fail if output is of type ZMQ_ROUTER. 348 | int 349 | zpipes_msg_send_close (void *output); 350 | 351 | // Send the CLOSE_OK to the output in one step 352 | // WARNING, this call will fail if output is of type ZMQ_ROUTER. 353 | int 354 | zpipes_msg_send_close_ok (void *output); 355 | 356 | // Send the CLOSE_FAILED to the output in one step 357 | // WARNING, this call will fail if output is of type ZMQ_ROUTER. 358 | int 359 | zpipes_msg_send_close_failed (void *output, 360 | const char *reason); 361 | 362 | // Send the PING to the output in one step 363 | // WARNING, this call will fail if output is of type ZMQ_ROUTER. 364 | int 365 | zpipes_msg_send_ping (void *output); 366 | 367 | // Send the PING_OK to the output in one step 368 | // WARNING, this call will fail if output is of type ZMQ_ROUTER. 369 | int 370 | zpipes_msg_send_ping_ok (void *output); 371 | 372 | // Send the INVALID to the output in one step 373 | // WARNING, this call will fail if output is of type ZMQ_ROUTER. 374 | int 375 | zpipes_msg_send_invalid (void *output); 376 | 377 | // Duplicate the zpipes_msg message 378 | zpipes_msg_t * 379 | zpipes_msg_dup (zpipes_msg_t *self); 380 | 381 | // Print contents of message to stdout 382 | void 383 | zpipes_msg_print (zpipes_msg_t *self); 384 | 385 | // Get/set the message routing id 386 | zframe_t * 387 | zpipes_msg_routing_id (zpipes_msg_t *self); 388 | void 389 | zpipes_msg_set_routing_id (zpipes_msg_t *self, zframe_t *routing_id); 390 | 391 | // Get the zpipes_msg id and printable command 392 | int 393 | zpipes_msg_id (zpipes_msg_t *self); 394 | void 395 | zpipes_msg_set_id (zpipes_msg_t *self, int id); 396 | const char * 397 | zpipes_msg_command (zpipes_msg_t *self); 398 | 399 | // Get/set the pipename field 400 | const char * 401 | zpipes_msg_pipename (zpipes_msg_t *self); 402 | void 403 | zpipes_msg_set_pipename (zpipes_msg_t *self, const char *format, ...); 404 | 405 | // Get/set the reason field 406 | const char * 407 | zpipes_msg_reason (zpipes_msg_t *self); 408 | void 409 | zpipes_msg_set_reason (zpipes_msg_t *self, const char *format, ...); 410 | 411 | // Get/set the size field 412 | uint32_t 413 | zpipes_msg_size (zpipes_msg_t *self); 414 | void 415 | zpipes_msg_set_size (zpipes_msg_t *self, uint32_t size); 416 | 417 | // Get/set the timeout field 418 | uint32_t 419 | zpipes_msg_timeout (zpipes_msg_t *self); 420 | void 421 | zpipes_msg_set_timeout (zpipes_msg_t *self, uint32_t timeout); 422 | 423 | // Get a copy of the chunk field 424 | zchunk_t * 425 | zpipes_msg_chunk (zpipes_msg_t *self); 426 | // Get the chunk field and transfer ownership to caller 427 | zchunk_t * 428 | zpipes_msg_get_chunk (zpipes_msg_t *self); 429 | // Set the chunk field, transferring ownership from caller 430 | void 431 | zpipes_msg_set_chunk (zpipes_msg_t *self, zchunk_t **chunk_p); 432 | 433 | // Self test of this class 434 | int 435 | zpipes_msg_test (bool verbose); 436 | // @end 437 | 438 | // For backwards compatibility with old codecs 439 | #define zpipes_msg_dump zpipes_msg_print 440 | 441 | #ifdef __cplusplus 442 | } 443 | #endif 444 | 445 | #endif 446 | -------------------------------------------------------------------------------- /include/zpipes_server.h: -------------------------------------------------------------------------------- 1 | /* ========================================================================= 2 | zpipes_server - ZPIPES server 3 | 4 | ** WARNING ************************************************************* 5 | THIS SOURCE FILE IS 100% GENERATED. If you edit this file, you will lose 6 | your changes at the next build cycle. This is great for temporary printf 7 | statements. DO NOT MAKE ANY CHANGES YOU WISH TO KEEP. The correct places 8 | for commits are: 9 | 10 | * The XML model used for this code generation: zpipes_server.xml 11 | * The code generation script that built this file: zproto_server_c 12 | ************************************************************************ 13 | 14 | Copyright (c) the Contributors as noted in the AUTHORS file. 15 | This file is part of zbroker, the ZeroMQ broker project. 16 | 17 | This Source Code Form is subject to the terms of the Mozilla Public 18 | License, v. 2.0. If a copy of the MPL was not distributed with this 19 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 20 | ========================================================================= 21 | */ 22 | 23 | #ifndef __ZPIPES_SERVER_H_INCLUDED__ 24 | #define __ZPIPES_SERVER_H_INCLUDED__ 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | // @interface 31 | // To work with zpipes_server, use the CZMQ zactor API: 32 | // 33 | // Create new zpipes server instance, passing logging prefix: 34 | // 35 | // zactor_t *zpipes_server = zactor_new (zpipes_server, "myname"); 36 | // 37 | // Destroy zpipes server instance 38 | // 39 | // zactor_destroy (&zpipes_server); 40 | // 41 | // Enable verbose logging of commands and activity: 42 | // 43 | // zstr_send (server, "VERBOSE"); 44 | // 45 | // Bind zpipes server to specified endpoint. TCP endpoints may specify 46 | // the port number as "*" to aquire an ephemeral port: 47 | // 48 | // zstr_sendx (zpipes_server, "BIND", endpoint, NULL); 49 | // 50 | // Return assigned port number, specifically when BIND was done using an 51 | // an ephemeral port: 52 | // 53 | // zstr_sendx (zpipes_server, "PORT", NULL); 54 | // char *command, *port_str; 55 | // zstr_recvx (zpipes_server, &command, &port_str, NULL); 56 | // assert (streq (command, "PORT")); 57 | // 58 | // Specify configuration file to load, overwriting any previous loaded 59 | // configuration file or options: 60 | // 61 | // zstr_sendx (zpipes_server, "CONFIGURE", filename, NULL); 62 | // 63 | // Set configuration path value: 64 | // 65 | // zstr_sendx (zpipes_server, "SET", path, value, NULL); 66 | // 67 | // Send zmsg_t instance to zpipes server: 68 | // 69 | // zactor_send (zpipes_server, &msg); 70 | // 71 | // Receive zmsg_t instance from zpipes server: 72 | // 73 | // zmsg_t *msg = zactor_recv (zpipes_server); 74 | // 75 | // This is the zpipes_server constructor as a zactor_fn: 76 | // 77 | void 78 | zpipes_server (zsock_t *pipe, void *args); 79 | 80 | // Self test of this class 81 | void 82 | zpipes_server_test (bool verbose); 83 | // @end 84 | 85 | #ifdef __cplusplus 86 | } 87 | #endif 88 | 89 | #endif 90 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | lib_LTLIBRARIES = libzbroker.la 2 | 3 | pkgconfigdir = $(libdir)/pkgconfig 4 | pkgconfig_DATA = libzbroker.pc 5 | 6 | include_HEADERS = \ 7 | ../include/zbroker.h \ 8 | ../include/zpipes_msg.h \ 9 | ../include/zpipes_server.h \ 10 | ../include/zpipes_client.h 11 | 12 | libzbroker_la_SOURCES = \ 13 | zpipes_msg.c \ 14 | zpipes_client.c \ 15 | zpipes_server.c \ 16 | zpipes_server_engine.h 17 | 18 | AM_CFLAGS = -g 19 | AM_CPPFLAGS = -I$(top_srcdir)/include 20 | bin_PROGRAMS = zbroker 21 | noinst_PROGRAMS = zbroker_selftest zpipes_test_cluster zpipes_dump 22 | 23 | zbroker_LDADD = libzbroker.la 24 | zbroker_selftest_LDADD = libzbroker.la 25 | zpipes_test_cluster_LDADD = libzbroker.la 26 | zpipes_dump_LDADD = libzbroker.la 27 | 28 | libzbroker_la_LDFLAGS = -version-info @LTVER@ 29 | 30 | TESTS = zbroker_selftest zpipes_test_cluster 31 | 32 | # Produce generated models; do this manually in src directory 33 | code: 34 | gsl -q zpipes_msg.xml 35 | gsl -q zpipes_server.xml 36 | -------------------------------------------------------------------------------- /src/libzbroker.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=@exec_prefix@ 3 | libdir=@libdir@ 4 | includedir=@includedir@ 5 | 6 | Name: libzbroker 7 | Description: ZeroMQ broker project 8 | Version: @VERSION@ 9 | Requires: libzmq libczmq libzyre 10 | Libs: -L${libdir} -lzbroker 11 | Cflags: -I${includedir} 12 | -------------------------------------------------------------------------------- /src/libzpipesclient.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=@exec_prefix@ 3 | libdir=@libdir@ 4 | includedir=@includedir@ 5 | 6 | Name: libzpipesclient 7 | Description: reliable & distributed named pipes client 8 | Version: @VERSION@ 9 | Requires: libzmq libczmq libzyre 10 | Libs: -L${libdir} -lzpipesclient 11 | Cflags: -I${includedir} 12 | -------------------------------------------------------------------------------- /src/license.xml: -------------------------------------------------------------------------------- 1 | 2 | Copyright (c) the Contributors as noted in the AUTHORS file. 3 | This file is part of zbroker, the ZeroMQ broker project. 4 | 5 | This Source Code Form is subject to the terms of the Mozilla Public 6 | License, v. 2.0. If a copy of the MPL was not distributed with this 7 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | -------------------------------------------------------------------------------- /src/selftest: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | # 3 | # Run selftests and check memory 4 | 5 | MAIN=zbroker_selftest 6 | VG="valgrind --tool=memcheck --leak-check=full --show-reachable=yes --suppressions=valgrind.supp" 7 | 8 | make code 9 | gcc -g -o $MAIN \ 10 | $MAIN.c \ 11 | zpipes_msg.c zpipes_client.c zpipes_server.c \ 12 | -lczmq -lzmq -lzyre -luuid -lsodium 13 | test $? -ne 0 && exit 14 | $VG ./$MAIN 15 | rm -f vgcore.* 16 | -------------------------------------------------------------------------------- /src/valgrind.supp: -------------------------------------------------------------------------------- 1 | { 2 | 3 | Memcheck:Param 4 | socketcall.sendto(msg) 5 | fun:send 6 | ... 7 | } 8 | { 9 | 10 | Memcheck:Param 11 | socketcall.send(msg) 12 | fun:send 13 | ... 14 | } 15 | -------------------------------------------------------------------------------- /src/vg: -------------------------------------------------------------------------------- 1 | valgrind --tool=memcheck --leak-check=full --suppressions=valgrind.supp $* 2 | -------------------------------------------------------------------------------- /src/zbroker-daemon.cfg: -------------------------------------------------------------------------------- 1 | # Default zbroker configuration 2 | 3 | # Apply to the whole broker 4 | server 5 | timeout = 10000 # Client connection timeout, msec 6 | background = 1 # Run as background process 7 | workdir = . # Working directory for daemon 8 | verbose = 1 # Do verbose logging of activity? 9 | user = ph # Run as this user 10 | group = ph # Run as this group 11 | lockfile = /var/run/zbroker.pid 12 | 13 | # Apply to the zpipes server only 14 | zpipes_server 15 | echo = binding zpipes service to 'ipc://@/zpipes/local' 16 | bind 17 | endpoint = ipc://@/zpipes/local 18 | 19 | # Zyre cluster configuration 20 | zyre 21 | port = 5670 # Default = 5670 22 | interval = 250 # Default = 1000 msec 23 | # name = somenode # Override generated node name 24 | # interface = eth0 # Use this network interface 25 | -------------------------------------------------------------------------------- /src/zbroker.c: -------------------------------------------------------------------------------- 1 | /* ========================================================================= 2 | zbroker - command-line broker daemon 3 | 4 | Copyright (c) the Contributors as noted in the AUTHORS file. 5 | This file is part of zbroker, the ZeroMQ broker project. 6 | 7 | This Source Code Form is subject to the terms of the Mozilla Public 8 | License, v. 2.0. If a copy of the MPL was not distributed with this 9 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 10 | ========================================================================= 11 | */ 12 | 13 | #include "zbroker_classes.h" 14 | 15 | #define PRODUCT "zbroker service/0.0.2" 16 | #define COPYRIGHT "Copyright (c) 2014 the Contributors" 17 | #define NOWARRANTY \ 18 | "This Software is provided under the MPLv2 License on an \"as is\" basis,\n" \ 19 | "without warranty of any kind, either expressed, implied, or statutory.\n" 20 | 21 | int main (int argc, char *argv []) 22 | { 23 | puts (PRODUCT); 24 | puts (COPYRIGHT); 25 | puts (NOWARRANTY); 26 | 27 | if (argc == 2 && streq (argv [1], "-h")) { 28 | puts ("Usage: zbroker [-h | config-file]"); 29 | puts (" Default config-file is 'zbroker.cfg'"); 30 | return 0; 31 | } 32 | // Collect configuration file name 33 | const char *config_file = "zbroker.cfg"; 34 | if (argc > 1) 35 | config_file = argv [1]; 36 | 37 | // Send logging to system facility as well as stdout 38 | zsys_init (); 39 | zsys_set_logsystem (true); 40 | 41 | // Load config file for our own use here 42 | zsys_info ("starting zpipes broker using config in '%s'", config_file); 43 | zconfig_t *config = zconfig_load (config_file); 44 | if (config) { 45 | // Do we want to run broker in the background? 46 | int as_daemon = atoi (zconfig_resolve (config, "server/background", "0")); 47 | const char *workdir = zconfig_resolve (config, "server/workdir", "."); 48 | if (as_daemon) { 49 | zsys_info ("broker switching to background process..."); 50 | if (zsys_daemonize (workdir)) 51 | return -1; 52 | } 53 | // Switch to user/group to run process under, if any 54 | if (zsys_run_as ( 55 | zconfig_resolve (config, "server/lockfile", NULL), 56 | zconfig_resolve (config, "server/group", NULL), 57 | zconfig_resolve (config, "server/user", NULL))) 58 | return -1; 59 | 60 | zconfig_destroy (&config); 61 | } 62 | else { 63 | zsys_error ("cannot load config file '%s'\n", config_file); 64 | return 1; 65 | } 66 | zactor_t *server = zactor_new (zpipes_server, NULL); 67 | zstr_sendx (server, "CONFIGURE", config_file, NULL); 68 | zstr_sendx (server, "JOIN CLUSTER", NULL); 69 | 70 | char *reply = zstr_recv (server); 71 | if (reply && strneq (reply, "OK")) 72 | zsys_warning ("no UDP discovery, cannot join cluster"); 73 | free (reply); 74 | 75 | // Accept and print any message back from server 76 | while (true) { 77 | char *message = zstr_recv (server); 78 | if (message) { 79 | puts (message); 80 | free (message); 81 | } 82 | else { 83 | puts ("interrupted"); 84 | break; 85 | } 86 | } 87 | // Shutdown all services 88 | zactor_destroy (&server); 89 | return 0; 90 | } 91 | -------------------------------------------------------------------------------- /src/zbroker.cfg: -------------------------------------------------------------------------------- 1 | # Default zbroker configuration 2 | 3 | # Apply to the whole broker 4 | server 5 | timeout = 10000 # Client connection timeout, msec 6 | background = 0 # Run as background process 7 | workdir = . # Working directory for daemon 8 | verbose = 1 # Do verbose logging of activity? 9 | 10 | # Apply to the zpipes server only 11 | zpipes_server 12 | echo = binding zpipes service to 'ipc://@/zpipes/local' 13 | bind 14 | endpoint = ipc://@/zpipes/local 15 | 16 | # Zyre cluster configuration 17 | zyre 18 | name = zbroker # Default = random name 19 | discovery = gossip # beacon | gossip 20 | 21 | # Beacon discovery uses UDP broadcasts (CZMQ zbeacon class) 22 | beacon 23 | interface = auto # Beacon network interface, default = auto 24 | interval = 250 # Beacon interval, default = 1000 msec 25 | port = 5670 # Beacon UDP port, default = 5670 26 | 27 | # Gossip discovery uses loosely-connected TCP (CZMQ zgossip), 28 | # must bind or connect to 29 | gossip 30 | # This is our Zyre endpoint that we'll broadcast over the 31 | # gossip network; it must be accessible to all brokers in 32 | # the network. Default is hostname + ephemeral port. 33 | endpoint = tcp://127.0.0.1:5671 34 | # This is the network configuration for the gossip service 35 | # which binds to a set of endpoints and connects to a set 36 | # of endpoints (independently of Zyre) 37 | bind = ipc://@/zgossip/hub 38 | -------------------------------------------------------------------------------- /src/zbroker_classes.h: -------------------------------------------------------------------------------- 1 | /* ========================================================================= 2 | zpipes_classes - all classes in proper order for building 3 | 4 | ------------------------------------------------------------------------- 5 | Copyright (c) the Contributors as noted in the AUTHORS file. 6 | This file is part of zbroker, the ZeroMQ broker project. 7 | 8 | This Source Code Form is subject to the terms of the Mozilla Public 9 | License, v. 2.0. If a copy of the MPL was not distributed with this 10 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 11 | ========================================================================= 12 | */ 13 | 14 | #ifndef __ZPIPES_CLASSES_H_INCLUDED__ 15 | #define __ZPIPES_CLASSES_H_INCLUDED__ 16 | 17 | // External API 18 | #include "../include/zbroker.h" 19 | 20 | // Internal API 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /src/zbroker_daemon: -------------------------------------------------------------------------------- 1 | MAIN=zbroker 2 | 3 | sudo rm $MAIN 4 | gcc -g -o $MAIN \ 5 | $MAIN.c \ 6 | zpipes_msg.c zpipes_client.c zpipes_server.c \ 7 | -lczmq -lzmq -lzyre -luuid -lsodium 8 | test $? -ne 0 && exit 9 | 10 | sudo chown root $MAIN 11 | sudo chgrp root $MAIN 12 | sudo chmod +s $MAIN 13 | 14 | ./$MAIN zbroker-daemon.cfg 15 | -------------------------------------------------------------------------------- /src/zbroker_selftest.c: -------------------------------------------------------------------------------- 1 | /* ========================================================================= 2 | zbroker_selftest - run self tests 3 | 4 | ------------------------------------------------------------------------- 5 | Copyright (c) the Contributors as noted in the AUTHORS file. 6 | This file is part of zbroker, the ZeroMQ broker project. 7 | 8 | This Source Code Form is subject to the terms of the Mozilla Public 9 | License, v. 2.0. If a copy of the MPL was not distributed with this 10 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 11 | ========================================================================= 12 | */ 13 | 14 | #include "zbroker_classes.h" 15 | 16 | int main (int argc, char *argv []) 17 | { 18 | bool verbose; 19 | if (argc == 2 && streq (argv [1], "-v")) 20 | verbose = true; 21 | else 22 | verbose = false; 23 | 24 | printf ("Running self tests...\n"); 25 | zpipes_msg_test (verbose); 26 | zpipes_server_test (verbose); 27 | zpipes_client_test (verbose); 28 | printf ("Tests passed OK\n"); 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /src/zpipes_client.c: -------------------------------------------------------------------------------- 1 | /* ========================================================================= 2 | zpipes_client.c - API for zpipes client applications 3 | 4 | Copyright (c) the Contributors as noted in the AUTHORS file. 5 | This file is part of zbroker, the ZeroMQ broker project. 6 | 7 | This Source Code Form is subject to the terms of the Mozilla Public 8 | License, v. 2.0. If a copy of the MPL was not distributed with this 9 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 10 | ========================================================================= 11 | */ 12 | 13 | /* 14 | @header 15 | Provides an API to the ZPIPES infrastructure. 16 | @discuss 17 | @end 18 | */ 19 | 20 | #include "zbroker_classes.h" 21 | 22 | // --------------------------------------------------------------------- 23 | // Structure of zpipes_client class 24 | 25 | struct _zpipes_client_t { 26 | zsock_t *dealer; // Dealer socket to zpipes server 27 | int error; // Last error cause 28 | }; 29 | 30 | 31 | // Return 0 if the reply from the broker is what we expect, else return 32 | // -1. This includes interrupts. 33 | // TODO: implement timeout when broker doesn't reply at all 34 | // TODO: this loop should also PING the broker every second 35 | 36 | static int 37 | s_expect_reply (zpipes_client_t *self, int message_id) 38 | { 39 | zpipes_msg_t *reply = zpipes_msg_recv (self->dealer); 40 | if (!reply) 41 | return -1; 42 | int rc = zpipes_msg_id (reply) == message_id? 0: -1; 43 | zpipes_msg_destroy (&reply); 44 | return rc; 45 | } 46 | 47 | 48 | // --------------------------------------------------------------------- 49 | // Constructor; open ">pipename" for writing, "pipename" for reading 50 | // Returns a new client instance, or NULL if there was an error (e.g. 51 | // two readers trying to access same pipe). 52 | 53 | zpipes_client_t * 54 | zpipes_client_new (const char *server_name, const char *pipe_name) 55 | { 56 | // Create new pipe API instance 57 | zpipes_client_t *self = (zpipes_client_t *) zmalloc (sizeof (zpipes_client_t)); 58 | assert (self); 59 | 60 | // Create dealer socket and connect to server IPC port 61 | self->dealer = zsock_new (ZMQ_DEALER); 62 | assert (self->dealer); 63 | int rc = zsock_connect (self->dealer, "ipc://@/zpipes/%s", server_name); 64 | assert (rc == 0); 65 | 66 | // Open pipe for reading or writing 67 | if (*pipe_name == '>') { 68 | zpipes_msg_send_output (self->dealer, pipe_name + 1); 69 | if (s_expect_reply (self, ZPIPES_MSG_OUTPUT_OK)) 70 | zpipes_client_destroy (&self); 71 | } 72 | else { 73 | zpipes_msg_send_input (self->dealer, pipe_name); 74 | if (s_expect_reply (self, ZPIPES_MSG_INPUT_OK)) 75 | zpipes_client_destroy (&self); 76 | } 77 | return self; 78 | } 79 | 80 | 81 | // --------------------------------------------------------------------- 82 | // Destructor 83 | 84 | void 85 | zpipes_client_destroy (zpipes_client_t **self_p) 86 | { 87 | assert (self_p); 88 | if (*self_p) { 89 | zpipes_client_t *self = *self_p; 90 | if (self->dealer) { 91 | zpipes_msg_send_close (self->dealer); 92 | // Get reply, ignore it: could be ok or an error depending 93 | // on what the client did before. 94 | zpipes_msg_t *reply = zpipes_msg_recv (self->dealer); 95 | zpipes_msg_destroy (&reply); 96 | } 97 | zsock_destroy (&self->dealer); 98 | free (self); 99 | *self_p = NULL; 100 | } 101 | } 102 | 103 | 104 | // --------------------------------------------------------------------- 105 | // Write chunk of data to pipe; returns number of bytes written, or -1 106 | // in case of error. To get the actual error code, call 107 | // zpipes_client_error(), which will be EINTR, EAGAIN, or EBADF. 108 | 109 | ssize_t 110 | zpipes_client_write (zpipes_client_t *self, void *data, size_t size, int timeout) 111 | { 112 | assert (self); 113 | zchunk_t *chunk = zchunk_new (data, size); 114 | assert (chunk); 115 | zpipes_msg_t *request = zpipes_msg_new (ZPIPES_MSG_WRITE); 116 | zpipes_msg_set_chunk (request, &chunk); 117 | zpipes_msg_set_timeout (request, timeout); 118 | zpipes_msg_send (&request, self->dealer); 119 | 120 | zpipes_msg_t *reply = zpipes_msg_recv (self->dealer); 121 | if (!reply) { 122 | self->error = EINTR; 123 | return -1; // Interrupted 124 | } 125 | ssize_t rc = size; 126 | if (zpipes_msg_id (reply) == ZPIPES_MSG_WRITE_TIMEOUT) { 127 | self->error = EAGAIN; 128 | rc = -1; 129 | } 130 | else 131 | if (zpipes_msg_id (reply) == ZPIPES_MSG_WRITE_FAILED) { 132 | // TODO: better error code? 133 | // This happens if we close a pipe while there's a pending write 134 | self->error = EINTR; 135 | rc = -1; 136 | } 137 | else 138 | if (zpipes_msg_id (reply) == ZPIPES_MSG_INVALID) { 139 | self->error = EBADF; 140 | rc = -1; 141 | } 142 | zpipes_msg_destroy (&reply); 143 | return rc; 144 | } 145 | 146 | 147 | // --------------------------------------------------------------------- 148 | // Read from the pipe. If the timeout is non-zero, waits at most that 149 | // many msecs for data. Returns number of bytes read, or zero if the 150 | // pipe was closed by the writer, and no more data is available. On a 151 | // timeout or interrupt, returns -1. To get the actual error code, call 152 | // zpipes_client_error(), which will be EINTR, EAGAIN, or EBADF. 153 | 154 | ssize_t 155 | zpipes_client_read (zpipes_client_t *self, void *data, size_t size, int timeout) 156 | { 157 | assert (self); 158 | 159 | zpipes_msg_send_read (self->dealer, size, timeout); 160 | zpipes_msg_t *reply = zpipes_msg_recv (self->dealer); 161 | if (!reply) { 162 | self->error = EINTR; 163 | return -1; // Interrupted 164 | } 165 | ssize_t rc = 0; 166 | if (zpipes_msg_id (reply) == ZPIPES_MSG_READ_OK) { 167 | zchunk_t *chunk = zpipes_msg_chunk (reply); 168 | ssize_t bytes = zchunk_size (chunk); 169 | assert (bytes <= size); 170 | memcpy (data, zchunk_data (chunk), bytes); 171 | rc = bytes; 172 | } 173 | else 174 | if (zpipes_msg_id (reply) == ZPIPES_MSG_READ_END) 175 | rc = 0; 176 | else 177 | if (zpipes_msg_id (reply) == ZPIPES_MSG_READ_TIMEOUT) { 178 | self->error = EAGAIN; 179 | rc = -1; 180 | } 181 | else 182 | if (zpipes_msg_id (reply) == ZPIPES_MSG_READ_FAILED) { 183 | // TODO: better error code? 184 | // This happens if we close a pipe while there's a pending read 185 | self->error = EINTR; 186 | rc = -1; 187 | } 188 | else 189 | if (zpipes_msg_id (reply) == ZPIPES_MSG_INVALID) { 190 | self->error = EBADF; 191 | rc = -1; 192 | } 193 | zpipes_msg_destroy (&reply); 194 | return rc; 195 | } 196 | 197 | 198 | // --------------------------------------------------------------------- 199 | // Returns last error number, if any 200 | 201 | int 202 | zpipes_client_error (zpipes_client_t *self) 203 | { 204 | assert (self); 205 | return self->error; 206 | } 207 | 208 | 209 | // --------------------------------------------------------------------- 210 | // Self test of this class 211 | 212 | void 213 | zpipes_client_test (bool verbose) 214 | { 215 | printf (" * zpipes_client: "); 216 | if (verbose) 217 | printf ("\n"); 218 | 219 | // @selftest 220 | zactor_t *server = zactor_new (zpipes_server, NULL); 221 | if (verbose) 222 | zstr_send (server, "VERBOSE"); 223 | zstr_sendx (server, "BIND", "ipc://@/zpipes/local", NULL); 224 | 225 | zpipes_client_t *reader = zpipes_client_new ("local", "test pipe"); 226 | zpipes_client_t *writer = zpipes_client_new ("local", ">test pipe"); 227 | 228 | byte buffer [100]; 229 | ssize_t bytes; 230 | 231 | // Expect timeout error, EAGAIN 232 | bytes = zpipes_client_read (reader, buffer, 6, 100); 233 | assert (bytes == -1); 234 | assert (zpipes_client_error (reader) == EAGAIN); 235 | 236 | bytes = zpipes_client_write (writer, "CHUNK1", 6, 100); 237 | assert (bytes == 6); 238 | bytes = zpipes_client_write (writer, "CHUNK2", 6, 100); 239 | assert (bytes == 6); 240 | bytes = zpipes_client_write (writer, "CHUNK3", 6, 100); 241 | assert (bytes == 6); 242 | 243 | bytes = zpipes_client_read (reader, buffer, 1, 100); 244 | assert (bytes == 1); 245 | bytes = zpipes_client_read (reader, buffer, 10, 100); 246 | assert (bytes == 10); 247 | 248 | // Now close writer 249 | zpipes_client_destroy (&writer); 250 | 251 | // Expect end of pipe (short read) 252 | bytes = zpipes_client_read (reader, buffer, 50, 100); 253 | assert (bytes == 7); 254 | 255 | // Expect end of pipe (empty chunk) 256 | bytes = zpipes_client_read (reader, buffer, 50, 100); 257 | assert (bytes == 0); 258 | 259 | // Expect illegal action (EBADF) writing on reader 260 | bytes = zpipes_client_write (reader, "CHUNK1", 6, 100); 261 | assert (bytes == -1); 262 | assert (zpipes_client_error (reader) == EBADF); 263 | 264 | zpipes_client_destroy (&reader); 265 | zpipes_client_destroy (&writer); 266 | zactor_destroy (&server); 267 | 268 | // @end 269 | printf ("OK\n"); 270 | } 271 | -------------------------------------------------------------------------------- /src/zpipes_dump.c: -------------------------------------------------------------------------------- 1 | /* ========================================================================= 2 | zpipes_dump - dump state of all zpipes brokers on network 3 | Currently, dumps Zyre map for each broker. 4 | 5 | Copyright (c) the Contributors as noted in the AUTHORS file. 6 | This file is part of zbroker, the ZeroMQ broker project. 7 | 8 | This Source Code Form is subject to the terms of the Mozilla Public 9 | License, v. 2.0. If a copy of the MPL was not distributed with this 10 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 11 | ========================================================================= 12 | */ 13 | 14 | #include "zbroker_classes.h" 15 | 16 | int main (int argc, char *argv []) 17 | { 18 | // Set up Zyre cluster from command-line arguments 19 | zyre_t *node = zyre_new ("zpipes_dump"); 20 | if (argc == 2 && streq (argv [1], "beacon")) 21 | printf ("zpipes_dump: using default UDP beaconing to find brokers\n"); 22 | else 23 | if (argc == 4 && streq (argv [1], "gossip")) { 24 | printf ("zpipes_dump: using gossip discovery to find brokers\n"); 25 | printf (" - Zyre node endpoint=%s", argv [2]); 26 | zyre_set_endpoint (node, "%s", argv [2]); 27 | char *gossip_endpoint = argv [3]; 28 | if (*gossip_endpoint == '@') { 29 | gossip_endpoint++; 30 | zsys_info (" - gossip service bind to %s", gossip_endpoint); 31 | zyre_gossip_bind (node, "%s", gossip_endpoint); 32 | } 33 | else { 34 | zsys_info (" - gossip service connect to %s", gossip_endpoint); 35 | zyre_gossip_connect (node, "%s", gossip_endpoint); 36 | } 37 | } 38 | else { 39 | puts ("Usage: zpipes_dump [ beacon | gossip zyre-endpoint [@]gossip-endpoint ] "); 40 | puts (" Where @ means bind, else connect to gossip endpoint"); 41 | zyre_destroy (&node); 42 | return 0; 43 | } 44 | zyre_start (node); 45 | zyre_join (node, "ZPIPES"); 46 | zclock_sleep (100); 47 | zyre_shouts (node, "ZPIPES", "DUMP"); 48 | zclock_sleep (100); 49 | zyre_destroy (&node); 50 | 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /src/zpipes_msg.bnf: -------------------------------------------------------------------------------- 1 | The following ABNF grammar defines the ZPIPES protocol: 2 | 3 | ZPIPES = reader | writer 4 | 5 | reader = input-command *( read-command | ping-command ) 6 | close-command 7 | input-command = c:input ( s:input-ok | s:input-failed ) 8 | read-command = c:read ( s:read-ok | s:read-end 9 | | s:read-timeout | s:read-failed ) 10 | close-command = c:close ( s:close-ok | s:close-failed ) 11 | 12 | writer = output-command *write-command close-command 13 | output-command = c:output ( s:output-ok | s:output-failed ) 14 | write-command = c:write ( s:write-ok 15 | | s:write-timeout | s:write-failed ) 16 | ping-command = c:ping s:ping-ok 17 | 18 | ; Create a new pipe for reading 19 | input = signature %d1 pipename 20 | signature = %xAA %xA0 ; two octets 21 | pipename = string ; Name of pipe 22 | 23 | ; Input request was successful 24 | input_ok = signature %d2 25 | 26 | ; Input request failed 27 | input_failed = signature %d3 reason 28 | reason = string ; Reason for failure 29 | 30 | ; Create a new pipe for writing 31 | output = signature %d4 pipename 32 | pipename = string ; Name of pipe 33 | 34 | ; Output request was successful 35 | output_ok = signature %d5 36 | 37 | ; Output request failed 38 | output_failed = signature %d6 reason 39 | reason = string ; Reason for failure 40 | 41 | ; Read a chunk of data from pipe 42 | read = signature %d7 size timeout 43 | size = number-4 ; Number of bytes to read 44 | timeout = number-4 ; Timeout, msecs, or zero 45 | 46 | ; Read was successful 47 | read_ok = signature %d8 chunk 48 | chunk = chunk ; Chunk of data 49 | 50 | ; Pipe is closed, no more data 51 | read_end = signature %d9 52 | 53 | ; Read ended with timeout 54 | read_timeout = signature %d10 55 | 56 | ; Read failed due to error 57 | read_failed = signature %d11 reason 58 | reason = string ; Reason for failure 59 | 60 | ; Write chunk of data to pipe 61 | write = signature %d12 chunk timeout 62 | chunk = chunk ; Chunk of data 63 | timeout = number-4 ; Timeout, msecs, or zero 64 | 65 | ; Write was successful 66 | write_ok = signature %d13 67 | 68 | ; Write ended with timeout 69 | write_timeout = signature %d14 70 | 71 | ; Read failed due to error 72 | write_failed = signature %d15 reason 73 | reason = string ; Reason for failure 74 | 75 | ; Close pipe 76 | close = signature %d16 77 | 78 | ; Close was successful 79 | close_ok = signature %d17 80 | 81 | ; Close failed due to error 82 | close_failed = signature %d18 reason 83 | reason = string ; Reason for failure 84 | 85 | ; Signal liveness 86 | ping = signature %d19 87 | 88 | ; Respond to ping 89 | ping_ok = signature %d20 90 | 91 | ; Command was invalid at this time 92 | invalid = signature %d21 93 | 94 | ; A chunk has 4-octet length + binary contents 95 | chunk = number-4 *OCTET 96 | 97 | ; Strings are always length + text contents 98 | string = number-1 *VCHAR 99 | 100 | ; Numbers are unsigned integers in network byte order 101 | number-1 = 1OCTET 102 | number-4 = 4OCTET 103 | -------------------------------------------------------------------------------- /src/zpipes_msg.xml: -------------------------------------------------------------------------------- 1 | 8 | This is a codec for the ZPIPES protocol (RFC tbd) 9 | 10 | 11 | 12 | ZPIPES = reader | writer 13 | 14 | reader = input-command *( read-command | ping-command ) 15 | close-command 16 | input-command = c:input ( s:input-ok | s:input-failed ) 17 | read-command = c:read ( s:read-ok | s:read-end 18 | | s:read-timeout | s:read-failed ) 19 | close-command = c:close ( s:close-ok | s:close-failed ) 20 | 21 | writer = output-command *write-command close-command 22 | output-command = c:output ( s:output-ok | s:output-failed ) 23 | write-command = c:write ( s:write-ok 24 | | s:write-timeout | s:write-failed ) 25 | ping-command = c:ping s:ping-ok 26 | 27 | 28 | 29 | Create a new pipe for reading 30 | Name of pipe 31 | 32 | 33 | 34 | Input request was successful 35 | 36 | 37 | 38 | Input request failed 39 | Reason for failure 40 | 41 | 42 | 43 | Create a new pipe for writing 44 | Name of pipe 45 | 46 | 47 | 48 | Output request was successful 49 | 50 | 51 | 52 | Output request failed 53 | Reason for failure 54 | 55 | 56 | 57 | Read a chunk of data from pipe 58 | Number of bytes to read 59 | Timeout, msecs, or zero 60 | 61 | 62 | 63 | Read was successful 64 | Chunk of data 65 | 66 | 67 | 68 | Pipe is closed, no more data 69 | 70 | 71 | 72 | Read ended with timeout 73 | 74 | 75 | 76 | Read failed due to error 77 | Reason for failure 78 | 79 | 80 | 81 | Write chunk of data to pipe 82 | Chunk of data 83 | Timeout, msecs, or zero 84 | 85 | 86 | 87 | Write was successful 88 | 89 | 90 | 91 | Write ended with timeout 92 | 93 | 94 | 95 | Read failed due to error 96 | Reason for failure 97 | 98 | 99 | 100 | Close pipe 101 | 102 | 103 | 104 | Close was successful 105 | 106 | 107 | 108 | Close failed due to error 109 | Reason for failure 110 | 111 | 112 | 113 | Signal liveness 114 | 115 | 116 | 117 | Respond to ping 118 | 119 | 120 | 121 | Command was invalid at this time 122 | 123 | 124 | -------------------------------------------------------------------------------- /src/zpipes_server.xml: -------------------------------------------------------------------------------- 1 | 8 | This is a server implementation for the ZPIPES protocol 9 | 10 | 11 | 12 | 13 | Names of states, events, and actions are case insensitive. 14 | By convention however we use uppercase for protocol events. 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | In this internal state, we either have a reader immediately, or 60 | we get a wakeup event after the specified write timeout. 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | Reading from a pipe waits until there is sufficient data, or a timeout. 102 | In this state we can also close the pipe. 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | In this internal state, we either have data immediately, or a we are 127 | woken up after the specified read timeout, or the writer closed our 128 | pipe. 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | This superstate defines default handling for external states: 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | This superstate defines default handling for internal states: 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | -------------------------------------------------------------------------------- /src/zpipes_test_cluster.c: -------------------------------------------------------------------------------- 1 | /* ========================================================================= 2 | zpipes_test_cluster - test zpipes over a cluster 3 | 4 | Copyright (c) the Contributors as noted in the AUTHORS file. 5 | This file is part of zbroker, the ZeroMQ broker project. 6 | 7 | This Source Code Form is subject to the terms of the Mozilla Public 8 | License, v. 2.0. If a copy of the MPL was not distributed with this 9 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 10 | ========================================================================= 11 | */ 12 | 13 | #include "zbroker_classes.h" 14 | 15 | int main (void) 16 | { 17 | zsys_info ("zpipes_test_cluster: *** starting cluster tests ***"); 18 | 19 | zactor_t *green = zactor_new (zpipes_server, NULL); 20 | zstr_sendx (green, "BIND", "ipc://@/zpipes/green", NULL); 21 | zstr_sendx (green, "SET", "zyre/interval", "100", NULL); 22 | zstr_sendx (green, "SET", "zyre/nodeid", "green", NULL); 23 | 24 | // JOIN CLUSTER message always replies with OK/SNAFU 25 | zstr_sendx (green, "JOIN CLUSTER", NULL); 26 | char *reply = zstr_recv (green); 27 | 28 | // If the machine has no usable broadcast interface, the JOIN CLUSTER 29 | // command will fail, and then there's no point in continuing... 30 | if (strneq (reply, "OK")) { 31 | zclock_log ("W: skipping test, no UDP discovery"); 32 | free (reply); 33 | zactor_destroy (&green); 34 | return 0; 35 | } 36 | free (reply); 37 | 38 | zactor_t *orange = zactor_new (zpipes_server, NULL); 39 | zstr_sendx (orange, "BIND", "ipc://@/zpipes/orange", NULL); 40 | zstr_sendx (orange, "SET", "zyre/interval", "100", NULL); 41 | zstr_sendx (orange, "SET", "zyre/nodeid", "orange", NULL); 42 | 43 | // JOIN CLUSTER message always replies with OK/SNAFU 44 | zstr_sendx (orange, "JOIN CLUSTER", NULL); 45 | reply = zstr_recv (orange); 46 | assert (streq (reply, "OK")); 47 | free (reply); 48 | 49 | // Give time for cluster to interconnect 50 | zclock_sleep (250); 51 | 52 | byte buffer [100]; 53 | ssize_t bytes; 54 | 55 | // Test 1 - simple read-write 56 | zsys_info ("zpipes_test_cluster: open writer"); 57 | zpipes_client_t *writer = zpipes_client_new ("orange", ">test pipe"); 58 | 59 | zsys_info ("zpipes_test_cluster: open reader"); 60 | zpipes_client_t *reader = zpipes_client_new ("green", "test pipe"); 61 | 62 | // Expect timeout error, EAGAIN 63 | zsys_info ("zpipes_test_cluster: read impatiently"); 64 | bytes = zpipes_client_read (reader, buffer, 6, 200); 65 | assert (bytes == -1); 66 | assert (zpipes_client_error (reader) == EAGAIN); 67 | 68 | zsys_info ("zpipes_test_cluster: write to pipe"); 69 | bytes = zpipes_client_write (writer, "Hello, World", 12, 0); 70 | assert (bytes == 12); 71 | 72 | zsys_info ("zpipes_test_cluster: read from pipe"); 73 | bytes = zpipes_client_read (reader, buffer, 12, 0); 74 | assert (bytes == 12); 75 | 76 | zsys_info ("zpipes_test_cluster: write three chunks"); 77 | bytes = zpipes_client_write (writer, "CHUNK1", 6, 200); 78 | assert (bytes == 6); 79 | bytes = zpipes_client_write (writer, "CHUNK2", 6, 200); 80 | assert (bytes == 6); 81 | bytes = zpipes_client_write (writer, "CHUNK3", 6, 200); 82 | assert (bytes == 6); 83 | 84 | zsys_info ("zpipes_test_cluster: read two chunks"); 85 | bytes = zpipes_client_read (reader, buffer, 1, 200); 86 | assert (bytes == 1); 87 | bytes = zpipes_client_read (reader, buffer, 10, 200); 88 | assert (bytes == 10); 89 | 90 | zsys_info ("zpipes_test_cluster: close writer"); 91 | zpipes_client_destroy (&writer); 92 | 93 | // Expect end of pipe (short read) 94 | zsys_info ("zpipes_test_cluster: read short"); 95 | bytes = zpipes_client_read (reader, buffer, 50, 200); 96 | assert (bytes == 7); 97 | 98 | // Expect end of pipe (empty chunk) 99 | zsys_info ("zpipes_test_cluster: read end of pipe"); 100 | bytes = zpipes_client_read (reader, buffer, 50, 200); 101 | assert (bytes == 0); 102 | 103 | // Expect illegal action (EBADF) writing on reader 104 | zsys_info ("zpipes_test_cluster: try to write on reader"); 105 | bytes = zpipes_client_write (reader, "CHUNK1", 6, 200); 106 | assert (bytes == -1); 107 | assert (zpipes_client_error (reader) == EBADF); 108 | 109 | zsys_info ("zpipes_test_cluster: close reader"); 110 | zpipes_client_destroy (&reader); 111 | 112 | // Test 2 - pipe reuse 113 | zsys_info ("zpipes_test_cluster: open reader"); 114 | reader = zpipes_client_new ("green", "test pipe 2"); 115 | 116 | zsys_info ("zpipes_test_cluster: open writer"); 117 | writer = zpipes_client_new ("orange", ">test pipe 2"); 118 | 119 | zsys_info ("zpipes_test_cluster: close reader"); 120 | zpipes_client_destroy (&reader); 121 | 122 | zsys_info ("zpipes_test_cluster: close writer"); 123 | zpipes_client_destroy (&writer); 124 | 125 | zsys_info ("zpipes_test_cluster: open reader reusing pipe name"); 126 | reader = zpipes_client_new ("green", "test pipe 2"); 127 | zpipes_client_destroy (&reader); 128 | 129 | zactor_destroy (&green); 130 | zactor_destroy (&orange); 131 | zsys_info ("zpipes_test_cluster: *** ending cluster tests ***"); 132 | return 0; 133 | } 134 | -------------------------------------------------------------------------------- /version.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # This script extracts the version from the project header file 4 | # 5 | project=$1 6 | if [ ! -f include/$project.h ]; then 7 | echo "version.sh: error: include/$project.h does not exist" 1>&2 8 | exit 1 9 | fi 10 | MAJOR=`egrep '^#define .*_VERSION_MAJOR +[0-9]+$' include/$project.h` 11 | MINOR=`egrep '^#define .*_VERSION_MINOR +[0-9]+$' include/$project.h` 12 | PATCH=`egrep '^#define .*_VERSION_PATCH +[0-9]+$' include/$project.h` 13 | if [ -z "$MAJOR" -o -z "$MINOR" -o -z "$PATCH" ]; then 14 | echo "version.sh: error: could not extract version from include/$project.h" 1>&2 15 | exit 1 16 | fi 17 | MAJOR=`echo $MAJOR | awk '{ print $3 }'` 18 | MINOR=`echo $MINOR | awk '{ print $3 }'` 19 | PATCH=`echo $PATCH | awk '{ print $3 }'` 20 | echo $MAJOR.$MINOR.$PATCH | tr -d '\n' 21 | 22 | --------------------------------------------------------------------------------