├── .gitignore ├── CONTRIBUTING.md ├── LICENSE.txt ├── README.md ├── compile_list.m ├── config.m ├── config_unix.m ├── config_win.m ├── examples ├── collector.m ├── consumer.m ├── producer.m ├── pub_server.m └── sub_client.m ├── lib └── +zmq │ ├── +core │ ├── bind.m │ ├── close.m │ ├── connect.m │ ├── ctx_get.m │ ├── ctx_new.m │ ├── ctx_set.m │ ├── ctx_shutdown.m │ ├── ctx_term.m │ ├── disconnect.m │ ├── getsockopt.m │ ├── recv.m │ ├── send.m │ ├── setsockopt.m │ ├── socket.m │ ├── unbind.m │ └── version.m │ ├── @Context │ ├── Context.m │ ├── get.m │ ├── get_ptr.m │ ├── normalize_const_name.m │ ├── set.m │ ├── socket.m │ └── term.m │ └── @Socket │ ├── Socket.m │ ├── bind.m │ ├── close.m │ ├── connect.m │ ├── disconnect.m │ ├── get.m │ ├── normalize_const_name.m │ ├── normalize_msg_options.m │ ├── recv.m │ ├── recv_multipart.m │ ├── recv_string.m │ ├── send.m │ ├── send_multipart.m │ ├── send_string.m │ ├── set.m │ └── unbind.m ├── make.m ├── src ├── core │ ├── bind.c │ ├── close.c │ ├── connect.c │ ├── ctx_get.c │ ├── ctx_new.c │ ├── ctx_set.c │ ├── ctx_shutdown.c │ ├── ctx_term.c │ ├── disconnect.c │ ├── getsockopt.c │ ├── recv.c │ ├── send.c │ ├── setsockopt.c │ ├── socket.c │ ├── unbind.c │ └── version.c └── util │ ├── conversions.c │ ├── conversions.h │ ├── errors.c │ ├── errors.h │ ├── socket.c │ ├── socket.h │ ├── sockopt.c │ └── sockopt.h └── tests ├── fixtures ├── utf8-sampler.html └── wikipedia.html ├── runner.m ├── support ├── assert_does_not_throw.m ├── assert_throw.m └── text_fixture.m ├── test_context_cleanup.m ├── test_context_get.m ├── test_socket_bind.m ├── test_socket_connect.m ├── test_socket_get.m ├── test_socket_send_recv.m ├── test_socket_send_recv_multipart.m ├── test_socket_send_recv_string.m ├── test_socket_set.m ├── test_zmq_bind.m ├── test_zmq_connect.m ├── test_zmq_ctx_get.m ├── test_zmq_getsockopt.m ├── test_zmq_req_rep.m ├── test_zmq_req_rep_multipart.m ├── test_zmq_setsockopt.m ├── test_zmq_socket.m └── test_zmq_version.m /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by http://www.gitignore.io 2 | 3 | ### OSX ### 4 | .DS_Store 5 | .AppleDouble 6 | .LSOverride 7 | 8 | # Icon must end with two \r 9 | Icon 10 | 11 | # Thumbnails 12 | ._* 13 | 14 | # Files that might appear on external disk 15 | .Spotlight-V100 16 | .Trashes 17 | 18 | # Directories potentially created on remote AFP share 19 | .AppleDB 20 | .AppleDesktop 21 | Network Trash Folder 22 | Temporary Items 23 | .apdisk 24 | 25 | 26 | ### vim ### 27 | [._]*.s[a-w][a-z] 28 | [._]s[a-w][a-z] 29 | *.un~ 30 | Session.vim 31 | .netrwhist 32 | *~ 33 | 34 | 35 | ### Matlab ### 36 | ##--------------------------------------------------- 37 | ## Remove autosaves generated by the Matlab editor 38 | ## We have git for backups! 39 | ##--------------------------------------------------- 40 | 41 | # Windows default autosave extension 42 | *.asv 43 | 44 | # OSX / *nix default autosave extension 45 | *.m~ 46 | 47 | # Compiled MEX binaries (all platforms) 48 | *.mex* 49 | 50 | # Simulink Code Generation 51 | slprj/ 52 | 53 | 54 | ### C ### 55 | # Object files 56 | *.o 57 | *.ko 58 | *.obj 59 | *.elf 60 | 61 | # Libraries 62 | *.lib 63 | *.a 64 | 65 | # Shared objects (inc. Windows DLLs) 66 | *.dll 67 | *.so 68 | *.so.* 69 | *.dylib 70 | 71 | # Executables 72 | *.exe 73 | *.out 74 | *.app 75 | *.i*86 76 | *.x86_64 77 | *.hex 78 | 79 | 80 | *.TMP -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Coding Guidelines 2 | 3 | * Use 4 spaces for identation 4 | * Variables should be javaCase with functions_underscored_like_so 5 | 6 | ### C Code 7 | 8 | * [K&R style](http://en.wikipedia.org/wiki/Indent_style#K.26R_style) for bracing 9 | * Traditional C style for comments (i.e. `/*` and `*/`) no matter how long they are. 10 | * One-line conditionals are discouraged, e.g. 11 | ```c 12 | /* bad: */ 13 | if (this) do_that(); 14 | else do_something_else(); 15 | 16 | /* good: */ 17 | if (this) 18 | do_that(); 19 | else 20 | do_something_else(); 21 | 22 | /* good: */ 23 | if (this) { 24 | do_that(); 25 | } else { 26 | do_something_else(); 27 | } 28 | ``` 29 | 30 | ### MATLAB Code 31 | 32 | * Condition statements must be wrapped in braces. 33 | This makes the code easier to read in that it makes control flow stand out, e.g. 34 | ```matlab 35 | if (foo == 1) % rather than if foo == 1 36 | ``` 37 | * One-line conditionals are discouraged, e.g. 38 | ```matlab 39 | % bad: 40 | if (this), do_that(), end; 41 | 42 | % good: 43 | if (this) 44 | do_that(); 45 | end 46 | ``` 47 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | matlab-zmq 2 | ========== 3 | 4 | What's this all about? 5 | ---------------------- 6 | 7 | This API aims to bring the awesome of ZMQ to MATLAB. This project has grown out @fagg wanting to 8 | better manage large scale numerical computing experiments across a High Performance Cluster. However, 9 | this library can be used in any number of contexts across any number of machines (even 1 is OK). 10 | 11 | 12 | Getting Started 13 | --------------- 14 | + Make sure you have ZMQ 4.0.x installed. Change settings in `config.m` to point to your installation. 15 | + Ensure you have mex configured [[1]](http://www.mathworks.com/help/matlab/matlab_external/what-you-need-to-build-mex-files.html) [[2]](http://www.mathworks.com/support/compilers/R2014b/index.html) 16 | + Run `make.m` 17 | + Make sure that the `lib` directory is on your MATLAB path. 18 | + Start hacking. 19 | 20 | Stuff Doesn't Work 21 | ------------------ 22 | 23 | - Git pull master - make clean; make; make test. Try again. 24 | - Try the dev branch. See if that works. 25 | - If not, open an issue and include the following information: 26 | - Versions: MATLAB, ZMQ and Operating System 27 | - Which version of matlab-zmq you're using (i.e. which branch, commit etc). 28 | - What you are trying to do - preferably include a succinct code example which illustrates the problem. 29 | - What doesn't work - please describe behaviour explicitly and include any error messages you encounter. 30 | 31 | How can I help? 32 | ----------- 33 | 34 | Pull requests are most welcome. As a general rule, please base all pull requests in master. If in doubt, contact @fagg. 35 | 36 | Development Team 37 | ----------------------- 38 | 39 | - Ashton Fagg (@fagg) 40 | - Anderson Bravalheri (@abravalheri) 41 | 42 | Contributors 43 | ------------ 44 | 45 | This project contains contributions from the following people: 46 | 47 | - Ashton Fagg (@fagg) 48 | - Anderson Bravalheri (@abravalheri) 49 | - Matheus Svolenski (@msvolenski) 50 | 51 | -------------------------------------------------------------------------------- /compile_list.m: -------------------------------------------------------------------------------- 1 | % List of files to be compiled 2 | % 3 | % A simple string entry indicates that are no dependencies. 4 | % 5 | % If a entry of type `cell` (nested list) is found, the first string represents 6 | % the __main__ file, and the others represent dependencies to be compiled 7 | % together with the __main__ file. 8 | 9 | COMPILE_LIST = { ... 10 | 'version.c', ... 11 | 'ctx_new.c', ... 12 | 'ctx_term.c', ... 13 | 'ctx_shutdown.c', ... 14 | 'ctx_get.c', ... 15 | 'ctx_set.c', ... 16 | 'socket.c', ... 17 | {'close.c' , 'util/conversions.c', 'util/socket.c' , 'util/errors.c'} ... 18 | {'bind.c' , 'util/conversions.c', 'util/socket.c' , 'util/errors.c'} ... 19 | {'unbind.c' , 'util/conversions.c', 'util/socket.c' , 'util/errors.c'} ... 20 | {'connect.c' , 'util/conversions.c', 'util/socket.c' , 'util/errors.c'} ... 21 | {'disconnect.c', 'util/conversions.c', 'util/socket.c' , 'util/errors.c'} ... 22 | {'getsockopt.c', 'util/conversions.c', 'util/sockopt.c', 'util/socket.c', 'util/errors.c'} ... 23 | {'setsockopt.c', 'util/conversions.c', 'util/sockopt.c', 'util/socket.c', 'util/errors.c'} ... 24 | {'send.c' , 'util/conversions.c', 'util/socket.c' , 'util/errors.c'} ... 25 | {'recv.c' , 'util/conversions.c', 'util/socket.c' , 'util/errors.c'} ... 26 | }; 27 | -------------------------------------------------------------------------------- /config.m: -------------------------------------------------------------------------------- 1 | % Please edit this file with the correct paths for ZMQ instalation. 2 | % 3 | % Examples can be found in files `config_unix.m`, `config_win.m`. 4 | % This file itself shows how to build `matlab-zmq` using a Homebrew 5 | % installation of ZMQ 4.0.4 for OS-X. 6 | 7 | % ZMQ library filename 8 | ZMQ_COMPILED_LIB = './libzmq.a'; 9 | 10 | % ZMQ library path 11 | ZMQ_LIB_PATH = '/usr/local/Cellar/zeromq/4.0.4/lib/'; 12 | 13 | % ZMQ headers path 14 | ZMQ_INCLUDE_PATH = '/usr/local/Cellar/zeromq/4.0.4/include/'; 15 | -------------------------------------------------------------------------------- /config_unix.m: -------------------------------------------------------------------------------- 1 | % ZMQ library filename 2 | ZMQ_COMPILED_LIB = 'libzmq.a'; 3 | 4 | % ZMQ library path 5 | ZMQ_LIB_PATH = '/usr/local/lib/'; 6 | 7 | % ZMQ headers path 8 | ZMQ_INCLUDE_PATH = '/usr/local/include/'; -------------------------------------------------------------------------------- /config_win.m: -------------------------------------------------------------------------------- 1 | % The filename for the compiled lib (binary file) 2 | % 3 | % Please refer http://zeromq.org/distro:microsoft-windows to find the correct 4 | % binary for your SO version. 5 | ZMQ_COMPILED_LIB = 'libzmq-v120-mt-4_0_4.lib'; 6 | 7 | % ZMQ library path 8 | ZMQ_LIB_PATH = 'C:\Program Files\ZeroMQ 4.0.4\lib\'; 9 | 10 | % ZMQ headers path 11 | ZMQ_INCLUDE_PATH = 'C:\Program Files\ZeroMQ 4.0.4\include'; -------------------------------------------------------------------------------- /examples/collector.m: -------------------------------------------------------------------------------- 1 | function collector 2 | % A collector receive the results sent from workers and aggregate them. 3 | % 4 | % Example borrowed from 5 | % http://learning-0mq-with-pyzmq.readthedocs.org/en/latest/pyzmq/patterns/pushpull.html 6 | 7 | context = zmq.core.ctx_new(); 8 | socket = zmq.core.socket(context, 'ZMQ_PULL'); 9 | address = 'tcp://127.0.0.1:5558'; 10 | zmq.core.bind(socket, address); 11 | 12 | total = 0; 13 | for x = 1:50 14 | result = sscanf(char(zmq.core.recv(socket)), '%d %d'); 15 | fprintf('data received from consumer#%d: %d\n', result(1), result(2)); 16 | total = total + result(2); 17 | end 18 | 19 | fprintf('\nTotal: %d\n', total); 20 | 21 | zmq.core.disconnect(socket, address); 22 | zmq.core.close(socket); 23 | 24 | zmq.core.ctx_shutdown(context); 25 | zmq.core.ctx_term(context); 26 | end 27 | -------------------------------------------------------------------------------- /examples/consumer.m: -------------------------------------------------------------------------------- 1 | function consumer 2 | % A consumer can attend requests from a producer and send the result to a collector. 3 | % 4 | % To receive work, it uses a PULL socket, and to send the result it uses a PUSH socket. 5 | % 6 | % Example borrowed from 7 | % http://learning-0mq-with-pyzmq.readthedocs.org/en/latest/pyzmq/patterns/pushpull.html 8 | 9 | id = randi([1, 10005], 1, 1); 10 | fprintf('I am consumer #%d', id); 11 | 12 | context = zmq.core.ctx_new(); 13 | % recieve work 14 | rx = zmq.core.socket(context, 'ZMQ_PULL'); 15 | producerAddress = 'tcp://127.0.0.1:5557'; 16 | zmq.core.connect(rx, producerAddress); 17 | % send results 18 | tx = zmq.core.socket(context, 'ZMQ_PUSH'); 19 | collectorAddress = 'tcp://127.0.0.1:5558'; 20 | zmq.core.connect(tx, collectorAddress); 21 | 22 | while (1) 23 | data = str2double(char(zmq.core.recv(rx))); 24 | if (mod(data, 2) == 0) 25 | result = sprintf('%d %d', id, data); 26 | zmq.core.send(tx, uint8(result)); 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /examples/producer.m: -------------------------------------------------------------------------------- 1 | function producer 2 | % A Push socket will distribute sent messages to its Pull clients evenly 3 | % 4 | % Example borrowed from 5 | % http://learning-0mq-with-pyzmq.readthedocs.org/en/latest/pyzmq/patterns/pushpull.html 6 | 7 | context = zmq.core.ctx_new(); 8 | socket = zmq.core.socket(context, 'ZMQ_PUSH'); 9 | address = 'tcp://127.0.0.1:5557'; 10 | zmq.core.bind(socket, address); 11 | 12 | % NOICE: Start your result manager and workers before you start your producers 13 | for num = 1:100 14 | zmq.core.send(socket, uint8(num2str(num))); 15 | end 16 | 17 | zmq.core.disconnect(socket, address); 18 | zmq.core.close(socket); 19 | 20 | zmq.core.ctx_shutdown(context); 21 | zmq.core.ctx_term(context); 22 | end 23 | -------------------------------------------------------------------------------- /examples/pub_server.m: -------------------------------------------------------------------------------- 1 | function pub_server(varargin) 2 | % Super reliable weather information server 3 | % 4 | % Example borrowed from 5 | % http://learning-0mq-with-pyzmq.readthedocs.org/en/latest/pyzmq/patterns/pubsub.html 6 | % 7 | % This weather server will broadcast messages consisting of two integers 8 | % separated by a space, the first one is the CEP (ZIP brazilian equivalent) 9 | % and the second is the temperature in celsius 10 | 11 | port = 5556; 12 | if (nargin > 0) 13 | port = varargin{1}; 14 | end 15 | 16 | context = zmq.core.ctx_new(); 17 | socket = zmq.core.socket(context, 'ZMQ_PUB'); 18 | zmq.core.bind(socket, sprintf('tcp://*:%d', port)); 19 | 20 | fprintf('Broadcasting temperature information...\n'); 21 | while (1) 22 | topic = randi([15198, 15202], 1, 1); % Choose a brazilian CEP code (first 5 digits) 23 | data = randi([10, 45]); % Pick a random temperature 24 | message = sprintf('%d %d', topic, data); 25 | fprintf('%s\n', message); 26 | zmq.core.send(socket, uint8(message)); 27 | delay(1); 28 | end 29 | end 30 | 31 | function delay(seconds) 32 | % pause the program 33 | % 34 | % Aguments: 35 | % seconds - delay time in seconds 36 | tic; 37 | while toc < seconds 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /examples/sub_client.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fagg/matlab-zmq/7788c39b3fc206e63ad1e26cf044a40447025b91/examples/sub_client.m -------------------------------------------------------------------------------- /lib/+zmq/+core/bind.m: -------------------------------------------------------------------------------- 1 | % zmq.core.bind - Binds the socket to a local endpoint and then accepts incoming 2 | % connections on that endpoint. 3 | % 4 | % Usage: status = zmq.core.bind(socket, endpoint) 5 | % 6 | % Input: socket - Instantiated ZMQ socket handle (see zmq.core.socket). 7 | % endpoint - String consisting of a 'transport://' followed by an 'address'. 8 | % The transport specifies the underlying protocol to use. 9 | % The address specifies the transport-specific address to bind to. 10 | % 11 | % ZMQ provides the the following transports: 12 | % 13 | % * tcp - unicast transport using TCP 14 | % * ipc - local inter-process communication transport 15 | % * inproc - local in-process (inter-thread) communication transport 16 | % * pgm, epgm - reliable multicast transport using PGM 17 | % 18 | % Please refer to http://api.zeromq.org/4-0:zmq-bind for further information. 19 | % 20 | % Output: Zero if successful, otherwise -1. 21 | % 22 | -------------------------------------------------------------------------------- /lib/+zmq/+core/close.m: -------------------------------------------------------------------------------- 1 | % zmq.core.close- Close a ZMQ socket 2 | % 3 | % Usage: status = zmq.core.close(socket) 4 | % 5 | % Input: socket - Instantiated ZMQ socket handle to be closed (see zmq.core.socket). 6 | % 7 | % Output: Zero if successful, otherwise -1. 8 | % 9 | -------------------------------------------------------------------------------- /lib/+zmq/+core/connect.m: -------------------------------------------------------------------------------- 1 | % zmq.core.bind - Create outgoing connection from socket on a endpoint. 2 | % 3 | % Usage: status = zmq.core.connect(socket, endpoint) 4 | % 5 | % Input: socket - Instantiated ZMQ socket handle (see zmq.core.socket). 6 | % endpoint - String consisting of a 'transport://' followed by an 'address'. 7 | % The 'transport' specifies the underlying protocol to use. 8 | % The address specifies the transport-specific address to connect to. 9 | % 10 | % ZMQ provides the the following transports: 11 | % 12 | % * tcp - unicast transport using TCP 13 | % * ipc - local inter-process communication transport 14 | % * inproc - local in-process (inter-thread) communication transport 15 | % * pgm, epgm - reliable multicast transport using PGM 16 | % 17 | % Please refer to http://api.zeromq.org/4-0:zmq-connect for further information. 18 | % 19 | % Output: Zero if successful, otherwise -1. 20 | % 21 | -------------------------------------------------------------------------------- /lib/+zmq/+core/ctx_get.m: -------------------------------------------------------------------------------- 1 | % zmq.core.ctx_get - Mex function for interacting with ZMQ Contexts. 2 | % 3 | % Usage: output = zmq.core.ctx_get(context, option_name) 4 | % 5 | % Input: context - Instantiated ZMQ context handle (see zmq.core.ctx_new). 6 | % option_name - Option string. Must be one of the following: 7 | % * ZMQ_IO_THREADS - Number of I/O threads in context thread pool. 8 | % * ZMQ_MAX_SOCKETS - Maximum number of sockets allowed on context. 9 | % * ZMQ_IPV6 - IPv6 option. 10 | % 11 | % Output: output - Depending on the option_string, output will be either numeric 12 | % (ZMQ_IO_THREADS and ZMQ_MAX_SOCKETS) or boolean (ZMQ_IPV6). 13 | -------------------------------------------------------------------------------- /lib/+zmq/+core/ctx_new.m: -------------------------------------------------------------------------------- 1 | % zmq.core.ctx_new - Create new context for use with ZMQ functions 2 | % 3 | % Usage: context = zmq.core.ctx_new 4 | % 5 | % Input: None 6 | % 7 | % Output: Handle to the instantiated ZMQ context 8 | -------------------------------------------------------------------------------- /lib/+zmq/+core/ctx_set.m: -------------------------------------------------------------------------------- 1 | % zmq.core.ctx_set - Mex function for setting ZMQ context options. Complementary to zmq.core.ctx_get. 2 | % 3 | % Usage: zmq.core.ctx_set(context, option_name, option_value). 4 | % 5 | % Input: context - Instantiated ZMQ context handle (see zmq.core.ctx_new). 6 | % option_name - Option string. Must be one of the following: 7 | % * ZMQ_IO_THREADS - Number of I/O threads in context thread pool. 8 | % * ZMQ_MAX_SOCKETS - Maximum number of sockets allowed on context. 9 | % * ZMQ_IPV6 - IPv6 option. 10 | % option_value - Numerical value to which option_name is to be set. Exception will be 11 | % thrown should this fail. 12 | % 13 | % Output: None. 14 | -------------------------------------------------------------------------------- /lib/+zmq/+core/ctx_shutdown.m: -------------------------------------------------------------------------------- 1 | % zmq.core.ctx_shutdown - Shutdown a ZMQ context. 2 | % 3 | % Usage: zmq.core.ctx_shutdown(context) 4 | % 5 | % Input: context - Instantiated ZMQ context handle (see zmq.core.ctx_new). 6 | % 7 | % Output: None. 8 | -------------------------------------------------------------------------------- /lib/+zmq/+core/ctx_term.m: -------------------------------------------------------------------------------- 1 | % zmq.core.ctx_term - Destroy ZMQ context. 2 | % 3 | % Usage: zmq.core.ctx_term(context) 4 | % 5 | % Input: context - Instantiated ZMQ context (see zmq.core.context_new). 6 | % 7 | % Output: None. 8 | 9 | -------------------------------------------------------------------------------- /lib/+zmq/+core/disconnect.m: -------------------------------------------------------------------------------- 1 | % zmq.core.disconnect - Disconnect a socket from a endpoint 2 | % 3 | % Usage: status = zmq.core.disconnect(socket, endpoint) 4 | % 5 | % Input: socket - Instantiated ZMQ socket handle (see zmq.core.socket). 6 | % endpoint - String consisting of a 'transport://' followed by an 'address'. 7 | % (see zmq.core.connect). 8 | % 9 | % Output: Zero if successful, otherwise -1. 10 | % 11 | -------------------------------------------------------------------------------- /lib/+zmq/+core/getsockopt.m: -------------------------------------------------------------------------------- 1 | % zmq.core.getsockopt - Retrieve ZMQ socket options. Complementary to zmq.core.setsockopt. 2 | % 3 | % Usage: optvalue = zmq.core.getsockopt(socket, option_name). 4 | % 5 | % Input: socket - Instantiated ZMQ socket handle (see zmq.core.socket). 6 | % option_name - Option string. Please refer to http://api.zeromq.org/master:zmq-getsockopt 7 | % for a complete description. Examples: 8 | % * ZMQ_TYPE: Retrieve socket type 9 | % * ZMQ_BACKLOG: Retrieve maximum length of the queue of outstanding connections 10 | % * ZMQ_IPV6: Retrieve IPv6 socket status 11 | % 12 | % Output: Current value for socket option. 13 | -------------------------------------------------------------------------------- /lib/+zmq/+core/recv.m: -------------------------------------------------------------------------------- 1 | % zmq.core.recv - Receive a message part from a socket. 2 | % 3 | % Usage: message = zmq.core.recv(socket) 4 | % message = zmq.core.recv(socket, bufferLength) 5 | % message = zmq.core.recv(socket, option1, option2, ...) 6 | % message = zmq.core.recv(socket, bufferLength, option1, option2, ...) 7 | % [msg, len] = zmq.core.recv(socket) 8 | % 9 | % Input: socket - Instantiated ZMQ socket handle (see zmq.core.socket). 10 | % bufferLength - Size in bytes of buffer pre-allocated to receive message. 11 | % This parameter is optional with default value of 255. 12 | % options - List of strings containing the options' names for reception. 13 | % 14 | % Output: uint8 array containing binary data received. If a second output is required, 15 | % the length of the message will be provided. 16 | % 17 | % An application that processes multi-part messages must check the 'ZMQ_RCVMORE' 18 | % option with `zmq.core.getsockopt` after calling `zmq.core.recv` to determine if there 19 | % are further parts to receive. 20 | % 21 | % The following options are considered valid: 22 | % 23 | % * ZMQ_DONTWAIT 24 | % Specifies that the operation should be performed in non-blocking mode. 25 | % If there are no messages available on the specified socket, the 26 | % zmq.core.recv() function shall fail with zmq:core:recv:EAGAIN error code. 27 | % 28 | % 29 | % NOTICE 30 | % - The message received should be a uint8 row vector. Please consider using 31 | % `char`, `cast` and `typecast` functions before using it. Make sure to know 32 | % what is the transmitter encoding when receiveing strings, so you can use 33 | % conversions if they're neeeded, for example: 34 | % `unicode2native(str, 'UTF-8')` or 35 | % `feature('DefaultCharacterSet', 'UTF-8')`. 36 | % - If the pre-allocated buffer is shorter than the message received, the returned 37 | % vector will be truncated and a `zmq:core:recv:bufferTooSmall` warning will be thrown. 38 | % 39 | % EXAMPLE 40 | % feature('DefaultCharacterSet', 'UTF-8'); 41 | % try 42 | % message1 = zmq.core.recv(socket, 100, 'ZMQ_DONTWAIT'); 43 | % % maximum size of message1: 100 bytes 44 | % fprintf('Received message1: %s\n', char(message1)); 45 | % message2 = zmq.core.recv(socket, 'ZMQ_DONTWAIT'); 46 | % % maximum size of message2: 255 bytes 47 | % fprintf('Received message2: %s\n', char(message2)); 48 | % catch e 49 | % if strcmp(e.identifier, 'zmq:core:recv:EAGAIN') 50 | % fprintf('No message available.\n'); 51 | % else 52 | % rethrow(e); 53 | % end 54 | % end 55 | % message3 = zmq.core.recv(socket); % this will block MATLAB until receive a message 56 | % % maximum size of message3: 255 bytes 57 | % fprintf('Received message3: %s\n', char(message3)); 58 | % 59 | % Please refer to http://api.zeromq.org/4-0:zmq-recv for further information. 60 | % 61 | -------------------------------------------------------------------------------- /lib/+zmq/+core/send.m: -------------------------------------------------------------------------------- 1 | % zmq.core.send - Send a message part on a socket. 2 | % 3 | % Usage: msgLen = zmq.core.send(socket, message) 4 | % msgLen = zmq.core.send(socket, message) 5 | % msgLen = zmq.core.send(socket, message, option1, ...) 6 | % msgLen = zmq.core.send(socket, message, option1, option2, ...) 7 | % 8 | % Input: socket - Instantiated ZMQ socket handle (see zmq.core.socket). 9 | % message - uint8 array containing binary data to be queued for transmission 10 | % options - List of strings containing the options' names for transmission. 11 | % Output: number of bytes in the message if successful, otherwise -1. 12 | % 13 | % If the message cannot be queued on the socket, the zmq.core.send() function shall 14 | % fail with zmq:core:send:EAGAIN error code. 15 | % 16 | % The following options are considered valid: 17 | % 18 | % * ZMQ_DONTWAIT 19 | % For socket types (DEALER, PUSH) that block when there are no available peers 20 | % (or all peers have full high-water mark), specifies that the operation should 21 | % be performed in non-blocking mode. 22 | % * ZMQ_SNDMORE 23 | % Specifies that the message being sent is a multi-part message, and that 24 | % further message parts are to follow. 25 | % 26 | % 27 | % NOTICE 28 | % - A successful invocation of zmq.core.send() does not indicate that the message 29 | % has been transmitted to the network, only that it has been queued on the 30 | % socket and ZMQ has assumed responsibility for the message. 31 | % - The message to be sent should be a uint8 row vector. It's recommended that 32 | % you use functions like `uint8`, `cast` and `typecast` before send it. When 33 | % sending scripts, it's also recommended that you ensure the use of UTF-8 encoding. 34 | % You can do by this using, for example: 35 | % `native2unicode(str, 'UTF-8')` or 36 | % `feature('DefaultCharacterSet', 'UTF-8')`. 37 | % - Consider splitting long messages in shorter parts by using 'ZMQ_SNDMORE' option 38 | % to avoid truncating them, due to the buffer length set in the receiver. 39 | % 40 | % EXAMPLE 41 | % feature('DefaultCharacterSet', 'UTF-8'); 42 | % % Send a multi-part message consisting of three parts to socket 43 | % rc = zmq.core.send(socket, uint8('ABC'), 'ZMQ_SNDMORE'); 44 | % assert(rc == 3); 45 | % rc = zmq.core.send(socket, uint8('DEFGH'), 'ZMQ_SNDMORE'); 46 | % assert(rc == 5); 47 | % % Final part; no more parts to follow 48 | % rc = zmq.core.send(socket, uint8('IJ')); 49 | % assert (rc == 2); 50 | % 51 | % Please refer to http://api.zeromq.org/4-0:zmq-send for further information. 52 | % 53 | -------------------------------------------------------------------------------- /lib/+zmq/+core/setsockopt.m: -------------------------------------------------------------------------------- 1 | % zmq.core.setsockopt - Set ZMQ socket options. Complementary to zmq.core.getsockopt. 2 | % 3 | % Usage: status = zmq.core.getsockopt(socket, optionName, optionValue). 4 | % 5 | % Input: socket - Instantiated ZMQ socket handle (see zmq.core.socket). 6 | % optionName - Option string. Please refer to http://api.zeromq.org/master:zmq-setsockopt 7 | % for a complete description. Examples: 8 | % * ZMQ_TYPE: Retrieve socket type 9 | % * ZMQ_BACKLOG: Retrieve maximum length of the queue of outstanding connections 10 | % * ZMQ_IPV6: Retrieve IPv6 socket status 11 | % optionValue - New value for option. Please refer to http://api.zeromq.org/master:zmq-setsockopt 12 | % for a complete description. 13 | % 14 | % Output: Zero if successful, otherwise -1 . 15 | -------------------------------------------------------------------------------- /lib/+zmq/+core/socket.m: -------------------------------------------------------------------------------- 1 | % zmq.core.ctx_new - Create a ZMQ socket 2 | % 3 | % Usage: socket = zmq.core.socket(context, type) 4 | % 5 | % Input: context - Instantiated ZMQ context handle (see zmq.core.ctx_new). 6 | % type - type string of messaging pattern to be executed by this socket. 7 | % Please refer to http://api.zeromq.org/master:zmq-socket for a 8 | % complete description. Examples:7 9 | % * ZMQ_REQ: used by a client to send requests to and receive replies from a service 10 | % * ZMQ_REP: used by a service to receive requests from and send replies to a client 11 | % * ZMQ_PUB: used by a publisher to distribute data. Messages sent are distributed 12 | % in a fan out fashion to all connected peers. 13 | % * ZMQ_SUB: used by a subscriber to subscribe to data distributed by a publisher. 14 | % Initially a ZMQ_SUB socket is not subscribed to any messages, 15 | % use the ZMQ_SUBSCRIBE option of zmq.core.setsockopt to specify which 16 | % messages to subscribe to. 17 | % 18 | % Output: Handle to the newly created socket, unbound, and not associated with endpoints. 19 | % In order to establish a message flow a socket must first be connected to at least one 20 | % endpoint (see zmq.core.connect), or at least one endpoint must be created for accepting 21 | % incoming connections with (see zmq.core.bind). 22 | -------------------------------------------------------------------------------- /lib/+zmq/+core/unbind.m: -------------------------------------------------------------------------------- 1 | % zmq.core.unbind - Stop accepting connections on a socket from a endpoint 2 | % 3 | % Usage: status = zmq.core.unbind(socket, endpoint) 4 | % 5 | % Input: socket - Instantiated ZMQ socket handle (see zmq.core.socket). 6 | % endpoint - String consisting of a 'transport://' followed by an 'address'. 7 | % (see zmq.core.bind). 8 | % 9 | % Output: Zero if successful, otherwise -1. 10 | % 11 | -------------------------------------------------------------------------------- /lib/+zmq/+core/version.m: -------------------------------------------------------------------------------- 1 | % zmq.core.version - Retrieve ZMQ version. 2 | % 3 | % Usage: 4 | % zmq.core.version; % Prints ZMQ version to MATLAB console. 5 | % v = zmq.core.version; % Return version string (e.g. '4.0.4'). 6 | -------------------------------------------------------------------------------- /lib/+zmq/@Context/Context.m: -------------------------------------------------------------------------------- 1 | classdef Context < handle 2 | 3 | properties (Access = private) 4 | contextPointer; 5 | spawnedSockets; 6 | end 7 | 8 | methods 9 | function obj = Context(varargin) 10 | if (nargin ~= 0) 11 | warning('zmq:Context:extraConstructArgs','Extraneous constructor arguments.'); 12 | end 13 | % Core API 14 | obj.contextPointer = zmq.core.ctx_new(); 15 | % Initi properties 16 | obj.spawnedSockets = {}; 17 | end 18 | 19 | function delete(obj) 20 | if (obj.contextPointer ~= 0) 21 | for n = 1:length(obj.spawnedSockets) 22 | socketObj = obj.spawnedSockets{n}; 23 | if (isvalid(socketObj)) 24 | socketObj.delete() 25 | end 26 | end 27 | zmq.core.ctx_shutdown(obj.contextPointer); 28 | obj.term; 29 | end 30 | end 31 | end 32 | 33 | methods (Access = protected) 34 | normalized = normalize_const_name(obj, name); 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /lib/+zmq/@Context/get.m: -------------------------------------------------------------------------------- 1 | function option = get(obj, name) 2 | optName = obj.normalize_const_name(name); 3 | option = zmq.core.ctx_get(obj.contextPointer, optName); 4 | end 5 | -------------------------------------------------------------------------------- /lib/+zmq/@Context/get_ptr.m: -------------------------------------------------------------------------------- 1 | % This exposes the underlying context pointer. 2 | function ptr = get_ptr(obj) 3 | ptr = obj.contextPointer; 4 | end 5 | -------------------------------------------------------------------------------- /lib/+zmq/@Context/normalize_const_name.m: -------------------------------------------------------------------------------- 1 | function normalized = normalize_const_name(~, name) 2 | normalized = strrep(upper(name), 'ZMQ_', ''); 3 | normalized = strcat('ZMQ_', normalized); 4 | end 5 | -------------------------------------------------------------------------------- /lib/+zmq/@Context/set.m: -------------------------------------------------------------------------------- 1 | function set(obj, name, value) 2 | optName = obj.normalize_const_name(name); 3 | zmq.core.ctx_set(obj.contextPointer, optName, value); 4 | end 5 | -------------------------------------------------------------------------------- /lib/+zmq/@Context/socket.m: -------------------------------------------------------------------------------- 1 | function newSocket = socket(obj, socketType) 2 | % Spawns a socket from the context 3 | 4 | newSocket = zmq.Socket(obj.contextPointer, socketType); 5 | 6 | % Keep tracking of spawned sockets 7 | % this is important to the cleanup process 8 | obj.spawnedSockets{end+1} = newSocket; 9 | end 10 | -------------------------------------------------------------------------------- /lib/+zmq/@Context/term.m: -------------------------------------------------------------------------------- 1 | function term(obj) 2 | zmq.core.ctx_term(obj.contextPointer); 3 | obj.contextPointer = 0; % ensure NULL pointer 4 | end 5 | -------------------------------------------------------------------------------- /lib/+zmq/@Socket/Socket.m: -------------------------------------------------------------------------------- 1 | classdef Socket < handle 2 | 3 | properties (Access = private) 4 | socketPointer; 5 | end 6 | 7 | properties (Access = public) 8 | bindings; 9 | connections; 10 | defaultBufferLength; 11 | end 12 | 13 | methods 14 | function obj = Socket(contextPointer, socketType) 15 | socketType = obj.normalize_const_name(socketType); 16 | % Core API 17 | obj.socketPointer = zmq.core.socket(contextPointer, socketType); 18 | % Init properties 19 | obj.bindings = {}; 20 | obj.connections = {}; 21 | obj.defaultBufferLength = 255; 22 | end 23 | 24 | function delete(obj) 25 | if (obj.socketPointer ~= 0) 26 | % Disconnect/Unbind all the endpoints 27 | cellfun(@(b) obj.unbind(b), obj.bindings, 'UniformOutput', false); 28 | cellfun(@(c) obj.disconnect(c), obj.connections, 'UniformOutput', false); 29 | % Avoid linger time 30 | obj.set('linger', 0); 31 | % close 32 | obj.close; 33 | end 34 | end 35 | end 36 | 37 | methods (Access = protected) 38 | normalized = normalize_const_name(obj, name); 39 | varargout = normalize_msg_options(obj, varargin); 40 | end 41 | 42 | end 43 | -------------------------------------------------------------------------------- /lib/+zmq/@Socket/bind.m: -------------------------------------------------------------------------------- 1 | function bind(obj, endpoint) 2 | status = zmq.core.bind(obj.socketPointer, endpoint); 3 | if (status == 0) 4 | % Add endpoint to the tracked bindings 5 | % this is important to the cleanup process 6 | obj.bindings{end+1} = endpoint; 7 | end 8 | end -------------------------------------------------------------------------------- /lib/+zmq/@Socket/close.m: -------------------------------------------------------------------------------- 1 | function close(obj, endpoint) 2 | status = zmq.core.close(obj.socketPointer); 3 | if (status == 0) 4 | obj.socketPointer = 0; % ensure NULL pointer 5 | end 6 | end -------------------------------------------------------------------------------- /lib/+zmq/@Socket/connect.m: -------------------------------------------------------------------------------- 1 | function connect(obj, endpoint) 2 | status = zmq.core.connect(obj.socketPointer, endpoint); 3 | if (status == 0) 4 | % Add endpoint to the tracked connections 5 | % this is important to the cleanup process 6 | obj.connections{end+1} = endpoint; 7 | end 8 | end -------------------------------------------------------------------------------- /lib/+zmq/@Socket/disconnect.m: -------------------------------------------------------------------------------- 1 | function disconnect(obj, endpoint) 2 | status = zmq.core.disconnect(obj.socketPointer, endpoint); 3 | if (status == 0) 4 | % Remove endpoint from the tracked connections 5 | % to avoid double cleaning 6 | index = find(strcmp(obj.connections, endpoint)); 7 | obj.connections(index) = []; 8 | end 9 | end -------------------------------------------------------------------------------- /lib/+zmq/@Socket/get.m: -------------------------------------------------------------------------------- 1 | function option = get(obj, name) 2 | optName = obj.normalize_const_name(name); 3 | option = zmq.core.getsockopt(obj.socketPointer, optName); 4 | end -------------------------------------------------------------------------------- /lib/+zmq/@Socket/normalize_const_name.m: -------------------------------------------------------------------------------- 1 | function normalized = normalize_const_name(~, name) 2 | normalized = strrep(upper(name), 'ZMQ_', ''); 3 | normalized = strcat('ZMQ_', normalized); 4 | end -------------------------------------------------------------------------------- /lib/+zmq/@Socket/normalize_msg_options.m: -------------------------------------------------------------------------------- 1 | function [buffLen, options] = normalize_msg_options(obj, varargin) 2 | buffLen = obj.defaultBufferLength; 3 | options = cell(0); 4 | if (nargin > 1) 5 | if (isnumeric(varargin{1})) 6 | options = cell(1, nargin-2); 7 | buffLen = varargin{1}; 8 | offset = 1; 9 | else 10 | options = cell(1, nargin-1); 11 | offset = 0; 12 | end 13 | 14 | for n = 1:nargin-offset-1 15 | options{n} = obj.normalize_const_name(varargin{n+offset}); 16 | end 17 | end 18 | end -------------------------------------------------------------------------------- /lib/+zmq/@Socket/recv.m: -------------------------------------------------------------------------------- 1 | function varargout = recv(obj, varargin) 2 | [buffLen, options] = obj.normalize_msg_options(varargin{:}); 3 | [varargout{1:nargout}] = zmq.core.recv(obj.socketPointer, buffLen, options{:}); 4 | end -------------------------------------------------------------------------------- /lib/+zmq/@Socket/recv_multipart.m: -------------------------------------------------------------------------------- 1 | function message = recv_multipart(obj, varargin) 2 | [buffLen, options] = obj.normalize_msg_options(varargin{:}); 3 | 4 | message = []; 5 | 6 | keepReceiving = 1; 7 | 8 | while keepReceiving > 0 9 | part = obj.recv(buffLen, options{:}); 10 | message = [message part]; 11 | keepReceiving = obj.get('rcvmore'); 12 | end 13 | end -------------------------------------------------------------------------------- /lib/+zmq/@Socket/recv_string.m: -------------------------------------------------------------------------------- 1 | function message = recv_multipart(obj, varargin) 2 | message = char(obj.recv_multipart(varargin{:})); 3 | end -------------------------------------------------------------------------------- /lib/+zmq/@Socket/send.m: -------------------------------------------------------------------------------- 1 | function nbytes = send(obj, data, varargin) 2 | [~, options] = obj.normalize_msg_options(varargin{:}); 3 | nbytes = zmq.core.send(obj.socketPointer, data, options{:}); 4 | end -------------------------------------------------------------------------------- /lib/+zmq/@Socket/send_multipart.m: -------------------------------------------------------------------------------- 1 | function send_multipart(obj, message, varargin) 2 | [buffLen, options] = obj.normalize_msg_options(varargin{:}); 3 | 4 | offset = 1; 5 | 6 | L = length(message); % length of original message 7 | N = floor(L/buffLen); % number of multipart messages 8 | 9 | for m = 1:N 10 | part = message(offset:(offset+buffLen-1)); 11 | offset = offset+buffLen; 12 | obj.send(part, 'sndmore'); 13 | end 14 | 15 | part = message(offset:end); 16 | obj.send(part); 17 | end -------------------------------------------------------------------------------- /lib/+zmq/@Socket/send_string.m: -------------------------------------------------------------------------------- 1 | function send_string(obj, message, varargin) 2 | obj.send_multipart(uint8(message), varargin{:}); 3 | end -------------------------------------------------------------------------------- /lib/+zmq/@Socket/set.m: -------------------------------------------------------------------------------- 1 | function set(obj, name, value) 2 | optName = obj.normalize_const_name(name); 3 | option = zmq.core.setsockopt(obj.socketPointer, optName, value); 4 | end -------------------------------------------------------------------------------- /lib/+zmq/@Socket/unbind.m: -------------------------------------------------------------------------------- 1 | function unbind(obj, endpoint) 2 | status = zmq.core.unbind(obj.socketPointer, endpoint); 3 | if (status == 0) 4 | % Remove endpoint from the tracked bindings 5 | % to avoid double cleaning 6 | index = find(strcmp(obj.bindings, endpoint)); 7 | obj.bindings(index) = []; 8 | end 9 | end -------------------------------------------------------------------------------- /make.m: -------------------------------------------------------------------------------- 1 | function success = make(varargin) 2 | % make.m 3 | % 4 | % Tools for building matlab API for ZMQ. 5 | % 6 | % ## USAGE: 7 | % 8 | % ```matlab 9 | % >> make % This will build all the core API 10 | % >> make zmq_version.c zmq_ctx_new.c % This will build only the listed files 11 | % >> make clean % Remove files produced by compilation process 12 | % ``` 13 | % 14 | % ## NOTICE: 15 | % 16 | % Before runnig this, make sure to install ZMQ and edit 'config.m' file. 17 | % 18 | % Instructions for installing ZMQ: http://zeromq.org/intro:get-the-software. 19 | % 20 | % The files `config_win.m` and `config_unix.m` are examples of how to edit 21 | % `config.m` for different operating systems. 22 | % 23 | % The file `config.m` itself shows how to build `matlab-zmq` using a Homebrew 24 | % instalation of ZMQ 4.0.4 for OS-X. 25 | 26 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 27 | %% Rules 28 | if nargin > 0 29 | switch lower(varargin{1}) 30 | case 'clean' 31 | success = clean(varargin{2:end}); 32 | case 'test' 33 | success = run_tests(varargin{2:end}); 34 | case {'build', 'compile'} 35 | success = build(varargin{2:end}); 36 | otherwise 37 | success = build(varargin{:}); 38 | end 39 | else 40 | success = build; 41 | end 42 | end 43 | 44 | %% Make rules 45 | 46 | function success = clean(varargin) 47 | % Remove the files generated during compilation process. 48 | % 49 | % Arguments: 50 | % - [...]: Variable list of paths to be deleted, relative to this file. 51 | % No recursive glob patterns can be used. 52 | % 53 | % If no argument is provided, all '+zmq/+core/*.mex*', '*.o', '*.asv', '*.m~' files 54 | % will be remvoed. 55 | % 56 | % NOTICE: Without arguments, it will purge the created bindings. 57 | success = false; 58 | 59 | [make_path, ~, ~, ~] = get_paths(); 60 | if nargin > 0 61 | rubbish = varargin; 62 | else 63 | rubbish = {'lib/+zmq/+core/*.mex*', '*.o', '*.asv', '*.m~'}; 64 | end 65 | 66 | for n = 1:length(rubbish) 67 | pattern = fullfile(make_path, rubbish{n}); 68 | try 69 | if ~isempty(dir(pattern)) 70 | delete(pattern); 71 | end 72 | end 73 | end 74 | 75 | success = true; 76 | end 77 | 78 | function success = run_tests(varargin) 79 | % Run tests for the library 80 | % 81 | % ## Arguments 82 | % - [...]: variable list of tests. 83 | % 84 | % If no argument is provided, all the files `test*.m` under `tests` dir will 85 | % run. 86 | % 87 | % Notice that the files will be considered relative to `tests` directory. 88 | [make_path, ~, ~, test_path] = get_paths; 89 | 90 | % save current path 91 | original_path = path; 92 | addpath(test_path); 93 | % point at the core package. TODO: this could be tidier 94 | addpath(fullfile(make_path, 'lib')); 95 | cleanup = onCleanup(@() path(original_path)); % restore path after finish 96 | success = runner(varargin{:}); 97 | end 98 | 99 | function success = build(varargin) 100 | % Build core ZMQ bindings 101 | % 102 | % ## Arguments 103 | % - [...]: variable list of files to be compiled. 104 | % 105 | % If no argument is provided, the list will be loaded from `compile_list.m` 106 | % file. 107 | % 108 | % Notice that the files will be considered relative to `src/core` directory. 109 | % 110 | % Instead of a plain string, a cell array of strings can be also used as 111 | % argument. In this case, the first string is the _main_ file 112 | % (relative to `src/core` directory), while the others are _dependencies_ 113 | % (relative to `src`). 114 | 115 | [make_path, lib_path, src_path, ~] = get_paths; 116 | 117 | %% ZMQ CONFIGURATION: 118 | % Try manual config first 119 | config; 120 | 121 | if (~testzmq(ZMQ_LIB_PATH) || ~testzmq(ZMQ_INCLUDE_PATH)) 122 | % Default fallback 123 | if (ispc) 124 | % == WINDOWS == 125 | config_win; 126 | else 127 | % == POSIX == 128 | config_unix; 129 | end 130 | 131 | if (~testzmq(ZMQ_LIB_PATH) || ~testzmq(ZMQ_INCLUDE_PATH)) 132 | error('make:matlab-zmq:badConfig', ... 133 | 'Could not find ZMQ files, please edit ''config.m'' and try again.'); 134 | end 135 | end 136 | 137 | %% SCRIPT VARS 138 | 139 | % --> Windows whitespace normalization :( 140 | orig_zmq_include_path = ZMQ_INCLUDE_PATH; 141 | orig_zmq_lib_path = ZMQ_LIB_PATH; 142 | ZMQ_INCLUDE_PATH = reducepath(ZMQ_INCLUDE_PATH); 143 | ZMQ_LIB_PATH = reducepath(ZMQ_LIB_PATH); 144 | % <-- 145 | 146 | % --> '-l' option: libname normalization 147 | orig_zmq_lib = ZMQ_COMPILED_LIB; 148 | ZMQ_COMPILED_LIB = regexprep(orig_zmq_lib, '(^lib)|(\.\w+$)', ''); 149 | % <-- 150 | 151 | zmq_compile_flags = { ... 152 | ['-I' dquote(src_path)], ... 153 | ['-I' dquote(ZMQ_INCLUDE_PATH)], ... 154 | ['-L' dquote(ZMQ_LIB_PATH)], ... 155 | ['-l' dquote(ZMQ_COMPILED_LIB)] ... 156 | }; 157 | 158 | if nargin > 0 159 | COMPILE_LIST = varargin; 160 | else 161 | compile_list; 162 | end 163 | 164 | lib_path = reducepath(lib_path); % Windows :( 165 | 166 | build_function = @(file) compile(zmq_compile_flags, file, fullfile(lib_path,'+zmq/+core')); 167 | cellfun(build_function, COMPILE_LIST); 168 | 169 | clean('*.o'); 170 | 171 | files = ls(fullfile(fullfile(lib_path, '+zmq/+core'), '*.mex*')); 172 | if size(files, 1) == length(COMPILE_LIST) 173 | success = true; 174 | fprintf('\nSuccesful build for:\n'); 175 | else 176 | success = false; 177 | fprintf('\nErrors during build for:\n'); 178 | end 179 | fprintf(... 180 | '\tZMQ_INCLUDE_PATH = %s\n\tZMQ_LIB_PATH = %s\n\tZMQ_COMPILED_LIB = %s\n\n', ... 181 | orig_zmq_include_path, orig_zmq_lib_path, orig_zmq_lib); 182 | end 183 | 184 | %% Aux functions 185 | 186 | function compile(flags, file, outputdir) 187 | % Compile files 188 | [~, ~, src_path, ~] = get_paths; 189 | 190 | deps = {}; 191 | 192 | if iscell(file) 193 | if length(file) > 1 194 | deps = cellfun(@(dep) dquote(fullfile(src_path, dep)), file(2:end), 'UniformOutput', false); 195 | end 196 | file = file{1}; 197 | end 198 | 199 | [~, name, ext] = fileparts(file); 200 | outputfile = fullfile(outputdir, name); 201 | file = dquote([fullfile(src_path, 'core', name), ext]); 202 | 203 | fprintf('compile %s\n', file); 204 | cellfun(@(dep) fprintf('\t- %s\n', dep), deps); 205 | 206 | if isoctave 207 | mex(flags{:}, deps{:}, file, '-o', dquote(outputfile)); 208 | else 209 | % TODO: scape properly the `outputfile` to avoid whitespace issues. 210 | % Inexplicably just using quotes (`sprintf('"%s"', outputfile)` or 211 | % `['"' outputfile '"']` ) does not work on Windows, even when there are not 212 | % whitespaces. 213 | mex('-largeArrayDims', '-O', flags{:}, deps{:}, file, '-output', outputfile); 214 | end 215 | end 216 | 217 | function result = isoctave 218 | % Check if it is octave 219 | result = exist('OCTAVE_VERSION', 'builtin'); 220 | end 221 | 222 | function quoted = dquote(file) 223 | % Double quote strings 224 | quoted = ['"' file '"']; 225 | end 226 | 227 | function red_path = reducepath(orig_path) 228 | % Unfortunatelly windows has severe issues with spaces in the path 229 | % strings, even when we scape them with quotes. 230 | % 231 | % Thanks to backward compatibility (dating back to MS-DOS times), it's 232 | % possible to convert the paths to an alternate ancient short form 233 | % (http://en.wikipedia.org/wiki/8.3_filename). 234 | % 235 | % The black magic necessary to do so was found in: 236 | % - http://stackoverflow.com/questions/1333589/how-do-i-transform-the-working-directory-into-a-8-3-short-file-name-using-batch 237 | % - http://stackoverflow.com/questions/10227144/convert-long-filename-to-short-filename-8-3-using-cmd-exe 238 | % 239 | % There is an alternate procedure, as documented in: 240 | % http://www.mathworks.com/matlabcentral/answers/93932-how-can-i-get-the-short-path-for-a-windows-long-path-using-matlab-7-8-r2009a 241 | % 242 | % TODO: consider the much nicer second alternative. Is it reliable in a 243 | % wide range of environments (diferent versions of Windows, even the 244 | % future ones)? 245 | 246 | if ispc 247 | [status, red_path] = system(['for %A in ("', orig_path ,'") do @echo %~sA']); 248 | if status; error('system:reducepath', 'Unable to recognize path'); end 249 | red_path = strtrim(red_path); 250 | else 251 | red_path = orig_path; 252 | end 253 | end 254 | 255 | function response = testzmq(folder) 256 | % Test if there are any zmq files inside folder 257 | 258 | try 259 | files = dir(fullfile(folder, '*zmq*')); 260 | catch 261 | files = []; 262 | end 263 | 264 | if ~isempty(files) 265 | response = 1; 266 | else 267 | response = 0; 268 | end 269 | end 270 | 271 | function [make_path, lib_path, src_path, test_path] = get_paths() 272 | % Return the paths used for this library 273 | 274 | [make_path, ~, ~] = fileparts(mfilename('fullpath')); 275 | lib_path = fullfile(make_path, 'lib/'); 276 | src_path = fullfile(make_path, 'src'); 277 | test_path = fullfile(make_path, 'tests'); 278 | end 279 | 280 | 281 | 282 | 283 | 284 | -------------------------------------------------------------------------------- /src/core/bind.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) 8 | { 9 | void* socket = NULL; 10 | char* endpoint = NULL; 11 | int rc; 12 | 13 | if (nrhs != 2) { 14 | mexErrMsgIdAndTxt("zmq:core:bind:invalidArgs", 15 | "Error: Two arguments are required: socket, endpoint."); 16 | return; 17 | } 18 | if (mxIsChar(prhs[1]) != 1) { 19 | mexErrMsgIdAndTxt("zmq:core:bind:invalidEndpoint", 20 | "Error: endpoint is not a string."); 21 | return; 22 | } 23 | if (mxGetM(prhs[1]) != 1) { 24 | mexErrMsgIdAndTxt("zmq:core:bind:endpointNotRowVec", 25 | "Error: endpoint is not a row vector."); 26 | return; 27 | } 28 | 29 | socket = pointer_from_m(prhs[0]); 30 | if (socket == NULL) return; 31 | 32 | endpoint = (char*) str_from_m(prhs[1]); 33 | if (endpoint == NULL) 34 | return; 35 | 36 | rc = zmq_bind(socket, endpoint); 37 | 38 | if (rc < 0) 39 | handle_error(); 40 | else 41 | plhs[0] = int_to_m((void*) &rc); 42 | 43 | mxFree(endpoint); 44 | } 45 | -------------------------------------------------------------------------------- /src/core/close.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) 9 | { 10 | void* socket = NULL; 11 | int rc; 12 | 13 | if (nrhs != 1) { 14 | mexErrMsgIdAndTxt("zmq:core:close:invalidArgs", 15 | "Error: One argument is required: socket"); 16 | return; 17 | } 18 | 19 | socket = pointer_from_m(prhs[0]); 20 | if (socket == NULL) return; 21 | 22 | rc = zmq_close(socket); 23 | 24 | if (rc < 0) { 25 | handle_error(); 26 | return; 27 | } 28 | 29 | plhs[0] = int_to_m((void*) &rc); 30 | } 31 | -------------------------------------------------------------------------------- /src/core/connect.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) 8 | { 9 | void* socket = NULL; 10 | char* endpoint = NULL; 11 | int rc; 12 | 13 | if (nrhs != 2) { 14 | mexErrMsgIdAndTxt("zmq:core:connect:invalidArgs", 15 | "Error: Two arguments are required: socket, endpoint."); 16 | return; 17 | } 18 | if (mxIsChar(prhs[1]) != 1) { 19 | mexErrMsgIdAndTxt("zmq:core:connect:invalidEndpoint", 20 | "Error: endpoint is not a string."); 21 | return; 22 | } 23 | if (mxGetM(prhs[1]) != 1) { 24 | mexErrMsgIdAndTxt("zmq:core:connect:endpointNotRowVec", 25 | "Error: endpoint is not a row vector."); 26 | return; 27 | } 28 | 29 | socket = pointer_from_m(prhs[0]); 30 | if (socket == NULL) return; 31 | 32 | endpoint = (char*) str_from_m(prhs[1]); 33 | if (endpoint == NULL) return; 34 | 35 | rc = zmq_connect(socket, endpoint); 36 | 37 | if (rc < 0) handle_error(); 38 | else plhs[0] = int_to_m((void*) &rc); 39 | 40 | mxFree(endpoint); 41 | } 42 | -------------------------------------------------------------------------------- /src/core/ctx_get.c: -------------------------------------------------------------------------------- 1 | /* zmq_ctx_get.cc - Mex wrapper for zmq_ctx_get(3). 2 | * 3 | * Copyright 2014 Ashton Fagg (ashton@fagg.id.au) 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | char *get_option_name(const mxArray *); 11 | int core_ctx_get(const mxArray *[]); 12 | 13 | void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) 14 | { 15 | int coreAPIReturn; 16 | int *mexReturn; 17 | 18 | if (nrhs != 2) { 19 | mexErrMsgIdAndTxt("zmq:core:ctx_get:invalidArgs", 20 | "Error: Need two arguments - context and option_name."); 21 | } 22 | if (mxIsChar(prhs[1]) != 1) { 23 | mexErrMsgIdAndTxt("zmq:core:ctx_get:optionNotString", 24 | "Error: option_name must be a string."); 25 | } 26 | if (mxGetM(prhs[1]) != 1) { 27 | mexErrMsgIdAndTxt("zmq:core:ctx_get:optionNotRowVec", 28 | "Error: option_name must be a row vector."); 29 | } 30 | 31 | coreAPIReturn = core_ctx_get(prhs); 32 | 33 | if (sizeof(void *) == 4) { 34 | plhs[0] = mxCreateNumericMatrix(1,1,mxUINT32_CLASS, mxREAL); 35 | } else { 36 | plhs[0] = mxCreateNumericMatrix(1,1,mxUINT64_CLASS, mxREAL); 37 | } 38 | mexReturn = (int *) mxGetData(plhs[0]); 39 | *mexReturn = coreAPIReturn; 40 | } 41 | 42 | char *get_option_name(const mxArray *param) 43 | { 44 | int optLen; 45 | char *ret; 46 | 47 | optLen = mxGetM(param) * mxGetN(param) + 1; 48 | ret = (char *) mxCalloc(optLen, sizeof(char)); 49 | 50 | if (mxGetString(param, ret, optLen) != 0) { 51 | mexErrMsgIdAndTxt("zmq:core:ctx_get:optNameCopyFail", 52 | "Error: Couldn't get option_name as string."); 53 | } 54 | return ret; 55 | } 56 | 57 | int core_ctx_get(const mxArray *params[]) 58 | { 59 | int ret, optSelection; 60 | char *option; 61 | void **contextPtr; 62 | 63 | option = get_option_name(params[1]); 64 | contextPtr = (void **) mxGetData(params[0]); 65 | 66 | if (!strcmp(option, "ZMQ_IO_THREADS")) 67 | optSelection = ZMQ_IO_THREADS; 68 | else if(!strcmp(option, "ZMQ_MAX_SOCKETS")) 69 | optSelection = ZMQ_MAX_SOCKETS; 70 | else if (!strcmp(option, "ZMQ_IPV6")) 71 | optSelection = ZMQ_IPV6; 72 | else { 73 | mxFree(option); 74 | mexErrMsgIdAndTxt("zmq:core:ctx_get:optNameInvalid", 75 | "Error: Invalid option_name."); 76 | } 77 | ret = zmq_ctx_get(*contextPtr, optSelection); 78 | 79 | /* Make sure the call returns OK, it should do considering we filter our 80 | * own option_value values. */ 81 | if (ret < 0) { 82 | mxFree(option); 83 | mexErrMsgIdAndTxt("zmq:core:ctx_get:coreAPIInvalidOption", 84 | "Error: Invalid option_name (core API)."); 85 | } 86 | mxFree(option); 87 | return ret; 88 | } 89 | -------------------------------------------------------------------------------- /src/core/ctx_new.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) 5 | { 6 | void *context; 7 | void **mexReturn; 8 | 9 | if (nrhs != 0) { 10 | mexErrMsgIdAndTxt("zmq:core:ctx_new:invalidArgs", 11 | "Error: No arguments are accepted by this function."); 12 | } 13 | /* Set up ZMQ context and check its validity */ 14 | context = zmq_ctx_new(); 15 | if (context == NULL) { 16 | mexErrMsgIdAndTxt("zmq:core:ctx_new:contextInitFail", 17 | "Error: ZMQ context instantiation failed."); 18 | } 19 | 20 | /* TODO: Refactor this */ 21 | /* Are we on a 32 or 64 bit machine? */ 22 | if (sizeof(void*) == 4) { 23 | plhs[0] = mxCreateNumericMatrix(1, 1, mxUINT32_CLASS, mxREAL); 24 | } else { 25 | plhs[0] = mxCreateNumericMatrix(1, 1, mxUINT64_CLASS, mxREAL); 26 | } 27 | 28 | mexReturn = (void **) mxGetData(plhs[0]); 29 | mexReturn[0] = context; 30 | } 31 | -------------------------------------------------------------------------------- /src/core/ctx_set.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | char *get_option_name(const mxArray *); 6 | void core_ctx_set(const mxArray *[]); 7 | 8 | void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) 9 | { 10 | if (nrhs != 3) { 11 | mexErrMsgIdAndTxt("zmq:core:ctx_set:invalidArgs", 12 | "Error: Need three arguments - context, option_name, option_value."); 13 | } 14 | if (mxIsChar(prhs[1]) != 1) { 15 | mexErrMsgIdAndTxt("zmq:core:ctx_set:optionNotString", 16 | "Error: option_name must be a string."); 17 | } 18 | if (mxGetM(prhs[1]) != 1) { 19 | mexErrMsgIdAndTxt("zmq:core:ctx_set:optionNotRowVec", 20 | "Error: option_name must be a row vector."); 21 | } 22 | if (mxIsNumeric(prhs[2]) != 1) { 23 | mexErrMsgIdAndTxt("zmq:core:ctx_set:optionNotNumeric", 24 | "Error: option_value isn't numeric."); 25 | } 26 | if (mxGetM(prhs[2]) != 1 || mxGetN(prhs[2]) != 1) { 27 | mexErrMsgIdAndTxt("zmq:core:ctx_set:optionNotSingleNumeric", 28 | "Error: option_value can't be an array or matrix."); 29 | } 30 | 31 | core_ctx_set(prhs); 32 | } 33 | 34 | char *get_option_name(const mxArray *param) 35 | { 36 | int optLen = mxGetM(param) * mxGetN(param) + 1; 37 | char *ret = (char *) mxCalloc(optLen, sizeof(char)); 38 | if (mxGetString(param, ret, optLen) != 0) { 39 | mexErrMsgIdAndTxt("zmq:core:ctx_set:optNameCopyFail", 40 | "Error: Couldn't get option_name as string."); 41 | } 42 | return ret; 43 | } 44 | 45 | void core_ctx_set(const mxArray *params[]) 46 | { 47 | int ret, optValue; 48 | char *option = get_option_name(params[1]); 49 | int optVal = mxGetScalar(params[2]); 50 | void **contextPtr = (void **) mxGetData(params[0]); 51 | 52 | if (!strcmp(option, "ZMQ_IO_THREADS")) 53 | ret = zmq_ctx_set(*contextPtr, ZMQ_IO_THREADS, optVal); 54 | else if (!strcmp(option, "ZMQ_MAX_SOCKETS")) 55 | ret = zmq_ctx_set(*contextPtr, ZMQ_MAX_SOCKETS, optVal); 56 | else if (!strcmp(option, "ZMQ_IPV6")) 57 | ret = zmq_ctx_set(*contextPtr, ZMQ_IPV6, optVal); 58 | else { 59 | mxFree(option); 60 | mexErrMsgIdAndTxt("zmq:core:ctx_set:optNameInvalid", 61 | "Error: Invalid option_name."); 62 | } 63 | if (ret != 0) { 64 | mxFree(option); 65 | mexErrMsgIdAndTxt("zmq:core:ctx_set:coreAPISetFailure", 66 | "Error: Setting option_name to option_value failed."); 67 | } else { 68 | mxFree(option); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/core/ctx_shutdown.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) 6 | { 7 | void **contextPtr; 8 | int coreAPIReturn; 9 | 10 | if (nrhs != 1) { 11 | mexErrMsgIdAndTxt("zmq:core:ctx_shutdown:invalidArgs", 12 | "Error: Only a context argument is accepted by this function."); 13 | } 14 | contextPtr = (void **) mxGetData(prhs[0]); 15 | coreAPIReturn = zmq_ctx_shutdown(*contextPtr); 16 | if (coreAPIReturn < 0) { 17 | switch (errno) { 18 | case EFAULT: 19 | mexErrMsgIdAndTxt("zmq:core:ctx_shutdown:invalidContext", 20 | "Error: Invalid ZMQ Context."); 21 | break; 22 | default: 23 | mexErrMsgIdAndTxt("zmq:core:ctx_shutdown:unknownOops", 24 | "Error: Something has gone very, very wrong. Unknown error."); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/core/ctx_term.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) 6 | { 7 | void **contextPtr; 8 | int coreAPIReturn; 9 | 10 | if (nrhs != 1) { 11 | mexErrMsgIdAndTxt("zmq:core:ctx_term:invalidArgs", 12 | "Error: Only a context argument is accepted by this function."); 13 | } 14 | contextPtr = (void **) mxGetData(prhs[0]); 15 | coreAPIReturn = zmq_ctx_term(*contextPtr); 16 | if (coreAPIReturn < 0) { 17 | switch (errno) { 18 | case EFAULT: 19 | mexErrMsgIdAndTxt("zmq:core:ctx_term:invalidContext", 20 | "Error: Invalid ZMQ context."); 21 | break; 22 | case EINTR: 23 | mexErrMsgIdAndTxt("zmq:core:ctx_term:termInter", 24 | "Error: Termination was interrupted by a signal."); 25 | break; 26 | default: 27 | mexErrMsgIdAndTxt("zmq:core:ctx_term:unknownOops", 28 | "Error: Something has gone very, very wrong. Unknown error."); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/core/disconnect.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) 8 | { 9 | void* socket = NULL; 10 | char* endpoint = NULL; 11 | int rc; 12 | 13 | if (nrhs != 2) { 14 | mexErrMsgIdAndTxt("zmq:core:disconnect:invalidArgs", 15 | "Error: Two arguments are required: socket, endpoint."); 16 | return; 17 | } 18 | if (mxIsChar(prhs[1]) != 1) { 19 | mexErrMsgIdAndTxt("zmq:core:disconnect:invalidEndpoint", 20 | "Error: endpoint is not a string."); 21 | return; 22 | } 23 | if (mxGetM(prhs[1]) != 1) { 24 | mexErrMsgIdAndTxt("zmq:core:disconnect:endpointNotRowVec", 25 | "Error: endpoint is not a row vector."); 26 | return; 27 | } 28 | 29 | socket = pointer_from_m(prhs[0]); 30 | if (socket == NULL) return; 31 | 32 | endpoint = (char*) str_from_m(prhs[1]); 33 | if (endpoint == NULL) return; 34 | 35 | rc = zmq_disconnect(socket, endpoint); 36 | 37 | if (rc < 0) handle_error(); 38 | else plhs[0] = int_to_m((void*) &rc); 39 | 40 | mxFree(endpoint); 41 | } 42 | -------------------------------------------------------------------------------- /src/core/getsockopt.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) 9 | { 10 | void* socket = NULL; 11 | char* option = NULL; 12 | void* coreAPIReturn = NULL; 13 | size_t coreAPIReturnSz; 14 | const zmq_sockopt_desc_t* optDesc = NULL; 15 | const zmq_sockopt_type_t* typeDesc = NULL; 16 | int rc; 17 | 18 | if (nrhs != 2) { 19 | mexErrMsgIdAndTxt("zmq:core:getsockopts:invalidArgs", 20 | "Error: Two arguments are required: socket, option"); 21 | return; 22 | } 23 | if (mxIsChar(prhs[1]) != 1) { 24 | mexErrMsgIdAndTxt("zmq:core:getsockopts:invalidOptionName", 25 | "Error: option_name is not a string."); 26 | return; 27 | } 28 | if (mxGetM(prhs[1]) != 1) { 29 | mexErrMsgIdAndTxt("zmq:core:getsockopts:optionNameNotRowVec", 30 | "Error: option_name is not a row vector."); 31 | return; 32 | } 33 | 34 | /* Discover which option should be used */ 35 | option = (char*) str_from_m(prhs[1]); 36 | if (option == NULL) 37 | return; 38 | 39 | optDesc = find_sockopt_by_name(option); 40 | if (optDesc == NULL) 41 | return; 42 | 43 | typeDesc = find_sockopt_type_by_id(optDesc->typeId); 44 | if (typeDesc == NULL) 45 | return; 46 | 47 | mxFree(option); 48 | 49 | socket = pointer_from_m(prhs[0]); 50 | 51 | coreAPIReturnSz = typeDesc->maxLen; 52 | coreAPIReturn = (void*) mxMalloc(coreAPIReturnSz); 53 | 54 | if (coreAPIReturn == NULL) { 55 | mexErrMsgIdAndTxt("mex:malloc", 56 | "Error: Unsuccessful memory allocation."); 57 | return; 58 | } 59 | 60 | rc = zmq_getsockopt(socket, optDesc->id, coreAPIReturn, &coreAPIReturnSz); 61 | 62 | if (rc < 0) { 63 | handle_error(); 64 | mxFree(coreAPIReturn); 65 | return; 66 | } 67 | 68 | plhs[0] = typeDesc->to_m(coreAPIReturn); 69 | mxFree(coreAPIReturn); 70 | } 71 | -------------------------------------------------------------------------------- /src/core/recv.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define DEFAULT_BUFFER_LENGTH 255 9 | 10 | int configure_flag(const mxArray **, int); 11 | void configure_return(int, mxArray **, int, size_t, void *); 12 | size_t configure_buffer_length(const mxArray **, int *); 13 | 14 | void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) 15 | { 16 | void *socket = NULL; 17 | void *buffer = NULL; 18 | size_t bufLen = DEFAULT_BUFFER_LENGTH; 19 | int optionStart = 1; /* from which index options can be passed */ 20 | int coreAPIReturn, coreAPIOptionFlag = 0; 21 | 22 | if (nrhs < 1) { 23 | mexErrMsgIdAndTxt("zmq:core:recv:invalidArgs", 24 | "Error: At least one argument is required: socket."); 25 | return; 26 | } 27 | 28 | if (nrhs >= 2) { 29 | /* Check if the user has chosen a bufLen, 30 | * if so get it and update the index where options should start */ 31 | bufLen = configure_buffer_length(prhs, &optionStart); 32 | if (bufLen == 0) 33 | return; 34 | 35 | /* Get the options for receiving */ 36 | coreAPIOptionFlag = configure_flag(&(prhs[optionStart]), nrhs - optionStart); 37 | } 38 | 39 | socket = pointer_from_m(prhs[0]); 40 | if (socket == NULL) { 41 | mexErrMsgIdAndTxt("zmq:core:recv:invalidSocket", "Error: Invalid socket."); 42 | return; 43 | } 44 | 45 | /* Create buffer and call API */ 46 | buffer = (uint8_t*) mxCalloc(bufLen, sizeof(uint8_t)); 47 | if (buffer == NULL) { 48 | mexErrMsgIdAndTxt("util:calloc", "Error: Unsuccessful memory allocation."); 49 | return; 50 | } 51 | 52 | coreAPIReturn = zmq_recv(socket, buffer, bufLen * sizeof(uint8_t), coreAPIOptionFlag); 53 | 54 | if (coreAPIReturn < 0) { 55 | /* Check if error is due to non-blocking with no message */ 56 | if (errno == EAGAIN) { 57 | /* no error, so return zmq_recv return value */ 58 | plhs[0] = mxCreateNumericMatrix(1, 1, mxINT32_CLASS, mxREAL); 59 | *((int*)mxGetData(plhs[0])) = coreAPIReturn; 60 | } 61 | else 62 | handle_error(); 63 | } else { 64 | /* Prepare the values that should be returned to MATLAB */ 65 | configure_return(nlhs, plhs, coreAPIReturn, bufLen, buffer); 66 | } 67 | 68 | mxFree(buffer); 69 | } 70 | 71 | /* Discover which options are passed by the user, and calculate the 72 | * corresponding flag */ 73 | int configure_flag(const mxArray **params, int nParams) 74 | { 75 | int i, coreAPIOptionFlag = 0; 76 | char *flagStr = NULL; 77 | 78 | for (i = 0 ; i < nParams; i++) { 79 | flagStr = (char *) str_from_m(params[i]); 80 | if (flagStr != NULL) { 81 | if(strcmp(flagStr, "ZMQ_DONTWAIT") == 0) 82 | coreAPIOptionFlag |= ZMQ_DONTWAIT; 83 | else 84 | mexErrMsgIdAndTxt("zmq:core:recv:invalidFlag", "Error: Unknown flag."); 85 | mxFree(flagStr); 86 | } 87 | } 88 | 89 | return coreAPIOptionFlag; 90 | } 91 | 92 | /* Check if the message was truncated, advising user and avoiding memory waste 93 | * while prepare it to return to MATLAB. Also handle the second optional return */ 94 | void configure_return(int nlhs, mxArray **plhs, int msgLen, size_t bufLen, void *buffer) { 95 | if (msgLen > bufLen) { 96 | mexWarnMsgIdAndTxt("zmq:core:recv:bufferTooSmall", 97 | "Message is %d bytes long, but buffer is %d. Truncated.", 98 | msgLen, bufLen); 99 | plhs[0] = uint8_array_to_m((void*) buffer, bufLen); 100 | } else { 101 | plhs[0] = uint8_array_to_m((void*) buffer, msgLen); 102 | } 103 | 104 | if (nlhs > 1) { 105 | plhs[1] = int_to_m((void*) &msgLen); 106 | } 107 | } 108 | 109 | /* Check if the param in the index is an number 110 | * if so, convert it from MATLAB and increments the index */ 111 | size_t configure_buffer_length(const mxArray **param, int *paramIndex) 112 | { 113 | size_t length = DEFAULT_BUFFER_LENGTH; 114 | size_t *input; 115 | 116 | if (mxIsNumeric(param[*paramIndex])) { 117 | input = (size_t*) size_t_from_m(param[*paramIndex]); 118 | *paramIndex += 1; 119 | if (input != NULL) { 120 | length = *input; 121 | mxFree(input); 122 | } else { 123 | mexErrMsgIdAndTxt("zmq:core:recv:unknowOops", "Unable to convert parameter."); 124 | return 0; 125 | } 126 | } 127 | 128 | return length; 129 | } 130 | -------------------------------------------------------------------------------- /src/core/send.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | /* TODO: Clean up, inline declarations. 10 | */ 11 | void configure_message(const mxArray *, void **, size_t *); 12 | int configure_flag(const mxArray **, int ); 13 | 14 | void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) 15 | { 16 | void *socket = NULL; 17 | void *payload = NULL; 18 | size_t payloadLen = 0; 19 | int coreAPIReturn, coreAPIOptionFlag = 0; 20 | 21 | /* Configure the message payload */ 22 | configure_message(prhs[1], &payload, &payloadLen); 23 | if (payload == NULL) 24 | return; 25 | 26 | /* Get the options for sending */ 27 | if (nrhs > 2) 28 | coreAPIOptionFlag = configure_flag(&(prhs[2]), nrhs - 2); 29 | 30 | socket = pointer_from_m(prhs[0]); 31 | if (socket != NULL) { 32 | coreAPIReturn = zmq_send(socket, payload, payloadLen * sizeof(uint8_t), coreAPIOptionFlag); 33 | if (coreAPIReturn < 0) 34 | handle_error(); 35 | else 36 | plhs[0] = int_to_m( (void *) &coreAPIReturn); 37 | } else { 38 | mexErrMsgIdAndTxt("zmq:core:send:invalidSocket", "Error: Invalid socket."); 39 | } 40 | 41 | mxFree(payload); 42 | } 43 | 44 | void configure_message(const mxArray *rawMessage, void **payload, size_t *payloadLen) 45 | { 46 | /* We don't care what we're sending, just send it in a dumb way and let higher levels 47 | * deal with typing and reconstruction of dimensions, tensors etc (i.e. serialize with JSON) 48 | * 49 | * Reasons for using uint8: 50 | * - Reported inconsistencies when using strings due enconding: 51 | * https://github.com/yida/msgpack-matlab/blob/master/README.md 52 | * 53 | * Reasons for restricting input to a row vector: 54 | * - Uncertainty when differentiating message shapes, 55 | * e. g. [1 2; 3 4; 5 6], [1 2 3; 4 5 6], [1 2 3 4 5 6]. */ 56 | if (mxGetM(rawMessage) != 1) { 57 | mexErrMsgIdAndTxt("zmq:core:send:messageNotRowVec", 58 | "Error: Message must be a row vector. Flatten before attempting to send."); 59 | } 60 | if (mxIsUint8(rawMessage) != 1) { 61 | mexErrMsgIdAndTxt("zmq:core:send:messageNotUint8", 62 | "Error: Message payload must be uint8"); 63 | } 64 | 65 | *payloadLen = mxGetN(rawMessage); 66 | 67 | *payload = uint8_array_from_m(rawMessage, *payloadLen); 68 | if (payload == NULL) { 69 | mexErrMsgIdAndTxt("zmq:core:send:messageIsEmpty", "Error: You're trying to send an empty message."); 70 | } 71 | } 72 | 73 | int configure_flag(const mxArray **params, int nParams) 74 | { 75 | int i, coreAPIOptionFlag = 0; 76 | char *flagStr = NULL; 77 | for (i = 0 ; i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) 10 | { 11 | void* socket = NULL; 12 | char* option = NULL; 13 | void* optValue = NULL; 14 | size_t optLen; 15 | const zmq_sockopt_desc_t* optDesc = NULL; 16 | const zmq_sockopt_type_t* typeDesc = NULL; 17 | int rc; 18 | 19 | if (nrhs != 3) { 20 | mexErrMsgIdAndTxt("zmq:core:setsockopt:invalidArgs", 21 | "Error: Tree arguments are required: socket, option, value"); 22 | return; 23 | } 24 | if (mxIsChar(prhs[1]) != 1) { 25 | mexErrMsgIdAndTxt("zmq:core:setsockopt:invalidOptionName", 26 | "Error: option_name is not a string."); 27 | return; 28 | } 29 | if (mxGetM(prhs[1]) != 1) { 30 | mexErrMsgIdAndTxt("zmq:core:setsockopt:optionNameNotRowVec", 31 | "Error: option_name is not a row vector."); 32 | return; 33 | } 34 | 35 | /* Discover which option should be used */ 36 | option = (char*) str_from_m(prhs[1]); 37 | if (option == NULL) return; 38 | 39 | optDesc = find_sockopt_by_name(option); 40 | if (optDesc == NULL) return; 41 | 42 | typeDesc = find_sockopt_type_by_id(optDesc->typeId); 43 | if (typeDesc == NULL) return; 44 | 45 | mxFree(option); 46 | 47 | socket = pointer_from_m(prhs[0]); 48 | if (socket == NULL) return; 49 | 50 | optValue = typeDesc->from_m(prhs[2]); 51 | if (optValue == NULL) return; 52 | 53 | optLen = typeDesc->maxLen; 54 | /* Correct len for compound types */ 55 | if (typeDesc->id == SOPT_STRING || typeDesc->id == SOPT_KEY) { 56 | optLen = mxGetNumberOfElements(prhs[2]); 57 | } 58 | 59 | rc = zmq_setsockopt(socket, optDesc->id, optValue, optLen); 60 | 61 | if (rc < 0) { 62 | handle_error(); 63 | mxFree(optValue); 64 | return; 65 | } 66 | 67 | plhs[0] = int_to_m((void*) &rc); 68 | mxFree(optValue); 69 | } 70 | -------------------------------------------------------------------------------- /src/core/socket.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | char *get_socket_type(const mxArray *); 8 | void *core_socket(const mxArray *[]); 9 | 10 | void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) 11 | { 12 | void *coreAPIReturn; 13 | void **mexReturn; 14 | 15 | if (nrhs != 2) { 16 | mexErrMsgIdAndTxt("zmq:core:socket:invalidArgs", 17 | "Error: Two arguments are required - context, socket_type."); 18 | } 19 | if (mxIsChar(prhs[1]) != 1) { 20 | mexErrMsgIdAndTxt("zmq:core:socket:sockTypeNotString", 21 | "Error: socket_type is not a string."); 22 | } 23 | if (mxGetM(prhs[1]) != 1) { 24 | mexErrMsgIdAndTxt("zmq:core:socket:sockTypeNotRowVec", 25 | "Error: socket_type is not a row vector."); 26 | } 27 | 28 | coreAPIReturn = core_socket(prhs); 29 | 30 | if (sizeof(void *) == 4) { 31 | plhs[0] = mxCreateNumericMatrix(1,1,mxUINT32_CLASS, mxREAL); 32 | } else { 33 | plhs[0] = mxCreateNumericMatrix(1,1,mxUINT64_CLASS, mxREAL); 34 | } 35 | mexReturn = (void **) mxGetData(plhs[0]); 36 | mexReturn[0] = coreAPIReturn; 37 | } 38 | 39 | char *get_socket_type(const mxArray *param) 40 | { 41 | int optLen; 42 | char *ret; 43 | 44 | optLen = mxGetM(param) * mxGetN(param) + 1; 45 | ret = (char *) mxCalloc(optLen, sizeof(char)); 46 | 47 | if (mxGetString(param, ret, optLen) != 0) { 48 | mexErrMsgIdAndTxt("zmq:core:socket:sockTypeCopyFail", 49 | "Error: Couldn't get socket_type as string."); 50 | } 51 | return ret; 52 | } 53 | 54 | void *core_socket(const mxArray *params[]) 55 | { 56 | int sockTypeVal; 57 | char *sockType; 58 | void **contextPtr; 59 | void *coreAPIReturn; 60 | int err; 61 | 62 | sockType = get_socket_type(params[1]); 63 | contextPtr = (void **) mxGetData(params[0]); 64 | 65 | if (!strcmp(sockType, "ZMQ_REQ")) 66 | sockTypeVal = ZMQ_REQ; 67 | else if (!strcmp(sockType, "ZMQ_REP")) 68 | sockTypeVal = ZMQ_REP; 69 | else if (!strcmp(sockType, "ZMQ_DEALER")) 70 | sockTypeVal = ZMQ_DEALER; 71 | else if (!strcmp(sockType, "ZMQ_ROUTER")) 72 | sockTypeVal = ZMQ_ROUTER; 73 | else if (!strcmp(sockType, "ZMQ_PUB")) 74 | sockTypeVal = ZMQ_PUB; 75 | else if (!strcmp(sockType, "ZMQ_SUB")) 76 | sockTypeVal = ZMQ_SUB; 77 | else if (!strcmp(sockType, "ZMQ_XPUB")) 78 | sockTypeVal = ZMQ_XPUB; 79 | else if (!strcmp(sockType, "ZMQ_XSUB")) 80 | sockTypeVal = ZMQ_XSUB; 81 | else if (!strcmp(sockType, "ZMQ_PUSH")) 82 | sockTypeVal = ZMQ_PUSH; 83 | else if (!strcmp(sockType, "ZMQ_PULL")) 84 | sockTypeVal = ZMQ_PULL; 85 | else if (!strcmp(sockType, "ZMQ_PAIR")) 86 | sockTypeVal = ZMQ_PAIR; 87 | else if (!strcmp(sockType, "ZMQ_STREAM")) 88 | sockTypeVal = ZMQ_STREAM; 89 | else { 90 | mxFree(sockType); 91 | mexErrMsgIdAndTxt("zmq:core:socket:unknownSocketType", 92 | "Error: Unknown socket type."); 93 | } 94 | 95 | coreAPIReturn = zmq_socket(*contextPtr, sockTypeVal); 96 | if (coreAPIReturn == NULL) { 97 | err = errno; 98 | /* Windows users can have problems with errno, see http://api.zeromq.org/4-0:zmq-errno */ 99 | if (err == 0) err = zmq_errno(); 100 | 101 | switch (errno) { 102 | case EINVAL: 103 | mexErrMsgIdAndTxt("zmq:core:socket:unknownSocketTypeCore", 104 | "Error: Unknown socket type (core)." 105 | "\n(original message: %s)", zmq_strerror(err)); 106 | break; 107 | case EFAULT: 108 | mexErrMsgIdAndTxt("zmq:core:socket:invalidContext", 109 | "Error: Invalid ZMQ context." 110 | "\n(original message: %s)", zmq_strerror(err)); 111 | break; 112 | case EMFILE: 113 | mexErrMsgIdAndTxt("zmq:core:socket:maxSocketsReached", 114 | "Error: Max sockets reached on context." 115 | "\n(original message: %s)", zmq_strerror(err)); 116 | break; 117 | case ETERM: 118 | mexErrMsgIdAndTxt("zmq:core:socket:contextTerminated", 119 | "Error: ZMQ context was terminated." 120 | "\n(original message: %s)", zmq_strerror(err)); 121 | break; 122 | default: 123 | mexErrMsgIdAndTxt("zmq:core:socket:unknownOops", 124 | "Error: Something has gone very, very wrong. Unknown error." 125 | "\n(original message: %s)", zmq_strerror(err)); 126 | } 127 | } 128 | return coreAPIReturn; 129 | } 130 | -------------------------------------------------------------------------------- /src/core/unbind.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) 8 | { 9 | void* socket = NULL; 10 | char* endpoint = NULL; 11 | int rc; 12 | 13 | if (nrhs != 2) { 14 | mexErrMsgIdAndTxt("zmq:core:unbind:invalidArgs", 15 | "Error: Two arguments are required: socket, endpoint."); 16 | return; 17 | } 18 | if (mxIsChar(prhs[1]) != 1) { 19 | mexErrMsgIdAndTxt("zmq:core:unbind:invalidEndpoint", 20 | "Error: endpoint is not a string."); 21 | return; 22 | } 23 | if (mxGetM(prhs[1]) != 1) { 24 | mexErrMsgIdAndTxt("zmq:core:unbind:endpointNotRowVec", 25 | "Error: endpoint is not a row vector."); 26 | return; 27 | } 28 | 29 | socket = pointer_from_m(prhs[0]); 30 | if (socket == NULL) return; 31 | 32 | endpoint = (char*) str_from_m(prhs[1]); 33 | if (endpoint == NULL) return; 34 | 35 | rc = zmq_unbind(socket, endpoint); 36 | 37 | if (rc < 0) handle_error(); 38 | else plhs[0] = int_to_m((void*) &rc); 39 | 40 | mxFree(endpoint); 41 | } 42 | -------------------------------------------------------------------------------- /src/core/version.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) 6 | { 7 | int minor, major, patch, bufLen = 50; 8 | char *outputBuf; 9 | 10 | zmq_version(&major, &minor, &patch); 11 | 12 | if (nlhs < 1) { 13 | mexPrintf("ZMQ Version %d.%d.%d\n", major, minor, patch); 14 | } else if (nlhs > 1) { 15 | mexErrMsgTxt("Too many output arguments."); 16 | } else { 17 | outputBuf = mxCalloc(bufLen, sizeof(char)); 18 | sprintf(outputBuf, "%d.%d.%d", major, minor, patch); 19 | plhs[0] = mxCreateString(outputBuf); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/util/conversions.c: -------------------------------------------------------------------------------- 1 | #include "conversions.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | /* -- from C to MATLAB ------------------------------------------------------ */ 8 | 9 | mxArray* uint64_matrix_to_m(void* handle, size_t m, size_t n) { 10 | mxArray* ret; 11 | uint64_t* input; 12 | uint64_t* output; 13 | int i, j; 14 | 15 | input = (uint64_t*) handle; 16 | 17 | ret = mxCreateNumericMatrix(m, n, mxUINT64_CLASS, mxREAL); 18 | output = (uint64_t*) mxGetData(ret); 19 | 20 | for (i = 0; i < m; i++) { 21 | for (j = 0; j < n; j++) { 22 | output[j*m + i] = (uint64_t) input[i*n + j]; 23 | } 24 | } 25 | 26 | return ret; 27 | } 28 | 29 | mxArray* int64_matrix_to_m(void* handle, size_t m, size_t n) { 30 | mxArray* ret; 31 | int64_t* input; 32 | int64_t* output; 33 | int i, j; 34 | 35 | input = (int64_t*) handle; 36 | 37 | ret = mxCreateNumericMatrix(m, n, mxINT64_CLASS, mxREAL); 38 | output = (int64_t*) mxGetData(ret); 39 | 40 | for (i = 0; i < m; i++) { 41 | for (j = 0; j < n; j++) { 42 | output[j*m + i] = (int64_t) input[i*n + j]; 43 | } 44 | } 45 | 46 | return ret; 47 | } 48 | 49 | mxArray* uint32_matrix_to_m(void* handle, size_t m, size_t n) { 50 | mxArray* ret; 51 | uint32_t* input; 52 | uint32_t* output; 53 | int i, j; 54 | 55 | input = (uint32_t*) handle; 56 | 57 | ret = mxCreateNumericMatrix(m, n, mxUINT32_CLASS, mxREAL); 58 | output = (uint32_t*) mxGetData(ret); 59 | 60 | for (i = 0; i < m; i++) { 61 | for (j = 0; j < n; j++) { 62 | output[j*m + i] = (uint32_t) input[i*n + j]; 63 | } 64 | } 65 | 66 | return ret; 67 | } 68 | 69 | /* TODO: discover the exact size of platform default int */ 70 | mxArray* int_matrix_to_m(void* handle, size_t m, size_t n) { 71 | mxArray* ret; 72 | int* input; 73 | int32_t* output; 74 | int i, j; 75 | 76 | input = (int*) handle; 77 | 78 | ret = mxCreateNumericMatrix(m, n, mxINT32_CLASS, mxREAL); 79 | output = (int32_t*) mxGetData(ret); 80 | 81 | for (i = 0; i < m; i++) { 82 | for (j = 0; j < n; j++) { 83 | output[j*m + i] = (int32_t) input[i*n + j]; 84 | } 85 | } 86 | 87 | return ret; 88 | } 89 | 90 | mxArray* uint8_array_to_m(void* handle, size_t n) { 91 | mxArray* ret; 92 | uint8_t* input; 93 | uint8_t* output; 94 | 95 | input = (uint8_t*) handle; 96 | 97 | ret = mxCreateNumericMatrix(1, n, mxUINT8_CLASS, mxREAL); 98 | output = (uint8_t*) mxGetData(ret); 99 | 100 | memcpy(output, input, n*sizeof(uint8_t)); 101 | 102 | return ret; 103 | } 104 | 105 | 106 | mxArray* size_t_to_m(void* handle) { 107 | mxArray* ret; 108 | uint64_t* output; 109 | 110 | ret = mxCreateNumericMatrix(1, 1, mxUINT64_CLASS, mxREAL); 111 | 112 | output = (uint64_t*) mxGetData(ret); 113 | output[0] = (uint64_t) *((size_t*) handle); 114 | 115 | return ret; 116 | } 117 | 118 | mxArray* uint64_to_m(void* handle) { 119 | return uint64_matrix_to_m(handle, 1, 1); 120 | } 121 | 122 | mxArray* int64_to_m(void* handle) { 123 | return int64_matrix_to_m(handle, 1, 1); 124 | } 125 | 126 | mxArray* uint32_to_m(void* handle) { 127 | return uint32_matrix_to_m(handle, 1, 1); 128 | } 129 | 130 | mxArray* int_to_m(void* handle) { 131 | return int_matrix_to_m(handle, 1, 1); 132 | } 133 | 134 | mxArray* str_to_m(void* handle) { 135 | return mxCreateString((char*) handle); 136 | } 137 | 138 | mxArray* pointer_to_m(void* handle) { 139 | mxArray* ret; 140 | void** output; 141 | 142 | if (sizeof(void*) == 4) { 143 | ret = mxCreateNumericMatrix(1, 1, mxUINT32_CLASS, mxREAL); 144 | } else { 145 | ret = mxCreateNumericMatrix(1, 1, mxUINT64_CLASS, mxREAL); 146 | } 147 | 148 | output = (void**) mxGetData(ret); 149 | output[0] = handle; 150 | 151 | return ret; 152 | } 153 | 154 | 155 | /* -- from MATLAB to C ------------------------------------------------------ */ 156 | 157 | /* 158 | We can discover matrix shape from handle, but enforcing n as argument 159 | ensures that caller would know it also... 160 | 161 | (Unfortunally there is no simple way to have 2 returns: pointer and n) 162 | */ 163 | void* uint8_array_from_m(const mxArray* param, size_t n) { 164 | uint8_t* input = NULL; 165 | uint8_t* output = NULL; 166 | 167 | input = (uint8_t*) mxGetData(param); 168 | output = (uint8_t*) mxCalloc(n, sizeof(uint8_t)); 169 | 170 | if (output == NULL) { 171 | mexErrMsgIdAndTxt("util:calloc", "Error: Unsuccessful memory allocation."); 172 | } 173 | 174 | return memcpy(output, input, n*sizeof(uint8_t)); 175 | } 176 | 177 | void* size_t_from_m(const mxArray* param) { 178 | size_t* output = NULL; 179 | output = (size_t*) mxCalloc(1, sizeof(size_t)); 180 | 181 | if (output == NULL) { 182 | mexErrMsgIdAndTxt("util:calloc", "Error: Unsuccessful memory allocation."); 183 | } 184 | 185 | *output = (size_t) mxGetScalar(param); 186 | 187 | return (void*) output; 188 | } 189 | 190 | void* uint64_from_m(const mxArray* param) { 191 | uint64_t* output = NULL; 192 | output = (uint64_t*) mxCalloc(1, sizeof(uint64_t)); 193 | 194 | if (output == NULL) { 195 | mexErrMsgIdAndTxt("util:calloc", "Error: Unsuccessful memory allocation."); 196 | } 197 | 198 | *output = (uint64_t) mxGetScalar(param); 199 | 200 | return (void*) output; 201 | } 202 | 203 | void* int64_from_m(const mxArray* param) { 204 | int64_t* output = NULL; 205 | output = (int64_t*) mxCalloc(1, sizeof(int64_t)); 206 | 207 | if (output == NULL) { 208 | mexErrMsgIdAndTxt("util:calloc", "Error: Unsuccessful memory allocation."); 209 | } 210 | 211 | *output = (int64_t) mxGetScalar(param); 212 | 213 | return (void*) output; 214 | } 215 | 216 | void* uint32_from_m(const mxArray* param) { 217 | uint32_t* output = NULL; 218 | output = (uint32_t*) mxCalloc(1, sizeof(uint32_t)); 219 | 220 | if (output == NULL) { 221 | mexErrMsgIdAndTxt("util:calloc", "Error: Unsuccessful memory allocation."); 222 | } 223 | 224 | *output = (uint32_t) mxGetScalar(param); 225 | 226 | return (void*) output; 227 | } 228 | 229 | void* int_from_m(const mxArray* param) { 230 | int* output = NULL; 231 | output = (int*) mxCalloc(1, sizeof(int)); 232 | 233 | if (output == NULL) { 234 | mexErrMsgIdAndTxt("util:calloc", "Error: Unsuccessful memory allocation."); 235 | } 236 | 237 | *output = (int) mxGetScalar(param); 238 | 239 | return (void*) output; 240 | } 241 | 242 | void* str_from_m(const mxArray* param) { 243 | char* str = NULL; 244 | size_t len; 245 | 246 | len = (size_t) mxGetM(param) * mxGetN(param) + 1; 247 | str = (char*) mxCalloc(len, sizeof(char)); 248 | 249 | if (str == NULL) { 250 | mexErrMsgIdAndTxt("mex:calloc", 251 | "Error: Unsuccessful memory allocation."); 252 | return str; 253 | } 254 | 255 | if (mxGetString(param, str, len) != 0) { 256 | mexErrMsgIdAndTxt("util:str_from_m", 257 | "Error: Couldn't get parameter as string."); 258 | } 259 | 260 | return (void*) str; 261 | } 262 | 263 | void* pointer_from_m(const mxArray* param) { 264 | void** input = NULL; 265 | void* output = NULL; 266 | 267 | input = (void**) mxGetData(param); 268 | output = (void*) input[0]; 269 | 270 | if (output == NULL) { 271 | mexErrMsgIdAndTxt("util:pointer_from_m", "Error: Invalid pointer."); 272 | } 273 | 274 | return output; 275 | } 276 | 277 | 278 | 279 | 280 | 281 | 282 | -------------------------------------------------------------------------------- /src/util/conversions.h: -------------------------------------------------------------------------------- 1 | #ifndef _UTIL_CONVERSIONS_H_ 2 | #define _UTIL_CONVERSIONS_H_ 3 | 4 | #include 5 | 6 | mxArray* uint64_matrix_to_m(void* handle, size_t m, size_t n); 7 | mxArray* int64_matrix_to_m(void* handle, size_t m, size_t n); 8 | mxArray* uint32_matrix_to_m(void* handle, size_t m, size_t n); 9 | mxArray* int_matrix_to_m(void* handle, size_t m, size_t n); 10 | 11 | mxArray* uint8_array_to_m(void* handle, size_t n); 12 | 13 | mxArray* size_t_to_m(void* handle); 14 | mxArray* uint64_to_m(void* handle); 15 | mxArray* int64_to_m(void* handle); 16 | mxArray* uint32_to_m(void* handle); 17 | mxArray* int_to_m(void* handle); 18 | mxArray* str_to_m(void* handle); 19 | mxArray* pointer_to_m(void* handle); 20 | 21 | void* uint8_array_from_m(const mxArray* param, size_t n); 22 | 23 | void* size_t_from_m(const mxArray* param); 24 | void* uint64_from_m(const mxArray* param); 25 | void* int64_from_m(const mxArray* param); 26 | void* uint32_from_m(const mxArray* param); 27 | void* int_from_m(const mxArray* param); 28 | void* str_from_m(const mxArray* param); 29 | void* pointer_from_m(const mxArray* param); 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /src/util/errors.c: -------------------------------------------------------------------------------- 1 | #include "errors.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | static const error_desc_t errorLookup[] = { 8 | {EADDRINUSE , "EADDRINUSE" }, 9 | {EADDRNOTAVAIL , "EADDRNOTAVAIL" }, 10 | {EAGAIN , "EAGAIN" }, 11 | {EFAULT , "EFAULT" }, 12 | {EFSM , "EFSM" }, 13 | {EHOSTUNREACH , "EHOSTUNREACH" }, 14 | {EINTR , "EINTR" }, 15 | {EINVAL , "EINVAL" }, 16 | {EMFILE , "EMFILE" }, 17 | {EMTHREAD , "EMTHREAD" }, 18 | {ENOCOMPATPROTO , "ENOCOMPATPROTO" }, 19 | {ENODEV , "ENODEV" }, 20 | {ENOMEM , "ENOMEM" }, 21 | {ENOTSOCK , "ENOTSOCK" }, 22 | {ENOTSUP , "ENOTSUP" }, 23 | {EPROTONOSUPPORT , "EPROTONOSUPPORT"}, 24 | {ETERM , "ETERM" }, 25 | {0 , "unknownOops" } 26 | }; 27 | 28 | const error_desc_t* find_error_by_id(int id) { 29 | int i; 30 | 31 | for (i = 0; errorLookup[i].id != 0; i++) { 32 | if (errorLookup[i].id == id) break; 33 | } 34 | 35 | return &(errorLookup[i]); 36 | } 37 | 38 | void handle_error() { 39 | int err; 40 | char identifier[255]; /* I think it's large enough */ 41 | const char* message; 42 | const char* caller; 43 | const error_desc_t* errDesc; 44 | 45 | err = errno; 46 | /* Windows users can have problems with errno, see http://api.zeromq.org/master:zmq-errno */ 47 | if (err == 0) 48 | err = zmq_errno(); 49 | 50 | if (err) { 51 | message = (const char*) zmq_strerror(err); 52 | caller = mexFunctionName(); 53 | errDesc = find_error_by_id(err); 54 | 55 | if (message == NULL) 56 | message = "Error: Something has gone very, very wrong. Unknown error."; 57 | 58 | if (caller == NULL) { 59 | sprintf(identifier, "zmq:%s", errDesc->name); 60 | } else { 61 | sprintf(identifier, "zmq:core:%s:%s", caller, errDesc->name); 62 | } 63 | 64 | mexErrMsgIdAndTxt(identifier, message); 65 | } 66 | } -------------------------------------------------------------------------------- /src/util/errors.h: -------------------------------------------------------------------------------- 1 | #ifndef _UTIL_ERRORS_H_ 2 | #define _UTIL_ERRORS_H_ 3 | 4 | typedef struct _error_desc { 5 | int id; 6 | const char* name; 7 | } error_desc_t; 8 | 9 | void handle_error(void); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /src/util/socket.c: -------------------------------------------------------------------------------- 1 | #include "socket.h" 2 | #include "conversions.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | /* 9 | Lookupt table with metadata used to interpret socket types. 10 | 11 | The field `id` is the constant defined in `zmq.h`. 12 | The field `name` is the string representing this constant. 13 | */ 14 | static const zmq_socket_type_t socketTypeLookup[] = { 15 | {ZMQ_PAIR , "ZMQ_PAIR" } , 16 | {ZMQ_PUB , "ZMQ_PUB" } , 17 | {ZMQ_SUB , "ZMQ_SUB" } , 18 | {ZMQ_REQ , "ZMQ_REQ" } , 19 | {ZMQ_REP , "ZMQ_REP" } , 20 | {ZMQ_DEALER , "ZMQ_DEALER"} , 21 | {ZMQ_ROUTER , "ZMQ_ROUTER"} , 22 | {ZMQ_PULL , "ZMQ_PULL" } , 23 | {ZMQ_PUSH , "ZMQ_PUSH" } , 24 | {ZMQ_XPUB , "ZMQ_XPUB" } , 25 | {ZMQ_XSUB , "ZMQ_XSUB" } , 26 | {ZMQ_STREAM , "ZMQ_STREAM"} , 27 | {-1 , NULL } 28 | }; 29 | 30 | /* 31 | Find the metadata related to the socket type. 32 | 33 | ## Arguments 34 | - type: pointer to string, containing the type, e.g. "ZMQ_REQ" 35 | 36 | ## Return 37 | Pointer to a struct with metada (`zmq_socket_type_t`) 38 | */ 39 | const zmq_socket_type_t* find_socket_type_by_name(char* type) { 40 | int i; 41 | const zmq_socket_type_t* descriptor = NULL; 42 | 43 | /* 44 | TODO: as `socketTypeLookup` table order can be chosen arbitrarily, 45 | we can use binary search to speed up this process. 46 | */ 47 | for (i = 0; socketTypeLookup[i].name != NULL; i++) { 48 | if (!strcmp(type, socketTypeLookup[i].name)) { 49 | descriptor = &(socketTypeLookup[i]); 50 | break; 51 | } 52 | } 53 | 54 | if (descriptor == NULL) { 55 | mexErrMsgIdAndTxt("zmq:core:socket:invalidTypeName", 56 | "Error: socket type %s is invalid.", type); 57 | } 58 | return descriptor; 59 | } 60 | 61 | /* 62 | Find the metadata related to the socket type. 63 | 64 | ## Arguments 65 | - id: integer constant identifying the type, e.g. ZMQ_REQ (defined in zmq.h) 66 | 67 | ## Return 68 | Pointer to a struct with metada (`zmq_socket_type_t`) 69 | */ 70 | const zmq_socket_type_t* find_socket_type_by_id(int id) { 71 | int i; 72 | const zmq_socket_type_t* descriptor = NULL; 73 | 74 | /* 75 | TODO: as `socketTypeLookup` table order can be chosen arbitrarily, 76 | we can use binary search to speed up this process. 77 | */ 78 | for (i = 0; socketTypeLookup[i].name != NULL; i++) { 79 | if (id == socketTypeLookup[i].id) { 80 | descriptor = &(socketTypeLookup[i]); 81 | break; 82 | } 83 | } 84 | 85 | if (descriptor == NULL) { 86 | mexErrMsgIdAndTxt("zmq:core:socket:invalidTypeId", 87 | "Error: socket type %d is invalid.", id); 88 | } 89 | return descriptor; 90 | } 91 | 92 | 93 | /* Custom CONSTANT <=> STRING convertions */ 94 | 95 | mxArray* socktype_to_m(void* handle) { 96 | mxArray* ret; 97 | const zmq_socket_type_t* sockType = NULL; 98 | 99 | sockType = find_socket_type_by_id(*((int*) handle)); 100 | 101 | if (sockType != NULL) ret = (mxArray*) str_to_m((void*) sockType->name); 102 | 103 | return ret; 104 | } 105 | 106 | void* socktype_from_m(const mxArray* param) { 107 | int* output = NULL; 108 | char* name = NULL; 109 | const zmq_socket_type_t* sockType = NULL; 110 | 111 | output = (int*) mxCalloc(1, sizeof(int)); 112 | 113 | if (output == NULL) { 114 | mexErrMsgIdAndTxt("util:calloc", "Error: Unsuccessful memory allocation."); 115 | } 116 | 117 | name = (char*) str_from_m(param); 118 | if (name == NULL) return NULL; 119 | 120 | sockType = find_socket_type_by_name(name); 121 | if (sockType != NULL) *output = sockType->id; 122 | 123 | mxFree(name); 124 | 125 | return (void*) output; 126 | } 127 | 128 | /* Common error handler */ 129 | 130 | void socket_error() { 131 | int err; 132 | 133 | err = errno; 134 | 135 | /* Windows users can have problems with errno, see http://api.zeromq.org/master:zmq-errno */ 136 | if (err == 0) err = zmq_errno(); 137 | 138 | switch (err) { 139 | case EINVAL: 140 | mexErrMsgIdAndTxt("zmq:core:socket:invalidOptsCore", 141 | "Error: The core API reports that something has gone wrong." 142 | "\n(original message: %s)", zmq_strerror(err)); 143 | break; 144 | case ETERM: 145 | mexErrMsgIdAndTxt("zmq:core:socket:contextTerm", 146 | "Error: The context associated with the socket was terminated." 147 | "\n(original message: %s)", zmq_strerror(err)); 148 | break; 149 | case EFAULT: 150 | case ENOTSOCK: 151 | mexErrMsgIdAndTxt("zmq:core:socket:invalidSocket", 152 | "Error: Invalid socket." 153 | "\n(original message: %s)", zmq_strerror(err)); 154 | break; 155 | case EINTR: 156 | mexErrMsgIdAndTxt("zmq:core:socket:interrupted", 157 | "Error: The operation was interrupted by a signal." 158 | "\n(original message: %s)", zmq_strerror(err)); 159 | break; 160 | default: 161 | mexErrMsgIdAndTxt("zmq:unknownOops", 162 | "Error: Something has gone very, very wrong. Unknown error." 163 | "\n(original message: %s)", zmq_strerror(err)); 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /src/util/socket.h: -------------------------------------------------------------------------------- 1 | #ifndef _UTIL_SOCKET_H_ 2 | #define _UTIL_SOCKET_H_ 3 | 4 | #include 5 | 6 | /* 7 | Struct with metadata fields, used to interpret socket types. 8 | 9 | The field `id` is the constant defined in `zmq.h`. 10 | The field `name` is the string representing this constant. 11 | */ 12 | typedef struct _stype_desc { 13 | int id; 14 | const char* name; 15 | } zmq_socket_type_t; 16 | 17 | const zmq_socket_type_t* find_socket_type_by_id(int id); 18 | const zmq_socket_type_t* find_socket_type_by_name(char* type); 19 | 20 | /* Extra conversions CONST => STRING */ 21 | mxArray* socktype_to_m(void* handle); 22 | void* socktype_from_m(const mxArray* param); 23 | 24 | /* Common error handler */ 25 | void socket_error(); 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /src/util/sockopt.c: -------------------------------------------------------------------------------- 1 | #include "socket.h" 2 | #include "sockopt.h" 3 | #include "conversions.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | /* 10 | Lookupt table with metadata used to interpret socket options. 11 | 12 | The field `id` is the constant defined in `zmq.h`. 13 | The field `name` is the string representing this constant. 14 | The field `typeId` is a constant, describing the type for option value, 15 | e.g. utin64, string, etc... 16 | 17 | Information used to construct this table can found in: 18 | - http://api.zeromq.org/master:zmq-getsockopt 19 | - http://api.zeromq.org/master:zmq-setsockopt 20 | - https://github.com/zeromq/czmq/blob/master/src/sockopts.xml 21 | 22 | WARNING: Option type seems to depend on ZMQ version, and documentation is not 23 | 100% reliable. 24 | TODO:generate this table automatically using iMatix gsl... 25 | */ 26 | static const zmq_sockopt_desc_t sockOptLookup[] = { 27 | {ZMQ_TYPE , "ZMQ_TYPE" , SOPT_SOCKTYPE } , 28 | {ZMQ_RCVMORE , "ZMQ_RCVMORE" , SOPT_INT } , 29 | {ZMQ_SNDHWM , "ZMQ_SNDHWM" , SOPT_INT } , 30 | {ZMQ_RCVHWM , "ZMQ_RCVHWM" , SOPT_INT } , 31 | {ZMQ_AFFINITY , "ZMQ_AFFINITY" , SOPT_UINT64 } , 32 | {ZMQ_SUBSCRIBE , "ZMQ_SUBSCRIBE" , SOPT_STRING } , 33 | {ZMQ_UNSUBSCRIBE , "ZMQ_UNSUBSCRIBE" , SOPT_STRING } , 34 | {ZMQ_IDENTITY , "ZMQ_IDENTITY" , SOPT_STRING } , 35 | {ZMQ_RATE , "ZMQ_RATE" , SOPT_INT } , 36 | {ZMQ_RECOVERY_IVL , "ZMQ_RECOVERY_IVL" , SOPT_INT } , 37 | {ZMQ_SNDBUF , "ZMQ_SNDBUF" , SOPT_INT } , 38 | {ZMQ_RCVBUF , "ZMQ_RCVBUF" , SOPT_INT } , 39 | {ZMQ_LINGER , "ZMQ_LINGER" , SOPT_INT } , 40 | {ZMQ_RECONNECT_IVL , "ZMQ_RECONNECT_IVL" , SOPT_INT } , 41 | {ZMQ_RECONNECT_IVL_MAX , "ZMQ_RECONNECT_IVL_MAX" , SOPT_INT } , 42 | {ZMQ_BACKLOG , "ZMQ_BACKLOG" , SOPT_INT } , 43 | {ZMQ_MAXMSGSIZE , "ZMQ_MAXMSGSIZE" , SOPT_INT64 } , 44 | {ZMQ_MULTICAST_HOPS , "ZMQ_MULTICAST_HOPS" , SOPT_INT } , 45 | {ZMQ_RCVTIMEO , "ZMQ_RCVTIMEO" , SOPT_INT } , 46 | {ZMQ_SNDTIMEO , "ZMQ_SNDTIMEO" , SOPT_INT } , 47 | {ZMQ_IPV6 , "ZMQ_IPV6" , SOPT_INT } , 48 | {ZMQ_IPV4ONLY , "ZMQ_IPV4ONLY" , SOPT_INT } , 49 | {ZMQ_IMMEDIATE , "ZMQ_IMMEDIATE" , SOPT_INT } , 50 | #if defined _WIN32 51 | /* 52 | _WIN32 is always defined , even for 64 bits , 53 | see http://jpassing.com/2011/05/02/ifdef-_win32 54 | http://msdn.microsoft.com/en-us/library/b0084kay.aspx 55 | */ 56 | {ZMQ_FD , "ZMQ_FD" , SOPT_SOCKET } , 57 | #else 58 | {ZMQ_FD , "ZMQ_FD" , SOPT_INT } , 59 | #endif 60 | {ZMQ_EVENTS , "ZMQ_EVENTS" , SOPT_INT } , 61 | {ZMQ_LAST_ENDPOINT , "ZMQ_LAST_ENDPOINT" , SOPT_STRING } , 62 | {ZMQ_ROUTER_MANDATORY , "ZMQ_ROUTER_MANDATORY" , SOPT_INT } , 63 | {ZMQ_ROUTER_RAW , "ZMQ_ROUTER_RAW" , SOPT_INT } , 64 | {ZMQ_PROBE_ROUTER , "ZMQ_PROBE_ROUTER" , SOPT_INT } , 65 | {ZMQ_XPUB_VERBOSE , "ZMQ_XPUB_VERBOSE" , SOPT_INT } , 66 | {ZMQ_REQ_CORRELATE , "ZMQ_REQ_CORRELATE" , SOPT_INT } , 67 | {ZMQ_REQ_RELAXED , "ZMQ_REQ_RELAXED" , SOPT_INT } , 68 | {ZMQ_TCP_KEEPALIVE , "ZMQ_TCP_KEEPALIVE" , SOPT_INT } , 69 | {ZMQ_TCP_KEEPALIVE_IDLE , "ZMQ_TCP_KEEPALIVE_IDLE" , SOPT_INT } , 70 | {ZMQ_TCP_KEEPALIVE_CNT , "ZMQ_TCP_KEEPALIVE_CNT" , SOPT_INT } , 71 | {ZMQ_TCP_KEEPALIVE_INTVL , "ZMQ_TCP_KEEPALIVE_INTVL" , SOPT_INT } , 72 | {ZMQ_TCP_ACCEPT_FILTER , "ZMQ_TCP_ACCEPT_FILTER" , SOPT_STRING } , 73 | {ZMQ_MECHANISM , "ZMQ_MECHANISM" , SOPT_MECHANISM } , 74 | {ZMQ_PLAIN_SERVER , "ZMQ_PLAIN_SERVER" , SOPT_INT } , 75 | {ZMQ_PLAIN_USERNAME , "ZMQ_PLAIN_USERNAME" , SOPT_STRING } , 76 | {ZMQ_PLAIN_PASSWORD , "ZMQ_PLAIN_PASSWORD" , SOPT_STRING } , 77 | {ZMQ_CURVE_SERVER , "ZMQ_CURVE_SERVER" , SOPT_INT } , 78 | {ZMQ_CURVE_PUBLICKEY , "ZMQ_CURVE_PUBLICKEY" , SOPT_KEY } , 79 | {ZMQ_CURVE_SECRETKEY , "ZMQ_CURVE_SECRETKEY" , SOPT_KEY } , 80 | {ZMQ_CURVE_SERVERKEY , "ZMQ_CURVE_SERVERKEY" , SOPT_KEY } , 81 | {ZMQ_ZAP_DOMAIN , "ZMQ_ZAP_DOMAIN" , SOPT_STRING } , 82 | {ZMQ_CONFLATE , "ZMQ_CONFLATE" , SOPT_INT } , 83 | /* END of array (`name` member of string **MUST** be NULL)*/ 84 | {-1 , NULL , -1 } 85 | }; 86 | 87 | /* 88 | Lookup table with metadata used to interpret/convert socket option types. 89 | 90 | The field `id` is a constant, identifying the type. 91 | The field `maxLen` is the maximum number of bytes that can be used for the 92 | option. 93 | The field `to_m` is a function pointer, that can be used to convert from C 94 | value to MATLAB. 95 | */ 96 | static const zmq_sockopt_type_t sockOptTypeLookup[] = { 97 | {SOPT_UINT64 , sizeof(uint64_t) , uint64_to_m , uint64_from_m } , 98 | {SOPT_INT64 , sizeof(int64_t) , int64_to_m , int64_from_m } , 99 | {SOPT_UINT32 , sizeof(uint32_t) , uint32_to_m , uint32_from_m } , 100 | {SOPT_INT , sizeof(int) , int_to_m , int_from_m } , 101 | {SOPT_STRING , 255*sizeof(char) , str_to_m , str_from_m } , 102 | {SOPT_KEY , 41*sizeof(char) , str_to_m , str_from_m } , /* Z85 key (40) + terminator (1) */ 103 | {SOPT_SOCKTYPE , sizeof(int) , socktype_to_m , socktype_from_m } , 104 | {SOPT_MECHANISM , sizeof(int) , mechanism_to_m , mechanism_from_m} , 105 | #if defined _WIN32 106 | {SOPT_SOCKET , sizeof(SOCKET) , pointer_to_m , pointer_from_m } , 107 | #endif 108 | {SOPT_INVALID , 0 , NULL , NULL } 109 | } ; 110 | 111 | /* 112 | Lookupt table with metadata fields, used to interpret security mechanism. 113 | 114 | The field `id` is the constant defined in `zmq.h`. 115 | The field `name` is the string representing this constant. 116 | */ 117 | static const zmq_sockopt_mechanism_t sockOptMechanismLookup[] = { 118 | {ZMQ_NULL , "ZMQ_NULL" } , 119 | {ZMQ_PLAIN, "ZMQ_PLAIN"} , 120 | {ZMQ_CURVE, "ZMQ_CURVE"} , 121 | {-1 , NULL } 122 | }; 123 | 124 | /* 125 | Find the metadata related to the socket option. 126 | 127 | ## Arguments 128 | - option: pointer to string, containing the name for the option, e.g. "ZMQ_BACKLOG" 129 | 130 | ## Return 131 | Pointer to a struct with metada (`zmq_sockopt_desc_t`) 132 | */ 133 | const zmq_sockopt_desc_t* find_sockopt_by_name(char* option) { 134 | int i; 135 | const zmq_sockopt_desc_t* descriptor = NULL; 136 | 137 | /* 138 | TODO: as `sockOptLookup` table order can be chosen arbitrarily, 139 | we can use binary search to speed up this process. 140 | */ 141 | for (i = 0; sockOptLookup[i].name != NULL; i++) { 142 | if (!strcmp(option, sockOptLookup[i].name)) { 143 | descriptor = &(sockOptLookup[i]); 144 | break; 145 | } 146 | } 147 | 148 | if (descriptor == NULL) { 149 | mexErrMsgIdAndTxt("zmq:core:sockopt:invalidOptionName", 150 | "Error: socket_option %s is invalid.", option); 151 | } 152 | return descriptor; 153 | } 154 | 155 | /* 156 | Find the metadata related to the socket option type. 157 | 158 | ## Arguments 159 | - typeId: integer identifying the option type, e.g. SOPT_INT64, SOPT_INT, ... 160 | 161 | ## Return 162 | Pointer to a struct with metada (`zmq_sockopt_type_t`) 163 | */ 164 | const zmq_sockopt_type_t* find_sockopt_type_by_id(int typeId) { 165 | int i; 166 | const zmq_sockopt_type_t* descriptor = NULL; 167 | 168 | /* 169 | TODO: as `typeId` values can be chosen arbitrarily, as well as 170 | sockOptTypeLookup table order, we can use binary search to speed up this 171 | process. Although, the table is small... 172 | */ 173 | for (i = 0; sockOptTypeLookup[i].id != SOPT_INVALID; i++) { 174 | if (typeId == sockOptTypeLookup[i].id) { 175 | descriptor = &(sockOptTypeLookup[i]); 176 | break; 177 | } 178 | } 179 | if (descriptor == NULL) { 180 | mexErrMsgIdAndTxt("zmq:core:sockopt:invalidOptionTypeId", 181 | "Error: socket_option typeId %d is invalid.", typeId); 182 | } 183 | return descriptor; 184 | } 185 | 186 | /* 187 | Find the metadata related to the socket security mechanism. 188 | 189 | ## Arguments 190 | - mechanismId: integer identifying the option type, e.g. SOPT_INT64, SOPT_INT, ... 191 | 192 | ## Return 193 | Pointer to a struct with metada (`zmq_sockopt_type_t`) 194 | */ 195 | const zmq_sockopt_mechanism_t* find_sockopt_mechanism_by_id(int mechanismId) { 196 | int i; 197 | const zmq_sockopt_mechanism_t* descriptor = NULL; 198 | 199 | /* 200 | TODO: as `typeId` values can be chosen arbitrarily, as well as 201 | sockOptTypeLookup table order, we can use binary search to speed up this 202 | process. Although, the table is small... 203 | */ 204 | for (i = 0; sockOptMechanismLookup[i].name != NULL; i++) { 205 | if (mechanismId == sockOptMechanismLookup[i].id) { 206 | descriptor = &(sockOptMechanismLookup[i]); 207 | break; 208 | } 209 | } 210 | if (descriptor == NULL) { 211 | mexErrMsgIdAndTxt("zmq:core:sockopt:invalidOptionMechanismId", 212 | "Error: socket_option mechanism %d is invalid.", mechanismId); 213 | } 214 | return descriptor; 215 | } 216 | 217 | /* 218 | Find the metadata related to the socket security mechanism. 219 | 220 | ## Arguments 221 | - name: pointer to string, containing the name for the option, e.g. "ZMQ_NULL" 222 | 223 | ## Return 224 | Pointer to a struct with metada (`zmq_sockopt_type_t`) 225 | */ 226 | const zmq_sockopt_mechanism_t* find_sockopt_mechanism_by_name(char* name) { 227 | int i; 228 | const zmq_sockopt_mechanism_t* descriptor = NULL; 229 | 230 | for (i = 0; sockOptMechanismLookup[i].name != NULL; i++) { 231 | if (!strcmp(name, sockOptMechanismLookup[i].name)) { 232 | descriptor = &(sockOptMechanismLookup[i]); 233 | break; 234 | } 235 | } 236 | if (descriptor == NULL) { 237 | mexErrMsgIdAndTxt("zmq:core:sockopt:invalidOptionMechanism", 238 | "Error: socket_option mechanism %s is invalid.", name); 239 | } 240 | return descriptor; 241 | } 242 | 243 | 244 | /* Custom CONSTANT <=> STRING convertions */ 245 | 246 | mxArray* mechanism_to_m(void* handle) { 247 | mxArray* ret; 248 | const zmq_sockopt_mechanism_t* mechanism = NULL; 249 | 250 | mechanism = find_sockopt_mechanism_by_id(*((int*) handle)); 251 | if (mechanism != NULL) ret = (mxArray*) str_to_m((void*) mechanism->name); 252 | 253 | return ret; 254 | } 255 | 256 | void* mechanism_from_m(const mxArray* param) { 257 | int* output = NULL; 258 | char* name = NULL; 259 | const zmq_sockopt_mechanism_t* mechanism = NULL; 260 | 261 | output = (int*) mxCalloc(1, sizeof(int)); 262 | 263 | if (output == NULL) { 264 | mexErrMsgIdAndTxt("util:calloc", "Error: Unsuccessful memory allocation."); 265 | } 266 | 267 | name = (char*) str_from_m(param); 268 | if (name == NULL) return NULL; 269 | 270 | mechanism = find_sockopt_mechanism_by_name(name); 271 | if (mechanism != NULL) *output = mechanism->id; 272 | 273 | mxFree(name); 274 | 275 | return (void*) output; 276 | } 277 | 278 | -------------------------------------------------------------------------------- /src/util/sockopt.h: -------------------------------------------------------------------------------- 1 | #ifndef _UTIL_SOCKOPT_H_ 2 | #define _UTIL_SOCKOPT_H_ 3 | 4 | #include 5 | #include 6 | 7 | enum { 8 | SOPT_UINT64, 9 | SOPT_INT64, 10 | SOPT_UINT32, 11 | SOPT_INT, 12 | SOPT_STRING, 13 | SOPT_KEY, 14 | SOPT_SOCKTYPE, 15 | SOPT_MECHANISM, 16 | #if defined _WIN32 17 | SOPT_SOCKET, 18 | #endif 19 | SOPT_INVALID 20 | }; 21 | 22 | /* 23 | Struct with metadata fields, used to interpret socket options. 24 | 25 | The field `id` is the constant defined in `zmq.h`. 26 | The field `name` is the string representing this constant. 27 | The field `typeId` is a constant, describing the type for option value, 28 | e.g. utin64, string, etc... 29 | */ 30 | typedef struct _sopt_desc { 31 | int id; 32 | const char* name; 33 | int typeId; 34 | } zmq_sockopt_desc_t; 35 | 36 | /* 37 | Struct with metadata fields, used to interpret socket option types. 38 | 39 | The field `id` is a constant, identifying the type. 40 | The field `maxLen` is the maximum number of bytes that can be used for the 41 | option. 42 | The field `to_m` is a function pointer, that can be used to convert from C 43 | value to MATLAB. 44 | */ 45 | typedef struct _sopt_type_desc { 46 | int id; 47 | size_t maxLen; 48 | mxArray* (*to_m)(void* handle); 49 | void* (*from_m)(const mxArray* param); 50 | } zmq_sockopt_type_t; 51 | 52 | /* 53 | Struct with metadata fields, used to interpret security mechanism. 54 | 55 | The field `id` is the constant defined in `zmq.h`. 56 | The field `name` is the string representing this constant. 57 | */ 58 | typedef struct _sopt_mechanism_desc { 59 | int id; 60 | const char* name; 61 | } zmq_sockopt_mechanism_t; 62 | 63 | /* Extra conversions CONST => STRING */ 64 | const zmq_sockopt_desc_t* find_sockopt_by_name(char* option); 65 | const zmq_sockopt_type_t* find_sockopt_type_by_id(int typeId); 66 | 67 | const zmq_sockopt_mechanism_t* find_sockopt_mechanism_by_id(int mechanismId); 68 | const zmq_sockopt_mechanism_t* find_sockopt_mechanism_by_name(char* name); 69 | 70 | mxArray* mechanism_to_m(void* handle) ; 71 | void* mechanism_from_m(const mxArray* param); 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /tests/fixtures/wikipedia.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Wikipedia 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 19 | 20 | 21 | 22 |

23 | WikipediA 24 |

25 | 26 | 27 | 105 | 106 | 107 |
108 | 109 |
110 |
111 | 112 | 113 | 114 | 115 | 116 | 117 | 173 | 174 | 175 | 176 | 177 |
178 |
179 |
180 | 181 |

182 | 183 | 194 | 195 | 196 |

197 | 1 000 000+ 198 |

199 | 200 | 201 |
202 | Deutsch • 203 | English • 204 | Español • 205 | Français • 206 | Italiano • 207 | Nederlands • 208 | Polski • 209 | Русский • 210 | Sinugboanong Binisaya • 211 | Svenska • 212 | Tiếng Việt • 213 | Winaray 214 |
215 | 216 | 217 |

218 | 100 000+ 219 |

220 | 221 | 222 |
223 | العربية • 224 | Azərbaycanca • 225 | Български • 226 | Català • 227 | Česky • 228 | Dansk • 229 | Eesti • 230 | Ελληνικά • 231 | Esperanto • 232 | Euskara • 233 | فارسی • 234 | Galego • 235 | 한국어 • 236 | Հայերեն • 237 | हिन्दी • 238 | Hrvatski • 239 | Bahasa Indonesia • 240 | עברית • 241 | Latina • 242 | Lietuvių • 243 | Magyar • 244 | Bahasa Melayu • 245 | Bahaso Minangkabau • 246 | 日本語 • 247 | Norsk (bokmål • nynorsk) • 248 | Oʻzbekcha / Ўзбекча • 249 | Português • 250 | Қазақша / Qazaqşa / قازاقشا • 251 | Română • 252 | Simple English • 253 | Slovenčina • 254 | Slovenščina • 255 | Српски / Srpski • 256 | Srpskohrvatski / Српскохрватски • 257 | Suomi • 258 | Türkçe • 259 | Українська • 260 | Volapük • 261 | 中文 262 |
263 | 264 | 265 |

266 | 10 000+ 267 |

268 | 269 | 270 |
271 | Afrikaans • 272 | Alemannisch • 273 | አማርኛ • 274 | Aragonés • 275 | Asturianu • 276 | Kreyòl Ayisyen • 277 | বাংলা • 278 | Bân-lâm-gú • 279 | Basa Banyumasan • 280 | Башҡортса • 281 | Беларуская (Акадэмічная • Тарашкевiца) • 282 | বিষ্ণুপ্রিয়া মণিপুরী • 283 | Boarisch • 284 | Bosanski • 285 | Brezhoneg • 286 | Чӑвашла • 287 | Cymraeg • 288 | Føroyskt • 289 | Frysk • 290 | Gaeilge • 291 | Gàidhlig • 292 | ગુજરાતી • 293 | Ido • 294 | Interlingua • 295 | Íslenska • 296 | Basa Jawa • 297 | ಕನ್ನಡ • 298 | ქართული • 299 | Kurdî / كوردی • 300 | Кыргызча • 301 | Latviešu • 302 | Lëtzebuergesch • 303 | Lumbaart • 304 | Македонски • 305 | Malagasy • 306 | മലയാളം • 307 | मराठी • 308 | مصرى • 309 | مازِرونی • 310 | Монгол • 311 | မြန်မာဘာသာ • 312 | Nāhuatl • 313 | नेपाल भाषा • 314 | नेपाली • 315 | Nnapulitano • 316 | Нохчийн • 317 | Occitan • 318 | ਪੰਜਾਬੀ • 319 | Piemontèis • 320 | Plattdüütsch • 321 | Runa Simi • 322 | संस्कृतम् • 323 | Саха Тыла • 324 | شاہ مکھی پنجابی • 325 | Scots • 326 | Shqip • 327 | Sicilianu • 328 | සිංහල • 329 | کوردی • 330 | Basa Sunda • 331 | Kiswahili • 332 | Tagalog • 333 | தமிழ் • 334 | Татарча / Tatarça • 335 | తెలుగు • 336 | Тоҷикӣ • 337 | ภาษาไทย • 338 | ᨅᨔ ᨕᨙᨁᨗ / Basa Ugi • 339 | اردو • 340 | Vèneto • 341 | Walon • 342 | ייִדיש • 343 | Yorùbá • 344 | 粵語 • 345 | Žemaitėška 346 |
347 | 348 | 349 |

350 | 1 000+ 351 |

352 | 353 | 354 |
355 | Bahsa Acèh • 356 | Адыгэбзэ • 357 | Armãneashce • 358 | Arpitan • 359 | ܐܬܘܪܝܐ • 360 | Avañe’ẽ • 361 | Авар • 362 | Aymar • 363 | Ænglisc • 364 | Bahasa Banjar • 365 | भोजपुरी • 366 | Bikol Central • 367 | བོད་ཡིག • 368 | Буряад • 369 | Chavacano de Zamboanga • 370 | Corsu • 371 | Deitsch • 372 | ދިވެހި • 373 | Diné Bizaad • 374 | Dolnoserbski • 375 | Emigliàn–Rumagnòl • 376 | Эрзянь • 377 | Estremeñu • 378 | Fiji Hindi • 379 | Furlan • 380 | Gaelg • 381 | Gagauz • 382 | گیلکی • 383 | 贛語 • 384 | Hak-kâ-fa / 客家話 • 385 | Хальмг • 386 | Hausa / هَوُسَا • 387 | ʻŌlelo Hawaiʻi • 388 | Hornjoserbsce • 389 | Igbo • 390 | Ilokano • 391 | Interlingue • 392 | Иронау • 393 | Kalaallisut • 394 | Kapampangan • 395 | Kaszëbsczi • 396 | Kernewek / Karnuack • 397 | ភាសាខ្មែរ • 398 | Kinyarwanda • 399 | Коми • 400 | Кырык Мары • 401 | Dzhudezmo / לאדינו • 402 | Лакку • 403 | ພາສາລາວ • 404 | Лезги • 405 | Líguru • 406 | Limburgs • 407 | Lingála • 408 | lojban • 409 | Malti • 410 | 文言 • 411 | Reo Mā’ohi • 412 | Māori • 413 | მარგალური • 414 | Mìng-dĕ̤ng-ngṳ̄ • 415 | Mirandés • 416 | Мокшень • 417 | Dorerin Naoero • 418 | Nedersaksisch • 419 | Nordfriisk • 420 | Nouormand / Normaund • 421 | Novial • 422 | Олык Марий • 423 | ଓଡି଼ଆ • 424 | অসমীযা় • 425 | पाऴि • 426 | Pangasinán • 427 | Papiamentu • 428 | پښتو • 429 | Перем Коми • 430 | Pfälzisch • 431 | Picard • 432 | Къарачай–Малкъар • 433 | Qaraqalpaqsha • 434 | Qırımtatarca • 435 | Ripoarisch • 436 | Rumantsch • 437 | Русиньскый Язык • 438 | Sámegiella • 439 | Sardu • 440 | Seeltersk • 441 | ChiShona • 442 | Ślůnski • 443 | Soomaaliga • 444 | Sranantongo • 445 | Taqbaylit • 446 | Tarandíne • 447 | Tetun • 448 | Tok Pisin • 449 | faka Tonga • 450 | Türkmençe • 451 | Удмурт • 452 | Uyghur / ئۇيغۇرچه • 453 | Võro • 454 | Vepsän • 455 | West-Vlams • 456 | Wolof • 457 | 吳語 • 458 | Zazaki • 459 | Zeêuws 460 |
461 | 462 | 463 |

464 | 100+ 465 |

466 | 467 | 468 |
469 | Akan • 470 | Аҧсуа • 471 | Bamanankan • 472 | Bislama • 473 | Chamoru • 474 | Chichewa • 475 | Cuengh • 476 | Eʋegbe • 477 | Fulfulde • 478 | Gĩkũyũ • 479 | 𐌲𐌿𐍄𐌹𐍃𐌺 • 480 | ᐃᓄᒃᑎᑐᑦ / Inuktitut • 481 | Iñupiak • 482 | كشميري • 483 | Kongo • 484 | Latgaļu • 485 | Luganda • 486 | मैथिली • 487 | Молдовеняскэ • 488 | Na Vosa Vaka-Viti • 489 | Nēhiyawēwin / ᓀᐦᐃᔭᐍᐏᐣ • 490 | Norfuk / Pitkern • 491 | Afaan Oromoo • 492 | Ποντιακά • 493 | རྫོང་ཁ • 494 | Romani • 495 | Kirundi • 496 | Gagana Sāmoa • 497 | Sängö • 498 | Sesotho • 499 | Sesotho sa Leboa • 500 | Setswana • 501 | سنڌي • 502 | Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ • 503 | SiSwati • 504 | ትግርኛ • 505 | ᏣᎳᎩ • 506 | chiTumbuka • 507 | Xitsonga • 508 | Tsėhesenėstsestotse • 509 | Tshivenḓa • 510 | Twi • 511 | Тыва дыл • 512 | isiXhosa • 513 | isiZulu 514 |
515 | 516 | 517 |
518 | 519 | 520 | Other languages • 521 | Weitere Sprachen • 522 | Autres langues • 523 | Kompletna lista języków • 524 | 他の言語 • 525 | Otros idiomas • 526 | 其他語言 • 527 | Другие языки • 528 | Aliaj lingvoj • 529 | 다른 언어 • 530 | Ngôn ngữ khác 531 | 532 |
533 | 534 |

535 | 536 | 537 |
538 | 539 |
540 | Wiktionary 541 |
542 | 543 |
544 | Wikinews 545 |
546 | 547 |
548 | Wikiquote 549 |
550 | 551 |
552 | Wikibooks 553 |
554 | 555 |
556 | Wikidata 557 |
558 | 559 |
560 | Wikispecies 561 |
562 | 563 |
564 | Wikisource 565 |
566 | 567 |
568 | Wikiversity 569 |
570 | 571 |
572 | Wikivoyage 573 |
574 | 575 |
576 | Commons 577 |
578 | 579 |
580 | MediaWiki 581 |
582 | 583 |
584 | Meta-Wiki 585 |
586 | 587 |
588 | 589 | 590 |
591 | A Wikimedia Project 592 |
593 | 594 | 595 | 596 | 597 | -------------------------------------------------------------------------------- /tests/runner.m: -------------------------------------------------------------------------------- 1 | function success = runner(varargin) 2 | % Run tests for the library 3 | % 4 | % ## Arguments 5 | % - [...]: variable list of tests. 6 | % 7 | % If no argument is provided, all the files `test*.m` under the directory 8 | % of this file will run. 9 | % 10 | % Notice that the files will be considered relative to this file. 11 | 12 | [testPath, ~, ~] = fileparts(mfilename('fullpath')); 13 | 14 | % save current path 15 | origPath = path; 16 | addpath(testPath); 17 | addpath(fullfile(testPath, 'support')); 18 | cleanupObj = onCleanup(@() path(origPath)); % restore path after finish 19 | 20 | failures = {}; 21 | nfailures = 0; 22 | nsuccess = 0; 23 | 24 | % Get the test files 25 | if (nargin > 0) 26 | tests = varargin; 27 | else 28 | try 29 | if (ispc) 30 | tests = cellstr(ls(fullfile(testPath, 'test*.m'))); 31 | else 32 | tests = strsplit(ls(fullfile(testPath, 'test*.m')),'\n'); 33 | tests = tests(:,1:end-1); 34 | end 35 | catch 36 | tests = {}; 37 | end 38 | end 39 | 40 | tic; 41 | for n = 1:length(tests) 42 | % Failed tests should throw an exception 43 | try 44 | [~, funcname, ~] = fileparts(tests{n}); 45 | fprintf('Running test (%s/%s): %s...', num2str(n), num2str(length(tests)), funcname); 46 | func = str2func(funcname); 47 | func(); 48 | fprintf('[PASS]\n'); 49 | nsuccess = nsuccess + 1; 50 | catch e 51 | fprintf('[FAIL]\n'); 52 | % Check if it is octave (`try...catch` not 100% > needs workaround) 53 | if (exist('OCTAVE_VERSION', 'builtin')) 54 | e = lasterror; 55 | end 56 | % Save the failure, in order to posterior display 57 | nfailures = nfailures + 1; 58 | failures{nfailures} = e; 59 | end 60 | end 61 | 62 | toc; 63 | 64 | if nfailures > 0 65 | success = 0; 66 | % Throw all failures as one 67 | error('Tests: %d passed, %d failed.\n\n%s\n', nsuccess, nfailures, ... 68 | strjoin(cellfun(@reportgen, failures, 'UniformOutput', false), '\n')); 69 | % An error will ensure the exit code different from 0 in case of any not-well-succeeded test. 70 | % This is useful for continuous-integration services. 71 | else 72 | success = 1; 73 | fprintf('%d tests passed, %d failed\n', nsuccess, nfailures); 74 | end 75 | end 76 | 77 | function output = reportgen(err) 78 | stack = find_test(err.stack); 79 | output = sprintf('%s (line %d):\n\t%s\n', stack.name, stack.line, err.message); 80 | end 81 | 82 | function output = find_test(stack) 83 | n = 1; 84 | l = length(stack); 85 | 86 | while (isempty(regexp(stack(n).name, '^test', 'once')) && n < l) 87 | n = n + 1; 88 | end 89 | output = stack(n); 90 | end 91 | -------------------------------------------------------------------------------- /tests/support/assert_does_not_throw.m: -------------------------------------------------------------------------------- 1 | function varargout = assert_does_not_throw(func, varargin) 2 | % Call function, passing the remaining arguments to it, and 3 | % check if an error does not occur 4 | % 5 | % ## Usage 6 | % ```matlab 7 | % assert_does_not_throw(idregex, @func, arg1, arg2, ...); 8 | % % Check if an error (whose identifier matches `idregex`) 9 | % % does not occur when calling `func(arg1, arg2, ...)` 10 | % 11 | % assert_does_not_throw(@func, arg1, arg2, ...); 12 | % assert_does_not_throw('*', @func, arg1, arg2, ...); 13 | % % Check if no error occurs when calling `func(arg1, arg2, ...)` 14 | % ``` 15 | % 16 | % ## Return 17 | % The same as func(arg1, arg2, ...) 18 | 19 | if isa(func, 'function_handle') 20 | idregex = '.*'; 21 | args = varargin; 22 | else 23 | idregex = func; 24 | func = varargin{1}; 25 | args = varargin(2:end); 26 | end 27 | 28 | if strcmp(idregex, '*') 29 | idregex = '.*'; 30 | end 31 | 32 | try 33 | if ~nargout 34 | func(args{:}); 35 | else 36 | [varargout{1:nargout}] = func(args{:}); 37 | end 38 | catch e 39 | % Check if it is octave (`try...catch` not 100% > needs workaround) 40 | if exist('OCTAVE_VERSION', 'builtin') 41 | e = lasterror; 42 | end 43 | 44 | match = regexp(e.identifier, idregex); 45 | if (~isempty(match)) 46 | error('assert:doesNotThrow', 'should not throw (%s) "%s".', e.identifier, e.message); 47 | else 48 | error(e); 49 | end 50 | end 51 | end -------------------------------------------------------------------------------- /tests/support/assert_throw.m: -------------------------------------------------------------------------------- 1 | function varargout = assert_throw(func, varargin) 2 | % Call function, passing the remaining arguments to it, and 3 | % check if a error occurs 4 | % 5 | % ## Usage 6 | % ```matlab 7 | % assert_throw(idregex, @func, arg1, arg2, ...); 8 | % % Check if an error (whose identifier matches `idregex`) 9 | % % occurs when calling `func(arg1, arg2, ...)` 10 | % 11 | % assert_throw('*', @func, arg1, arg2, ...); 12 | % assert_throw(@func, arg1, arg2, ...); 13 | % % Check if any error occurs when calling `func(arg1, arg2, ...)` 14 | % ``` 15 | % 16 | % ## Return 17 | % The same as func(arg1, arg2, ...) 18 | 19 | if isa(func, 'function_handle') 20 | idregex = '.*'; 21 | args = varargin; 22 | else 23 | idregex = func; 24 | func = varargin{1}; 25 | args = varargin(2:end); 26 | end 27 | 28 | if strcmp(idregex, '*') 29 | idregex = '.*'; 30 | end 31 | 32 | try 33 | if ~nargout 34 | func(args{:}); 35 | else 36 | [varargout{1:nargout}] = func(args{:}); 37 | end 38 | catch e 39 | % Check if it is octave (`try...catch` not 100% > needs workaround) 40 | if exist('OCTAVE_VERSION', 'builtin') 41 | e = lasterror; 42 | end 43 | 44 | match = regexp(e.identifier, idregex); 45 | if (isempty(match)) 46 | error('assert:throw', 'should throw "%s". Instead "%s" thrown ("%s").', idregex, ... 47 | e.identifier, e.message); 48 | else 49 | return 50 | end 51 | end 52 | 53 | error('assert:throw:nothingThrown', 'should throw "%s".', idregex); 54 | end -------------------------------------------------------------------------------- /tests/support/text_fixture.m: -------------------------------------------------------------------------------- 1 | function text = text_fixture(name) 2 | [supportPath, ~, ~] = fileparts(mfilename('fullpath')); 3 | [testPath, ~, ~] = fileparts(supportPath); 4 | fixturePath = fullfile(testPath, 'fixtures'); 5 | 6 | fid = fopen(fullfile(fixturePath, name), 'r'); 7 | data = fread(fid)'; 8 | fclose(fid); 9 | text = char(data); 10 | end -------------------------------------------------------------------------------- /tests/test_context_cleanup.m: -------------------------------------------------------------------------------- 1 | function test_context_cleanup 2 | % issues/22 3 | context = zmq.Context(); 4 | socket = context.socket('ZMQ_PUB'); 5 | clear('context'); % Assert do not block 6 | 7 | context = zmq.Context(); 8 | socket = context.socket('ZMQ_PUB'); 9 | context.delete(); % Assert do not block 10 | clear('context'); % Assert do not block 11 | 12 | context = zmq.Context(); 13 | socket = context.socket('ZMQ_PUB'); 14 | socket.delete(); 15 | context.delete(); % Assert do not block 16 | clear('context'); % Assert do not block 17 | end -------------------------------------------------------------------------------- /tests/test_context_get.m: -------------------------------------------------------------------------------- 1 | function test_context_get 2 | context = zmq.Context(); 3 | 4 | % These are what we expect the values to be 5 | % nThreads = 1; ipv6Status = 0; maxSockets = 1023; 6 | 7 | ipv6 = context.get('ZMQ_IPV6'); 8 | assert(ipv6 == 0, 'ZMQ_IPV6 should be 0, %d given', ipv6); 9 | 10 | nThreads = context.get('ZMQ_IO_THREADS'); 11 | assert(nThreads == 1, 'ZMQ_IO_THREADS should 1, %d given', nThreads); 12 | 13 | maxSocks = context.get('ZMQ_MAX_SOCKETS'); 14 | assert(maxSocks==1023 || maxSocks == 1024, ... 15 | 'ZMQ_MAX_SOCKETS should be 1024, %d given', maxSocks); 16 | clear('context'); 17 | end 18 | -------------------------------------------------------------------------------- /tests/test_socket_bind.m: -------------------------------------------------------------------------------- 1 | function test_socket_bind 2 | [ctx, socket] = setup; 3 | cleanupObj = onCleanup(@() cellfun(@(f) f(), ... 4 | {@() clear('socket'), @() teardown(ctx)}, ... 5 | 'UniformOutput', false)); 6 | 7 | %% binding 8 | assert_throw('EPROTONOSUPPORT', @socket.bind, 'abc://localhost'); % invalid transport - TODO sometimes it throws "zmq:core:bind:unknownOops" ("No such file or directory"). 9 | assert_throw('EINVAL', @socket.bind, 'tcp://localhost'); % port must specified 10 | assert_does_not_throw(@socket.bind, 'tcp://127.0.0.1:30000'); 11 | 12 | %% unbinding 13 | assert_throw(@socket.unbind, 'tcp://127.0.0.1:30103'); 14 | assert_does_not_throw(@socket.unbind, 'tcp://127.0.0.1:30000'); 15 | 16 | clear socket; 17 | end 18 | 19 | function [ctx, socket] = setup 20 | % let's just create and destroy a dummy socket 21 | ctx = zmq.core.ctx_new(); 22 | socket = zmq.Socket(ctx, 'pub'); 23 | end 24 | 25 | function teardown(ctx) 26 | % close session 27 | zmq.core.ctx_shutdown(ctx); 28 | zmq.core.ctx_term(ctx); 29 | end 30 | -------------------------------------------------------------------------------- /tests/test_socket_connect.m: -------------------------------------------------------------------------------- 1 | function test_socket_connect 2 | [ctx, socket] = setup; 3 | cleanupObj = onCleanup(@() cellfun(@(f) f(), ... 4 | {@() clear('socket'), @() teardown(ctx)}, ... 5 | 'UniformOutput', false)); 6 | 7 | %% connecting 8 | assert_throw('EPROTONOSUPPORT', @socket.connect, 'abc://localhost'); % invalid transport 9 | assert_throw('EINVAL', @socket.connect, 'tcp://localhost'); % port must specified 10 | assert_does_not_throw(@socket.connect, 'tcp://127.0.0.1:30000'); 11 | 12 | %% disconnecting 13 | assert_throw(@socket.disconnect, 'tcp://127.0.0.1:30103'); 14 | assert_does_not_throw(@socket.disconnect, 'tcp://127.0.0.1:30000'); 15 | end 16 | 17 | function [ctx, socket] = setup 18 | % let's just create and destroy a dummy socket 19 | ctx = zmq.core.ctx_new(); 20 | socket = zmq.Socket(ctx, 'sub'); 21 | end 22 | 23 | function teardown(ctx) 24 | % close session 25 | zmq.core.ctx_shutdown(ctx); 26 | zmq.core.ctx_term(ctx); 27 | end 28 | -------------------------------------------------------------------------------- /tests/test_socket_get.m: -------------------------------------------------------------------------------- 1 | function test_socket_get 2 | [ctx, socket] = setup; 3 | cleanupObj = onCleanup(@() cellfun(@(f) f(), ... 4 | {@() clear('socket'), @() teardown(ctx)}, ... 5 | 'UniformOutput', false)); 6 | 7 | % Table with the default values for options 8 | defaultOptions = { ... 9 | {'type' , 'ZMQ_REP' } , ... 10 | {'rcvmore' , 0 } , ... 11 | {'sndhwm' , 1000 } , ... 12 | {'rcvhwm' , 1000 } , ... 13 | {'affinity' , 0 } , ... 14 | ... % {'identity' , '' } , ... % issues on octave 15 | {'rate' , 100 } , ... 16 | {'recovery_ivl' , 10000 } , ... 17 | {'rcvbuf' , 0 } , ... 18 | {'linger' , -1 } , ... 19 | {'reconnect_ivl' , 100 } , ... 20 | {'reconnect_ivl_max' , 0 } , ... 21 | {'backlog' , 100 } , ... 22 | {'maxmsgsize' , -1 } , ... 23 | {'multicast_hops' , 1 } , ... 24 | {'rcvtimeo' , -1 } , ... 25 | {'sndtimeo' , -1 } , ... 26 | {'ipv6' , 0 } , ... 27 | {'ipv4only' , 1 } , ... 28 | {'immediate' , 0 }, ... 29 | {'tcp_keepalive' , -1 } , ... 30 | {'tcp_keepalive_idle' , -1 } , ... 31 | {'tcp_keepalive_cnt' , -1 } , ... 32 | {'tcp_keepalive_intvl' , -1 } , ... 33 | {'mechanism' , 'ZMQ_NULL'} , ... 34 | {'plain_username' , '' } , ... 35 | {'plain_password' , '' } , ... 36 | }; 37 | 38 | % This loop will test all the socket options against the default values listed 39 | % above. 40 | % 41 | % Once the socket is fresh and unused, all the options should remain with the 42 | % default values. 43 | for n = 1:(length(defaultOptions)-1) 44 | option = defaultOptions{n}{1}; 45 | value = defaultOptions{n}{2}; 46 | 47 | response = assert_does_not_throw(@socket.get, option); 48 | 49 | if ~ischar(value) 50 | condition = response == value; 51 | % display 52 | response = num2str(response); 53 | value = num2str(value); 54 | else 55 | condition = strcmp(value, response); 56 | % display 57 | response = ['"' response '"']; 58 | value = ['"' value '"']; 59 | end 60 | 61 | assert(condition, '%s should be %s, %s given.', option, value, response); 62 | end 63 | end 64 | 65 | function [ctx, socket] = setup 66 | % let's just create and destroy a dummy socket 67 | ctx = zmq.core.ctx_new(); 68 | socket = zmq.Socket(ctx, 'rep'); 69 | end 70 | 71 | function teardown(ctx) 72 | % close session 73 | zmq.core.ctx_shutdown(ctx); 74 | zmq.core.ctx_term(ctx); 75 | end -------------------------------------------------------------------------------- /tests/test_socket_send_recv.m: -------------------------------------------------------------------------------- 1 | function test_socket_send_recv 2 | [ctx, server, client] = setup; 3 | cleanupObj = onCleanup(@() cellfun(@(f) f(), ... 4 | {@() clear('client', 'server'), @() teardown(ctx)}, ... 5 | 'UniformOutput', false)); 6 | 7 | %% client test - request send 8 | msgSent = uint8('request'); 9 | msgSentSz = length(msgSent); 10 | rc = assert_does_not_throw(@client.send, msgSent); 11 | assert(rc == msgSentSz, ... 12 | 'socket.send should return the length of message. Expecting %d, but %d given', ... 13 | msgSentSz, rc); 14 | 15 | %% server test - request receive 16 | [msgRecv, msgRecvSz] = assert_does_not_throw(@server.recv); 17 | assert(msgSentSz == msgRecvSz, ... 18 | 'socket.recv should return the correct length of message. Expecting %d, but %d given', ... 19 | msgSentSz, msgRecvSz); 20 | assert(strcmp(char(msgSent), char(msgRecv)), ... 21 | 'socket.recv should return exactly the sent message. Expecting "%s", but "%s" given', ... 22 | char(msgSent), char(msgRecv)); 23 | 24 | %% server test - response send 25 | msgSent = uint8('response'); 26 | msgSentSz = length(msgSent); 27 | rc = assert_does_not_throw(@server.send, msgSent); 28 | assert(rc == msgSentSz, ... 29 | 'socket.send should return the length of message. Expecting %d, but %d given', ... 30 | msgSentSz, rc); 31 | 32 | %% client test - response receive 33 | delta = 2; % buffer reduction 34 | origState = warning; % save for further restoring 35 | warning('off', 'zmq:core:recv:bufferTooSmall'); 36 | msgRecv = client.recv(msgSentSz-delta, 'dontwait'); 37 | warning(origState); 38 | assert(strcmp(char(msgSent(1:end-delta)), char(msgRecv)), ... 39 | 'socket.recv should return the sent message truncated. Expecting "%s", but "%s" given', ... 40 | char(msgSent(1:end-delta)), char(msgRecv)); 41 | 42 | %% client test - cannot send 2 messages in a row (unless multipart) 43 | assert_does_not_throw(@client.send, msgSent); 44 | assert_throw(@client.send, msgSent); 45 | end 46 | 47 | function [ctx, server, client] = setup 48 | %% open session 49 | ctx = zmq.core.ctx_new(); 50 | 51 | client = zmq.Socket(ctx, 'req'); 52 | client.connect('tcp://127.0.0.1:30000'); 53 | 54 | server = zmq.Socket(ctx, 'rep'); 55 | server.bind('tcp://127.0.0.1:30000'); 56 | end 57 | 58 | function teardown(ctx) 59 | %% close session 60 | zmq.core.ctx_shutdown(ctx); 61 | zmq.core.ctx_term(ctx); 62 | end 63 | -------------------------------------------------------------------------------- /tests/test_socket_send_recv_multipart.m: -------------------------------------------------------------------------------- 1 | function test_socket_send_recv_multipart 2 | [ctx, server, client] = setup; 3 | cleanupObj = onCleanup(@() cellfun(@(f) f(), ... 4 | {@() clear('client', 'server'), @() teardown(ctx)}, ... 5 | 'UniformOutput', false)); 6 | 7 | %% client test - request send 8 | msgSent = uint8('request'); 9 | client.send(msgSent, 'sndmore'); 10 | assert_does_not_throw(@client.send, msgSent); 11 | 12 | %% server test - request receive 13 | msg1 = server.recv; 14 | rc = server.get('rcvmore'); 15 | assert(rc == 1, 'rcvmore option should be 1, while does not receive all parts in a multipart message'); 16 | msg2 = server.recv; 17 | rc = server.get('rcvmore'); 18 | assert(rc == 0, 'rcvmore option should be 0, after receive all parts in a multipart message'); 19 | 20 | %% -------- multipart methods ---------------------------------------------- 21 | original = uint8(text_fixture('wikipedia.html')); 22 | assert_does_not_throw(@server.send_multipart, original); % server send 23 | received = assert_does_not_throw(@client.recv_multipart); % client recv 24 | assert(strcmp(char(received), char(original)),... 25 | ['multipart messages should be transmitted without errors,'... 26 | ' but received differs from original']); 27 | end 28 | 29 | function [ctx, server, client] = setup 30 | %% open session 31 | ctx = zmq.core.ctx_new(); 32 | 33 | client = zmq.Socket(ctx, 'req'); 34 | client.connect('tcp://127.0.0.1:30000'); 35 | 36 | server = zmq.Socket(ctx, 'rep'); 37 | server.bind('tcp://127.0.0.1:30000'); 38 | end 39 | 40 | function teardown(ctx) 41 | %% close session 42 | zmq.core.ctx_shutdown(ctx); 43 | zmq.core.ctx_term(ctx); 44 | end -------------------------------------------------------------------------------- /tests/test_socket_send_recv_string.m: -------------------------------------------------------------------------------- 1 | function test_socket_send_recv_string 2 | [ctx, server, client, encoding] = setup; 3 | cleanupObj = onCleanup(@() cellfun(@(f) f(), ... 4 | {@() clear('client', 'server'), @() teardown(ctx, encoding) }, ... 5 | 'UniformOutput', false)); 6 | 7 | encodingArray = {'UTF-8', 'ISO-8859-1', 'Shift_JIS', 'latin1', 'windows-1252', encoding}; 8 | for n = 1:length(encodingArray) 9 | % Test against several encodings 10 | feature('DefaultCharacterSet', encodingArray{n}); 11 | 12 | original = text_fixture('utf8-sampler.html'); 13 | assert_does_not_throw(@client.send_string, original); % server send 14 | received = assert_does_not_throw(@server.recv_string); % client recv 15 | 16 | difference = find(original ~= received); 17 | assert(strcmp(received, original),... 18 | ['string messages should be transmitted without errors, '... 19 | 'but received differs from original:\n'... 20 | 'ORIGINAL:\n%s\n-------------\n'... 21 | 'RECEIVED:\n%s\n-------------\nEncoding: %s\n'],... 22 | original(difference), received(difference), encodingArray{n}); 23 | 24 | % Restart socket state machine 25 | server.send(uint8(1)); 26 | client.recv(); 27 | end 28 | end 29 | 30 | function [ctx, server, client, encoding] = setup 31 | %% open session 32 | ctx = zmq.core.ctx_new(); 33 | 34 | client = zmq.Socket(ctx, 'req'); 35 | client.connect('tcp://127.0.0.1:30000'); 36 | 37 | server = zmq.Socket(ctx, 'rep'); 38 | server.bind('tcp://127.0.0.1:30000'); 39 | 40 | %% save string encoding 41 | encoding = feature('DefaultCharacterSet'); 42 | end 43 | 44 | function teardown(ctx, encoding) 45 | %% close session 46 | zmq.core.ctx_shutdown(ctx); 47 | zmq.core.ctx_term(ctx); 48 | %% restore string encoding 49 | feature('DefaultCharacterSet', encoding); 50 | end -------------------------------------------------------------------------------- /tests/test_socket_set.m: -------------------------------------------------------------------------------- 1 | function test_socket_set 2 | [ctx, socket] = setup; 3 | cleanupObj = onCleanup(@() cellfun(@(f) f(), ... 4 | {@() clear('socket'), @() teardown(ctx)}, ... 5 | 'UniformOutput', false)); 6 | 7 | % -- Options not tested here------------------------------------------------- % 8 | %% Read-Only properties 9 | % 'ZMQ_TYPE' 10 | % 'ZMQ_RCVMORE' 11 | % 'ZMQ_MECHANISM' 12 | 13 | %% Specific options: 14 | % ZMQ_ROUTER_MANDATORY (w) -> ZMQ_ROUTER 15 | % ZMQ_PROBE_ROUTER (w) -> ZMQ_ROUTER, ZMQ_DEALER, ZMQ_REQ 16 | % ZMQ_REQ_CORRELATE (w), ZMQ_REQ_RELAXED (w) -> ZMQ_REQ 17 | % ZMQ_CONFLATE (w) -> ZMQ_PULL, ZMQ_PUSH, ZMQ_SUB, ZMQ_PUB, ZMQ_DEALER 18 | % ZMQ_SUBSCRIBE (w), ZMQ_UNSUBSCRIBE (w) -> ZMQ_SUB 19 | % ZMQ_IDENTITY (rw) -> ZMQ_REQ, ZMQ_REP, ZMQ_ROUTER, ZMQ_DEALER 20 | % ZMQ_XPUB_VERBOSE (w) -> ZMQ_XPUB 21 | % -------------------------------------------------------------------------- % 22 | 23 | % Table with examples for test socket options 24 | % OBS.: all of them are read-write 25 | commonOptions = { ... 26 | {'sndhwm' , 0 } , ... 27 | {'rcvhwm' , 0 } , ... 28 | {'affinity' , 2 } , ... 29 | {'rate' , 10 } , ... 30 | {'recovery_ivl' , 1000 } , ... 31 | {'sndbuf' , 2 } , ... 32 | {'rcvbuf' , 2 } , ... 33 | {'linger' , 2 } , ... 34 | {'reconnect_ivl' , 120 } , ... 35 | {'reconnect_ivl_max' , 150 } , ... 36 | {'backlog' , 150 } , ... 37 | {'maxmsgsize' , 100 } , ... 38 | {'multicast_hops' , 5 } , ... 39 | {'sndtimeo' , 1 } , ... 40 | {'rcvtimeo' , 1 } , ... 41 | {'ipv6' , 1 } , ... 42 | {'ipv4only' , 0 } , ... 43 | {'immediate' , 1 }, ... 44 | {'tcp_keepalive' , 1 } , ... 45 | {'tcp_keepalive_idle' , 2 } , ... 46 | {'tcp_keepalive_cnt' , 2 } , ... 47 | {'tcp_keepalive_intvl' , 2 } , ... 48 | ... % {'tcp_accept_filter' , '123' } , ... % I don't know how it exactly works 49 | {'plain_server' , 1 } , ... 50 | {'plain_username' , 'user' } , ... 51 | {'plain_password' , 'password'} , ... 52 | {'curve_server' , 1 } ... 53 | ... % {'curve_publickey' , '' } , ... % Z85 text generation/prase not implemented yet 54 | ... % {'curve_secretkey' , '' } , ... % Z85 text generation/prase not implemented yet 55 | ... % {'curve_serverkey' , '' } , ... % Z85 text generation/prase not implemented yet 56 | }; 57 | 58 | % This loop will test all the socket options against the default values listed 59 | % above. 60 | % 61 | % Once the socket is fresh and unused, all the options should remain with the 62 | % default values. 63 | for n = 1:(length(commonOptions)-1) 64 | option = commonOptions{n}{1}; 65 | value = commonOptions{n}{2}; 66 | 67 | assert_does_not_throw(@socket.set, option, value); 68 | 69 | response = socket.get(option); 70 | if ~ischar(value) 71 | condition = response == value; 72 | % display 73 | response = num2str(response); 74 | value = num2str(value); 75 | else 76 | condition = strcmp(value, response); 77 | % display 78 | response = ['"' response '"']; 79 | value = ['"' value '"']; 80 | end 81 | 82 | assert(condition, '%s should be %s, %s given.', option, value, response); 83 | end 84 | end 85 | 86 | function [ctx, socket] = setup 87 | % let's just create and destroy a dummy socket 88 | ctx = zmq.core.ctx_new(); 89 | socket = zmq.Socket(ctx, 'rep'); 90 | end 91 | 92 | function teardown(ctx) 93 | % close session 94 | zmq.core.ctx_shutdown(ctx); 95 | zmq.core.ctx_term(ctx); 96 | end -------------------------------------------------------------------------------- /tests/test_zmq_bind.m: -------------------------------------------------------------------------------- 1 | function test_zmq_bind 2 | [ctx, socket] = setup; 3 | cleanupObj = onCleanup(@() teardown(ctx, socket)); 4 | 5 | %% binding 6 | assert_throw('EPROTONOSUPPORT', @zmq.core.bind, socket, 'abc://localhost'); % invalid transport - TODO sometimes it throws "zmq:core:bind:unknownOops" ("No such file or directory"). 7 | assert_throw('EINVAL', @zmq.core.bind, socket, 'tcp://localhost'); % port must specified 8 | response = assert_does_not_throw(@zmq.core.bind, socket, 'tcp://127.0.0.1:30000'); 9 | assert(response == 0, 'status code should be 0, %d given.', response); 10 | 11 | %% unbinding 12 | assert_throw(@zmq.core.unbind, socket, 'tcp://127.0.0.1:30103'); 13 | response = assert_does_not_throw(@zmq.core.unbind, socket, 'tcp://127.0.0.1:30000'); 14 | assert(response == 0, 'status code should be 0, %d given.', response); 15 | end 16 | 17 | function [ctx, socket] = setup 18 | % let's just create and destroy a dummy socket 19 | ctx = zmq.core.ctx_new(); 20 | socket = zmq.core.socket(ctx, 'ZMQ_PUB'); 21 | end 22 | 23 | function teardown(ctx, socket) 24 | % close session 25 | zmq.core.close(socket); 26 | zmq.core.ctx_shutdown(ctx); 27 | zmq.core.ctx_term(ctx); 28 | end 29 | -------------------------------------------------------------------------------- /tests/test_zmq_connect.m: -------------------------------------------------------------------------------- 1 | function test_zmq_connect 2 | [ctx, socket] = setup; 3 | cleanupObj = onCleanup(@() teardown(ctx, socket)); 4 | 5 | %% connecting 6 | assert_throw('EPROTONOSUPPORT', @zmq.core.connect, socket, 'abc://localhost'); % invalid transport 7 | assert_throw('EINVAL', @zmq.core.connect, socket, 'tcp://localhost'); % port must specified 8 | response = assert_does_not_throw(@zmq.core.connect, socket, 'tcp://127.0.0.1:30000'); 9 | assert(response == 0, 'status code should be 0, %d given.', response); 10 | 11 | %% disconnecting 12 | assert_throw(@zmq.core.disconnect, socket, 'tcp://127.0.0.1:30103'); 13 | response = assert_does_not_throw(@zmq.core.disconnect, socket, 'tcp://127.0.0.1:30000'); 14 | assert(response == 0, 'status code should be 0, %d given.', response); 15 | end 16 | 17 | function [ctx, socket] = setup 18 | % let's just create and destroy a dummy socket 19 | ctx = zmq.core.ctx_new(); 20 | socket = zmq.core.socket(ctx, 'ZMQ_SUB'); 21 | end 22 | 23 | function teardown(ctx, socket) 24 | % close session 25 | zmq.core.close(socket); 26 | zmq.core.ctx_shutdown(ctx); 27 | zmq.core.ctx_term(ctx); 28 | end 29 | -------------------------------------------------------------------------------- /tests/test_zmq_ctx_get.m: -------------------------------------------------------------------------------- 1 | function test_zmq_ctx_get 2 | ctx = setup; 3 | cleanupObj = onCleanup(@() teardown(ctx)); 4 | 5 | % Once the context is fresh and unused, all the options should remain with the 6 | % default values. 7 | 8 | % ZMQ_IO_THREADS Default Value: 1 9 | nthreads = zmq.core.ctx_get(ctx, 'ZMQ_IO_THREADS'); 10 | assert(nthreads == 1, 'ZMQ_IO_THREADS should be 1, %d given.', nthreads); 11 | 12 | % ZMQ_IPV6 Default Value: 0 13 | ipv6 = zmq.core.ctx_get(ctx, 'ZMQ_IPV6'); 14 | assert(ipv6 == 0, 'ZMQ_IPV6 should be 0, %d given.', ipv6); 15 | 16 | % ZMQ_MAX_SOCKETS Default Value: 1024 17 | maxs = zmq.core.ctx_get(ctx, 'ZMQ_MAX_SOCKETS'); 18 | assert(maxs == 1024 || maxs == 1023, ... 19 | 'ZMQ_MAX_SOCKETS should be 1024, %d given (I suspect receiving 1023 is OK).', maxs); 20 | % NOTICE: 21 | % According to documentation (http://api.zeromq.org/4-0:zmq-ctx-set) 22 | % it should be 1024, but `zmq.h` defines it as 1023... 23 | end 24 | 25 | function ctx = setup 26 | % let's just create a dummy context 27 | ctx = zmq.core.ctx_new(); 28 | end 29 | 30 | function teardown(ctx) 31 | % close session 32 | zmq.core.ctx_shutdown(ctx); 33 | zmq.core.ctx_term(ctx); 34 | end 35 | -------------------------------------------------------------------------------- /tests/test_zmq_getsockopt.m: -------------------------------------------------------------------------------- 1 | function test_zmq_getsockopt 2 | [ctx, socket] = setup; 3 | cleanupObj = onCleanup(@() teardown(ctx, socket)); 4 | 5 | % Table with the default values for options 6 | defaultOptions = { ... 7 | {'ZMQ_TYPE' , 'ZMQ_REP' } , ... 8 | {'ZMQ_RCVMORE' , 0 } , ... 9 | {'ZMQ_SNDHWM' , 1000 } , ... 10 | {'ZMQ_RCVHWM' , 1000 } , ... 11 | {'ZMQ_AFFINITY' , 0 } , ... 12 | ... % {'ZMQ_IDENTITY' , '' } , ... % issues on octave 13 | {'ZMQ_RATE' , 100 } , ... 14 | {'ZMQ_RECOVERY_IVL' , 10000 } , ... 15 | {'ZMQ_RCVBUF' , 0 } , ... 16 | {'ZMQ_LINGER' , -1 } , ... 17 | {'ZMQ_RECONNECT_IVL' , 100 } , ... 18 | {'ZMQ_RECONNECT_IVL_MAX' , 0 } , ... 19 | {'ZMQ_BACKLOG' , 100 } , ... 20 | {'ZMQ_MAXMSGSIZE' , -1 } , ... 21 | {'ZMQ_MULTICAST_HOPS' , 1 } , ... 22 | {'ZMQ_RCVTIMEO' , -1 } , ... 23 | {'ZMQ_SNDTIMEO' , -1 } , ... 24 | {'ZMQ_IPV6' , 0 } , ... 25 | {'ZMQ_IPV4ONLY' , 1 } , ... 26 | {'ZMQ_IMMEDIATE' , 0 }, ... 27 | {'ZMQ_TCP_KEEPALIVE' , -1 } , ... 28 | {'ZMQ_TCP_KEEPALIVE_IDLE' , -1 } , ... 29 | {'ZMQ_TCP_KEEPALIVE_CNT' , -1 } , ... 30 | {'ZMQ_TCP_KEEPALIVE_INTVL' , -1 } , ... 31 | {'ZMQ_MECHANISM' , 'ZMQ_NULL'} , ... 32 | {'ZMQ_PLAIN_USERNAME' , '' } , ... 33 | {'ZMQ_PLAIN_PASSWORD' , '' } , ... 34 | }; 35 | 36 | % This loop will test all the socket options against the default values listed 37 | % above. 38 | % 39 | % Once the socket is fresh and unused, all the options should remain with the 40 | % default values. 41 | for n = 1:(length(defaultOptions)-1) 42 | option = defaultOptions{n}{1}; 43 | value = defaultOptions{n}{2}; 44 | 45 | response = assert_does_not_throw(@zmq.core.getsockopt, socket, option); 46 | 47 | if ~ischar(value) 48 | condition = response == value; 49 | % display 50 | response = num2str(response); 51 | value = num2str(value); 52 | else 53 | condition = strcmp(value, response); 54 | % display 55 | response = ['"' response '"']; 56 | value = ['"' value '"']; 57 | end 58 | 59 | assert(condition, '%s should be %s, %s given.', option, value, response); 60 | end 61 | end 62 | 63 | function [ctx, socket] = setup 64 | % let's just create and destroy a dummy socket 65 | ctx = zmq.core.ctx_new(); 66 | socket = zmq.core.socket(ctx, 'ZMQ_REP'); 67 | end 68 | 69 | function teardown(ctx, socket) 70 | % close session 71 | zmq.core.close(socket); 72 | zmq.core.ctx_shutdown(ctx); 73 | zmq.core.ctx_term(ctx); 74 | end 75 | -------------------------------------------------------------------------------- /tests/test_zmq_req_rep.m: -------------------------------------------------------------------------------- 1 | function test_zmq_req_rep 2 | [ctx, server, client] = setup; 3 | cleanupObj = onCleanup(@() teardown(ctx, server, client)); 4 | 5 | %% client test - request send 6 | msgSent = uint8('request'); 7 | msgSentSz = length(msgSent); 8 | rc = assert_does_not_throw(@zmq.core.send, client, msgSent); 9 | assert(rc == msgSentSz, ... 10 | 'zmq.core.send should return the length of message. Expecting %d, but %d given', ... 11 | msgSentSz, rc); 12 | 13 | %% server test - request receive 14 | [msgRecv, msgRecvSz] = assert_does_not_throw(@zmq.core.recv, server); 15 | assert(msgSentSz == msgRecvSz, ... 16 | 'zmq.core.recv should return the correct length of message. Expecting %d, but %d given', ... 17 | msgSentSz, msgRecvSz); 18 | assert(strcmp(char(msgSent), char(msgRecv)), ... 19 | 'zmq.core.recv should return exactly the sent message. Expecting "%s", but "%s" given', ... 20 | char(msgSent), char(msgRecv)); 21 | 22 | %% server test - response send 23 | msgSent = uint8('response'); 24 | msgSentSz = length(msgSent); 25 | rc = assert_does_not_throw(@zmq.core.send, server, msgSent); 26 | assert(rc == msgSentSz, ... 27 | 'zmq.core.send should return the length of message. Expecting %d, but %d given', ... 28 | msgSentSz, rc); 29 | 30 | %% client test - response receive 31 | delta = 2; % buffer reduction 32 | origState = warning; % save for further restoring 33 | warning('off', 'zmq:core:recv:bufferTooSmall'); 34 | msgRecv = zmq.core.recv(client, msgSentSz-delta, 'ZMQ_DONTWAIT'); 35 | warning(origState); 36 | assert(strcmp(char(msgSent(1:end-delta)), char(msgRecv)), ... 37 | 'zmq.core.recv should return the sent message truncated. Expecting "%s", but "%s" given', ... 38 | char(msgSent(1:end-delta)), char(msgRecv)); 39 | 40 | %% client test - cannot send 2 messages in a row (unless multipart) 41 | assert_does_not_throw(@zmq.core.send, client, msgSent); 42 | assert_throw(@zmq.core.send, client, msgSent); 43 | end 44 | 45 | function [ctx, server, client] = setup 46 | %% open session 47 | ctx = zmq.core.ctx_new(); 48 | 49 | client = zmq.core.socket(ctx, 'ZMQ_REQ'); 50 | zmq.core.connect(client, 'tcp://127.0.0.1:30000'); 51 | 52 | server = zmq.core.socket(ctx, 'ZMQ_REP'); 53 | zmq.core.bind(server, 'tcp://127.0.0.1:30000'); 54 | end 55 | 56 | function teardown(ctx, server, client) 57 | %% close session 58 | zmq.core.unbind(server, 'tcp://127.0.0.1:30000'); 59 | zmq.core.close(server); 60 | 61 | zmq.core.disconnect(client, 'tcp://127.0.0.1:30000'); 62 | zmq.core.close(client); 63 | 64 | zmq.core.ctx_shutdown(ctx); 65 | zmq.core.ctx_term(ctx); 66 | end 67 | -------------------------------------------------------------------------------- /tests/test_zmq_req_rep_multipart.m: -------------------------------------------------------------------------------- 1 | function test_zmq_req_rep_multipart 2 | [ctx, server, client] = setup; 3 | cleanupObj = onCleanup(@() teardown(ctx, server, client)); 4 | 5 | %% client test - request send 6 | msgSent = uint8('request'); 7 | msgSentSz = length(msgSent); 8 | zmq.core.send(client, msgSent, 'ZMQ_SNDMORE'); 9 | assert_does_not_throw(@zmq.core.send, client, msgSent); 10 | 11 | %% server test - request receive 12 | msg1 = zmq.core.recv(server); 13 | rc = zmq.core.getsockopt(server, 'ZMQ_RCVMORE'); 14 | assert(rc == 1, 'ZMQ_RCVMORE option should be 1, while does not receive all parts in a multipart message'); 15 | msg2 = zmq.core.recv(server); 16 | rc = zmq.core.getsockopt(server, 'ZMQ_RCVMORE'); 17 | assert(rc == 0, 'ZMQ_RCVMORE option should be 0, after receive all parts in a multipart message'); 18 | end 19 | 20 | function [ctx, server, client] = setup 21 | %% open session 22 | ctx = zmq.core.ctx_new(); 23 | 24 | client = zmq.core.socket(ctx, 'ZMQ_REQ'); 25 | zmq.core.connect(client, 'tcp://127.0.0.1:30000'); 26 | 27 | server = zmq.core.socket(ctx, 'ZMQ_REP'); 28 | zmq.core.bind(server, 'tcp://127.0.0.1:30000'); 29 | end 30 | 31 | function teardown(ctx, server, client) 32 | %% close session 33 | zmq.core.unbind(server, 'tcp://127.0.0.1:30000'); 34 | zmq.core.close(server); 35 | 36 | zmq.core.disconnect(client, 'tcp://127.0.0.1:30000'); 37 | zmq.core.close(client); 38 | 39 | zmq.core.ctx_shutdown(ctx); 40 | zmq.core.ctx_term(ctx); 41 | end 42 | -------------------------------------------------------------------------------- /tests/test_zmq_setsockopt.m: -------------------------------------------------------------------------------- 1 | function test_zmq_setsockopt 2 | [ctx, socket] = setup; 3 | cleanupObj = onCleanup(@() teardown(ctx, socket)); 4 | 5 | % -- Options not tested here------------------------------------------------- % 6 | %% Read-Only properties 7 | % 'ZMQ_TYPE' 8 | % 'ZMQ_RCVMORE' 9 | % 'ZMQ_MECHANISM' 10 | 11 | %% Specific options: 12 | % ZMQ_ROUTER_MANDATORY (w) -> ZMQ_ROUTER 13 | % ZMQ_PROBE_ROUTER (w) -> ZMQ_ROUTER, ZMQ_DEALER, ZMQ_REQ 14 | % ZMQ_REQ_CORRELATE (w), ZMQ_REQ_RELAXED (w) -> ZMQ_REQ 15 | % ZMQ_CONFLATE (w) -> ZMQ_PULL, ZMQ_PUSH, ZMQ_SUB, ZMQ_PUB, ZMQ_DEALER 16 | % ZMQ_SUBSCRIBE (w), ZMQ_UNSUBSCRIBE (w) -> ZMQ_SUB 17 | % ZMQ_IDENTITY (rw) -> ZMQ_REQ, ZMQ_REP, ZMQ_ROUTER, ZMQ_DEALER 18 | % ZMQ_XPUB_VERBOSE (w) -> ZMQ_XPUB 19 | % -------------------------------------------------------------------------- % 20 | 21 | % Table with examples for test socket options 22 | % OBS.: all of them are read-write 23 | common_options = { ... 24 | {'ZMQ_SNDHWM' , 0 } , ... 25 | {'ZMQ_RCVHWM' , 0 } , ... 26 | {'ZMQ_AFFINITY' , 2 } , ... 27 | {'ZMQ_RATE' , 10 } , ... 28 | {'ZMQ_RECOVERY_IVL' , 1000 } , ... 29 | {'ZMQ_SNDBUF' , 2 } , ... 30 | {'ZMQ_RCVBUF' , 2 } , ... 31 | {'ZMQ_LINGER' , 2 } , ... 32 | {'ZMQ_RECONNECT_IVL' , 120 } , ... 33 | {'ZMQ_RECONNECT_IVL_MAX' , 150 } , ... 34 | {'ZMQ_BACKLOG' , 150 } , ... 35 | {'ZMQ_MAXMSGSIZE' , 100 } , ... 36 | {'ZMQ_MULTICAST_HOPS' , 5 } , ... 37 | {'ZMQ_SNDTIMEO' , 1 } , ... 38 | {'ZMQ_RCVTIMEO' , 1 } , ... 39 | {'ZMQ_IPV6' , 1 } , ... 40 | {'ZMQ_IPV4ONLY' , 0 } , ... 41 | {'ZMQ_IMMEDIATE' , 1 }, ... 42 | {'ZMQ_TCP_KEEPALIVE' , 1 } , ... 43 | {'ZMQ_TCP_KEEPALIVE_IDLE' , 2 } , ... 44 | {'ZMQ_TCP_KEEPALIVE_CNT' , 2 } , ... 45 | {'ZMQ_TCP_KEEPALIVE_INTVL' , 2 } , ... 46 | ... % {'ZMQ_TCP_ACCEPT_FILTER' , '123' } , ... % I don't know how it exactly works 47 | {'ZMQ_PLAIN_SERVER' , 1 } , ... 48 | {'ZMQ_PLAIN_USERNAME' , 'user' } , ... 49 | {'ZMQ_PLAIN_PASSWORD' , 'password'} , ... 50 | {'ZMQ_CURVE_SERVER' , 1 } ... 51 | ... % {'ZMQ_CURVE_PUBLICKEY' , '' } , ... % Z85 text generation/prase not implemented yet 52 | ... % {'ZMQ_CURVE_SECRETKEY' , '' } , ... % Z85 text generation/prase not implemented yet 53 | ... % {'ZMQ_CURVE_SERVERKEY' , '' } , ... % Z85 text generation/prase not implemented yet 54 | }; 55 | 56 | % This loop will test all the socket options against the default values listed 57 | % above. 58 | % 59 | % Once the socket is fresh and unused, all the options should remain with the 60 | % default values. 61 | for n = 1:(length(common_options)-1) 62 | option = common_options{n}{1}; 63 | value = common_options{n}{2}; 64 | 65 | response = assert_does_not_throw(@zmq.core.setsockopt, socket, option, value); 66 | assert(response == 0, 'status code should be 0, %d given.', response); 67 | 68 | response = zmq.core.getsockopt(socket, option); 69 | if ~ischar(value) 70 | condition = response == value; 71 | % display 72 | response = num2str(response); 73 | value = num2str(value); 74 | else 75 | condition = strcmp(value, response); 76 | % display 77 | response = ['"' response '"']; 78 | value = ['"' value '"']; 79 | end 80 | 81 | assert(condition, '%s should be %s, %s given.', option, value, response); 82 | end 83 | end 84 | 85 | function [ctx, socket] = setup 86 | % let's just create and destroy a dummy socket 87 | ctx = zmq.core.ctx_new(); 88 | socket = zmq.core.socket(ctx, 'ZMQ_REQ'); 89 | end 90 | 91 | function teardown(ctx, socket) 92 | % close session 93 | zmq.core.close(socket); 94 | zmq.core.ctx_shutdown(ctx); 95 | zmq.core.ctx_term(ctx); 96 | end 97 | -------------------------------------------------------------------------------- /tests/test_zmq_socket.m: -------------------------------------------------------------------------------- 1 | function test_zmq_socket 2 | ctx = setup; 3 | cleanupObj = onCleanup(@() teardown(ctx)); 4 | 5 | % let's just create and destroy a dummy socket 6 | socket = assert_does_not_throw(@zmq.core.socket, ctx, 'ZMQ_REP'); 7 | response = assert_does_not_throw(@zmq.core.close, socket); 8 | assert(response == 0, 'status code should be 0, %d given.', response); 9 | end 10 | 11 | function ctx = setup 12 | ctx = zmq.core.ctx_new(); 13 | end 14 | 15 | function teardown(ctx) 16 | % close session 17 | zmq.core.ctx_shutdown(ctx); 18 | zmq.core.ctx_term(ctx); 19 | end 20 | -------------------------------------------------------------------------------- /tests/test_zmq_version.m: -------------------------------------------------------------------------------- 1 | function test_zmq_version 2 | v = zmq.core.version(); 3 | match = regexpi(v, '\d+\.\d+\.\d+'); 4 | 5 | assert(~isempty(match), 'zmq_version should return a valid version string, %s given.', v); 6 | end 7 | --------------------------------------------------------------------------------