├── LICENSE ├── README.md ├── bin └── winx64 │ ├── node18 │ └── tcp-netx.node │ ├── node20 │ └── tcp-netx.node │ ├── node22 │ └── tcp-netx.node │ └── node24 │ └── tcp-netx.node ├── binding.gyp ├── package.json └── src ├── tcp-netx.cpp └── tcp-netx.node /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tcp-netx 2 | 3 | Synchronous and Asynchronous access to TCP servers using basic TCP sockets or HTTP from Node.js. 4 | 5 | Chris Munt 6 | 29 May 2025, MGateway Ltd [http://www.mgateway.com](http://www.mgateway.com) 7 | 8 | * Verified to work with Node.js v4 to v24. 9 | * [Release Notes](#relnotes) can be found at the end of this document. 10 | 11 | Contents 12 | 13 | * [Acknowledgements](#acknowledgements) 14 | * [Prerequisites](#prereq) 15 | * [Installing tcp-netx](#install) 16 | * [Connecting to the server](#connect) 17 | * [Reading and Writing](#readwrite) 18 | * [HTTP requests](#http) 19 | * [Troubleshooting](#debug) 20 | * [Using Node.js/V8 worker threads](#threads) 21 | * [License](#license) 22 | 23 | 24 | ## Acknowledgements 25 | 26 | Special thanks to the Ripple Foundation [https://www.ripple.foundation/](https://www.ripple.foundation/) for 27 | support and funding the initial phase of this project. 28 | 29 | 30 | ## Prerequisites 31 | 32 | **tcp-netx** is a Node.js addon written in C++. It is distributed as C++ source code and the NPM installation procedure will expect a C++ compiler to be present on the target system. 33 | 34 | Linux systems can use the freely available GNU C++ compiler (g++) which can be installed as follows. 35 | 36 | Ubuntu: 37 | 38 | apt-get install g++ 39 | 40 | Red Hat and CentOS: 41 | 1. 42 | yum install gcc-c++ 43 | 44 | Apple OS X can use the freely available **Xcode** development environment. 45 | 46 | There are two options for Windows, both of which are free: 47 | 48 | * Microsoft Visual Studio Community: [https://www.visualstudio.com/vs/community/](https://www.visualstudio.com/vs/community/) 49 | * MinGW: [http://www.mingw.org/](http://www.mingw.org/) 50 | 51 | If the Windows machine is not set up for systems development, building native Addon modules for this platform from C++ source can be quite arduous. There is some helpful advice available at: 52 | 53 | * [Compiling native Addon modules for Windows](https://github.com/Microsoft/nodejs-guidelines/blob/master/windows-environment.md#compiling-native-addon-modules) 54 | 55 | Alternatively there are built Windows x64 binaries available from: 56 | 57 | * [https://github.com/chrisemunt/tcp-netx/blob/master/bin/winx64](https://github.com/chrisemunt/tcp-netx/blob/master/bin/winx64) 58 | 59 | 60 | ## Installing tcp-netx 61 | 62 | Assuming that Node.js is already installed and a C++ compiler is available to the installation process: 63 | 64 | npm install tcp-netx 65 | 66 | This command will create the **tcp-netx** addon (*tcp-netx.node*). 67 | 68 | 69 | ## Connecting to the server 70 | 71 | Most **tcp-netx** methods are capable of operating either synchronously or asynchronously. For an operation to complete asynchronously, simply supply a suitable callback as the last argument in the call. 72 | 73 | The first step is to add **tcp-netx** to your Node.js script 74 | 75 | var tcp = require('tcp-netx'); 76 | 77 | 78 | ### Create a Server Object 79 | 80 | The second step is to create a Server Object. This method does not actually create a connection; it simply registers the server host name and the TCP port on which it is listening. 81 | 82 | var db = new tcp.server(, ); 83 | 84 | For example, create a server connection object for a local web server listening on the *well known port* for HTTP (80). 85 | 86 | var db = new tcp.server("localhost", 80); 87 | 88 | 89 | #### Return the version of tcp-netx 90 | 91 | var result = db.version(); 92 | 93 | Example: 94 | 95 | console.log("\nTCP-NETX Version: " + db.version()); 96 | 97 | 98 | #### Modify the default timeout for tcp-netx methods 99 | 100 | The default timeout applied to all **tcp-netx** methods is 10 seconds. The **timeout()** method can be used to modify this value. 101 | 102 | var timeout = db.timeout([modified timeout]); 103 | 104 | Timeouts for **tcp-netx** methods are specified in seconds. 105 | 106 | Example 1 (returning the existing timeout value): 107 | 108 | var timeout = db.timeout(); 109 | 110 | Example 2 (resetting the default timeout to 30 seconds): 111 | 112 | var timeout = db.timeout(30); 113 | 114 | Several methods allow for the timeout to be modified on a per-operation basis. 115 | 116 | 117 | ### Connect to the Server 118 | 119 | Having created a Server Object, a connection can be made. 120 | 121 | Optionally, the **connect()** method may be supplied with an object to specify a *timeout* for the connect operation (in seconds). 122 | 123 | Synchronous: 124 | 125 | var result = db.connect([{timeout: }]); 126 | 127 | Asynchronous: 128 | 129 | db.connect([{timeout: }, ]callback(, )); 130 | 131 | Result Object: 132 | 133 | { 134 | ok: 135 | [, ErrorMessage: ] 136 | [, ErrorCode: ] 137 | } 138 | 139 | If the operation is successful, the *ok flag* will be set to *true*. Otherwise, the *ok flag* will be set to *false* and error information will be returned in the *ErrorMessage* and *ErrorCode* fields. 140 | 141 | Example 1 (connect to the server using the default timeout): 142 | 143 | var result = db.connect(); 144 | 145 | Example 2 (connect to the server with a timeout of 60 seconds): 146 | 147 | var result = db.connect({timeout: 60}); 148 | 149 | 150 | #### Disconnect from the Server 151 | 152 | Synchronous: 153 | 154 | var result = db.disconnect(); 155 | 156 | Asynchronous: 157 | 158 | db.disconnect(callback(, )); 159 | 160 | Result Object: 161 | 162 | { 163 | ok: 164 | [, ErrorMessage: ] 165 | [, ErrorCode: ] 166 | } 167 | 168 | If the operation is successful, the *ok flag* will be set to *true*. Otherwise, the *ok flag* will be set to *false* and error information will be returned in the *ErrorMessage* and *ErrorCode* fields. 169 | 170 | 171 | ## Reading and Writing 172 | 173 | ### Write to the Server 174 | 175 | The default character encoding for the **write()** method is UTF8. To write binary data to the server use the **writebinary()** method instead. 176 | 177 | The request object sent to the server must contain the *data* field. 178 | 179 | Synchronous: 180 | 181 | var result = db.write({data: }); 182 | 183 | Asynchronous: 184 | 185 | db.write({data: }, callback(, )); 186 | 187 | Result Object: 188 | 189 | { 190 | ok: 191 | [, ErrorMessage: ] 192 | [, ErrorCode: ] 193 | } 194 | 195 | If the operation is successful, the *ok flag* will be set to *true*. Otherwise, the *ok flag* will be set to *false* and error information will be returned in the *ErrorMessage* and *ErrorCode* fields. 196 | 197 | Example: *Send "PING" to the server* 198 | 199 | var result = db.write({data: "PING"}); 200 | 201 | 202 | ### Read from the Server 203 | 204 | The default character encoding for the **read()** method is UTF8. To read binary data from the server use the **readbinary()** method instead. 205 | 206 | Optionally, the **read()** method may be supplied with an object to specify the *length* of the data to be read and a *timeout* may also be specified (in seconds). 207 | 208 | Synchronous: 209 | 210 | var result = db.read([{[timeout: ] [, length: ]}]); 211 | 212 | Asynchronous: 213 | 214 | db.read([{[timeout: ] [, length: ]}], callback(, )); 215 | 216 | Result Object: 217 | 218 | { 219 | ok: , 220 | data: , 221 | eof: 222 | [, ErrorMessage: ] 223 | [, ErrorCode: ] 224 | } 225 | 226 | If the operation is successful, the *ok flag* will be set to *true* and the response *data* will be returned. Otherwise, the *ok flag* will be set to *false* and error information will be returned in the *ErrorMessage* and *ErrorCode* fields. 227 | 228 | If the *eof* flag is set then it must be assumed that the server closed the connection - either as a result of an error condition or timeout. 229 | 230 | If no *length* is specified, the method will return as much data as is currently available. Otherwise the method will block until it has received the requested amount of *data* from the server. 231 | 232 | Example: *Read 4 Bytes from the server with a timeout of 30 seconds* 233 | 234 | var result = db.read({length: 4, timeout: 30}); 235 | 236 | 237 | ## HTTP requests 238 | 239 | ### Sending an HTTP Request to a Web Server 240 | 241 | The request object sent to the web server must, at the very least, contain the HTTP request headers in the *headers* field. Optionally, the request may include a payload in the *content* field and a *timeout* may also be specified (in seconds). 242 | 243 | Synchronous: 244 | 245 | var result = db.http({headers: [, content: ] [, timeout: ]}); 246 | 247 | Asynchronous: 248 | 249 | db.http({headers: [, content: ] [, timeout: ]}, callback(, )); 250 | 251 | Result Object: 252 | 253 | { 254 | ok: , 255 | headers: , 256 | keepalive: 257 | [, content: ] 258 | [, eof: ] 259 | [, ErrorMessage: ] 260 | [, ErrorCode: ] 261 | } 262 | 263 | If the operation is successful, the *ok flag* will be set to *true* and the response *headers* and any *content* (i.e. payload) will be returned. Otherwise, the *ok flag* will be set to *false* and error information will be returned in the *ErrorMessage* and *ErrorCode* fields. 264 | 265 | If the *eof* flag is set then it must be assumed that the server closed the connection - either as a result of an error condition or timeout. 266 | 267 | If the HTTP *keepalive* flag is set then it is possible to send a further HTTP request without reconnecting to the web server. 268 | 269 | Example: *Request /index.html from the web server* 270 | 271 | var result = db.http({headers: "GET /index.html HTTP/1.1\r\nHost: localhost:80\r\nConnection: close\r\n\r\n"}); 272 | 273 | 274 | ## Using Node.js/V8 worker threads 275 | 276 | **tcp-netx** functionality can now be used with Node.js/V8 worker threads. This enhancement is available with Node.js v12 (and later). 277 | 278 | The following scheme illustrates how **tcp-netx** should be used in threaded Node.js applications. 279 | 280 | 281 | const { Worker, isMainThread, parentPort, threadId } = require('worker_threads'); 282 | 283 | if (isMainThread) { 284 | // start the threads 285 | const worker1 = new Worker(__filename); 286 | const worker2 = new Worker(__filename); 287 | 288 | // process messages received from threads 289 | worker1.on('message', (message) => { 290 | console.log(message); 291 | }); 292 | worker2.on('message', (message) => { 293 | console.log(message); 294 | }); 295 | } else { 296 | var tcp = require('tcp-netx'); 297 | var db = new tcp.server(, ); 298 | var result = db.connect(); 299 | 300 | // do some work 301 | 302 | var result = db.disconnect(); 303 | // tell the parent that we're done 304 | parentPort.postMessage("threadId=" + threadId + " Done"); 305 | } 306 | 307 | 308 | ## Troubleshooting 309 | 310 | **tcp-netx** contains a function call trace and logging facility to help with troubleshooting problems in operation. 311 | 312 | To write a running commentary of progress to the console window: 313 | 314 | var result = db.settrace(1); 315 | 316 | To write a running commentary of progress to a file: 317 | 318 | var result = db.settrace("/tmp/tcp-netx.log"); 319 | 320 | To disable the trace facility: 321 | 322 | var result = db.settrace(0); 323 | 324 | 325 | ## License 326 | 327 | Copyright (c) 2016-2025 MGateway Ltd, 328 | Surrey UK. 329 | All rights reserved. 330 | 331 | http://www.mgateway.com 332 | Email: cmunt@mgateway.com 333 | 334 | 335 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at 336 | 337 | http://www.apache.org/licenses/LICENSE-2.0 338 | 339 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. 340 | 341 | 342 | ## Release Notes 343 | 344 | ### v1.0.7 (2 December 2016) 345 | 346 | * Initial Release 347 | 348 | ### v1.1.8 (19 July 2019) 349 | 350 | * Support for Node.js v8, v10 and v12. 351 | * Support for sending and receiving binary data: **readbinary()** and **writebinary()** methods. 352 | 353 | ### v1.1.9 (12 September 2019) 354 | 355 | * Internal changes to replace V8/Node.js API functionality that was deprecated in Node.js v12. 356 | 357 | ### v1.1.10 (8 November 2019) 358 | 359 | * Correct a fault in the processing of HTTP POST requests in the db.http() method. 360 | 361 | ### v1.2.11 (6 May 2020) 362 | 363 | * Verify that **tcp-netx** will build and work with Node.js v14.x.x. 364 | * Introduce support for Node.js/V8 worker threads (for Node.js v12.x.x. and later). 365 | * See the section on 'Using Node.js/V8 worker threads'. 366 | * Correct a fault in the processing of error conditions (e.g. 'server not available' etc..). 367 | * Suppress a number of benign 'cast-function-type' compiler warnings when building on the Raspberry Pi. 368 | 369 | ### v1.2.12 (28 April 2021) 370 | 371 | * Verify that **tcp-netx** will build and work with Node.js v16.x.x. 372 | * A number of faults related to the use of **tcp\-netx** functionality in Node.js/v8 worker threads have been corrected. In particular, it was noticed that callback functions were not being fired correctly for some asynchronous invocations of **tcp\-netx** methods. 373 | 374 | ### v1.2.12a (25 April 2022) 375 | 376 | * Verify that **tcp-netx** will build and work with Node.js v18.x.x. 377 | 378 | ### v1.3.13 (14 December 2022) 379 | 380 | * Correct a fault in the processing of timeouts specified in the **read()** and **http()** methods. 381 | * Allow a timeout to be specified for the **connect()** method. 382 | * Introduce a **timeout()** method to allow the default timeout applied to all **tcp-netx** methods to be changed. The initial default timeout for all methods is set to 10 seconds. 383 | 384 | ### v1.3.13a (3 May 2023) 385 | 386 | * Verify that **tcp-netx** will build and work with Node.js v20.x.x. 387 | 388 | ### v1.3.13b (22 June 2023) 389 | 390 | * Documentation update. 391 | 392 | ### v1.4.14 (18 July 2023) 393 | 394 | * Introduce support for Alpine Linux. 395 | 396 | ### v1.4.14a (21 May 2024) 397 | 398 | * Verify that **tcp-netx** will build and work with Node.js v22.x.x. 399 | 400 | ### v1.4.15 (29 May 2025) 401 | 402 | * Verify that **tcp-netx** will build and work with Node.js v24.x.x. 403 | -------------------------------------------------------------------------------- /bin/winx64/node18/tcp-netx.node: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisemunt/tcp-netx/c96b93637f22dad6fe83da6b84090ab009ebe5eb/bin/winx64/node18/tcp-netx.node -------------------------------------------------------------------------------- /bin/winx64/node20/tcp-netx.node: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisemunt/tcp-netx/c96b93637f22dad6fe83da6b84090ab009ebe5eb/bin/winx64/node20/tcp-netx.node -------------------------------------------------------------------------------- /bin/winx64/node22/tcp-netx.node: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisemunt/tcp-netx/c96b93637f22dad6fe83da6b84090ab009ebe5eb/bin/winx64/node22/tcp-netx.node -------------------------------------------------------------------------------- /bin/winx64/node24/tcp-netx.node: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisemunt/tcp-netx/c96b93637f22dad6fe83da6b84090ab009ebe5eb/bin/winx64/node24/tcp-netx.node -------------------------------------------------------------------------------- /binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "tcp-netx", 5 | "sources": [ "src/tcp-netx.cpp" ] 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": { 3 | "name": "Chris Munt", 4 | "email": "cmunt@mgateway.com", 5 | "url": "http://www.gateway.com/" 6 | }, 7 | "name": "tcp-netx", 8 | "description": "Synchronous and Asynchronous access to TCP servers using basic TCP sockets or HTTP from Node.js.", 9 | "version": "1.4.15", 10 | "maintainers": "Chris Munt ", 11 | "homepage": "https://github.com/chrisemunt/tcp-netx", 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/chrisemunt/tcp-netx.git" 15 | }, 16 | "bugs": { 17 | "url": "https://github.com/chrisemunt/tcp-netx/issues" 18 | }, 19 | "os": [ 20 | "linux", 21 | "darwin", 22 | "win32" 23 | ], 24 | "keywords": [ 25 | "tcp", 26 | "http", 27 | "network" 28 | ], 29 | "scripts": { 30 | "install": "node-gyp rebuild", 31 | "test": "echo \"Error: no test specified\" && exit 1" 32 | }, 33 | "main": "./build/Release/tcp-netx", 34 | "license": "Apache-2.0", 35 | "engines": { 36 | "node": ">=0.12.x" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/tcp-netx.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ---------------------------------------------------------------------------- 3 | | tcp-netx.node | 4 | | Author: Chris Munt cmunt@mgateway.com | 5 | | chris.e.munt@gmail.com | 6 | | Copyright (c) 2019-2025 MGateway Ltd | 7 | | Surrey UK. | 8 | | All rights reserved. | 9 | | | 10 | | http://www.mgateway.com | 11 | | | 12 | | Licensed under the Apache License, Version 2.0 (the "License"); you may | 13 | | not use this file except in compliance with the License. | 14 | | You may obtain a copy of the License at | 15 | | | 16 | | http://www.apache.org/licenses/LICENSE-2.0 | 17 | | | 18 | | Unless required by applicable law or agreed to in writing, software | 19 | | distributed under the License is distributed on an "AS IS" BASIS, | 20 | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 21 | | See the License for the specific language governing permissions and | 22 | | limitations under the License. | 23 | | | 24 | | | 25 | | Special thanks to the Ripple Foundation for | 26 | | support and funding of this project. | 27 | ---------------------------------------------------------------------------- 28 | */ 29 | 30 | /* 31 | 32 | Change Log: 33 | 34 | Version 1.0.7 2 December 2016: 35 | First release. 36 | 37 | Version 1.1.8 19 July 2019: 38 | Support for Node.js v8, v10 and v12. 39 | Support for sending and receiving binary data: **readbinary()** and **writebinary()** methods. 40 | 41 | Version 1.1.9 12 September 2019: 42 | Replace functionality that was deprecated in Node.js/V8 v12. 43 | 44 | Version 1.1.10 8 November 2019: 45 | Correct a fault in the processing of HTTP POST requests in the db.http() method. 46 | 47 | Version 1.2.11 6 May 2020: 48 | Verify that the code base works with Node.js v14.x.x. 49 | Introduce support for Node.js/V8 worker threads (for Node.js v12.x.x. and later). 50 | Correct a fault in the processing of error conditions (e.g. 'server not available' etc..). 51 | Suppress a number of benign 'cast-function-type' compiler warnings when building on the Raspberry Pi. 52 | 53 | Version 1.2.12 28 April 2021: 54 | Verify that the code base works with Node.js v16.x.x. 55 | Fix A number of faults related to the use of tcp-netx functionality in Node.js/v8 worker threads. 56 | - Notably, callback functions were not being fired correctly for some asynchronous invocations of tcp-netx methods. 57 | 58 | Version 1.2.12a 25 April 2022: 59 | Verify that tcp-netx.node will build and work with Node.js v18.x.x. (ABI: 108). 60 | 61 | Version 1.3.13 14 December 2022: 62 | Correct a fault in the processing of timeouts specified in the read() and http() methods. 63 | Allow a timeout to be specified for the connect() method. 64 | Introduce a timeout() method to allow the default timeout applied to all tcp-netx methods to be changed. 65 | - The initial default timeout for all methods is set to 10 seconds. 66 | 67 | Version 1.3.13a 3 May 2023: 68 | Verify that tcp-netx.node will build and work with Node.js v20.x.x. (ABI: 115). 69 | 70 | Version 1.3.13b 22 June 2023: 71 | Documentation update. 72 | 73 | Version 1.4.14 18 July 2023: 74 | Introduce support for Alpine Linux. 75 | 76 | Version 1.4.14a 21 May 2024: 77 | Verify that tcp-netx will build and work with Node.js v22.x.x. (ABI: 127). 78 | 79 | Version 1.4.15 29 May 2025: 80 | Verify that tcp-netx will build and work with Node.js v24.x.x. (ABI: 137). 81 | 82 | */ 83 | 84 | 85 | #if defined(_WIN32) 86 | #define BUILDING_NODE_EXTENSION 1 87 | #if defined(_MSC_VER) 88 | #if (_MSC_VER >= 1400) 89 | #define _CRT_SECURE_NO_DEPRECATE 1 90 | #define _CRT_NONSTDC_NO_DEPRECATE 1 91 | #endif 92 | #endif 93 | #elif defined(__linux__) || defined(__linux) || defined(linux) 94 | #define LINUX 1 95 | #elif defined(__APPLE__) 96 | #define MACOSX 1 97 | #else 98 | #error "Unknown Compiler" 99 | #endif 100 | 101 | #if defined(_WIN32) 102 | 103 | #include 104 | #include 105 | #define INCL_WINSOCK_API_TYPEDEFS 1 106 | #include 107 | #include 108 | #include 109 | 110 | #else 111 | 112 | #include 113 | #include 114 | #include 115 | #include 116 | #include 117 | #include 118 | #include 119 | #include 120 | #include 121 | #if defined(__APPLE__) 122 | #include 123 | #endif 124 | #include 125 | #include 126 | #include 127 | #include 128 | #include 129 | #include 130 | #include 131 | #if !defined(HPUX) && !defined(HPUX10) && !defined(HPUX11) 132 | #include 133 | #endif 134 | #if defined(SOLARIS) 135 | #include 136 | #endif 137 | #include 138 | #include 139 | #include 140 | #include 141 | #include 142 | #include 143 | #include 144 | #include 145 | 146 | #endif /* #if defined(_WIN32) */ 147 | 148 | #if defined(__GNUC__) && __GNUC__ >= 8 149 | #define DISABLE_WCAST_FUNCTION_TYPE _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wcast-function-type\"") 150 | #define DISABLE_WCAST_FUNCTION_TYPE_END _Pragma("GCC diagnostic pop") 151 | #else 152 | #define DISABLE_WCAST_FUNCTION_TYPE 153 | #define DISABLE_WCAST_FUNCTION_TYPE_END 154 | #endif 155 | 156 | DISABLE_WCAST_FUNCTION_TYPE 157 | /* 158 | #include 159 | #include 160 | #include 161 | 162 | #include 163 | #include 164 | */ 165 | #include 166 | #include 167 | #include 168 | #include 169 | 170 | #define NETX_VERSION_MAJOR 1 171 | #define NETX_VERSION_MINOR 4 172 | #define NETX_VERSION_BUILD 15 173 | 174 | #define NETX_VERSION NETX_VERSION_MAJOR "." NETX_VERSION_MINOR "." NETX_VERSION_BUILD 175 | #define NETX_NODE_VERSION (NODE_MAJOR_VERSION * 10000) + (NODE_MINOR_VERSION * 100) + NODE_PATCH_VERSION 176 | 177 | #define NETX_TIMEOUT 10 178 | #define NETX_IPV6 1 179 | #define NETX_READ_EOF 0 180 | #define NETX_READ_NOCON -1 181 | #define NETX_READ_ERROR -2 182 | #define NETX_READ_TIMEOUT -3 183 | #define NETX_RECV_BUFFER 32768 184 | 185 | #define NETX_STR_HEADERS "headers" 186 | #define NETX_STR_CONTENT "content" 187 | #define NETX_STR_KEEPALIVE "keepalive" 188 | #define NETX_STR_DATA "data" 189 | #define NETX_STR_LENGTH "length" 190 | #define NETX_STR_TIMEOUT "timeout" 191 | #define NETX_STR_EOF "eof" 192 | #define NETX_STR_OK "ok" 193 | #define NETX_STR_ERRORMESSAGE "ErrorMessage" 194 | #define NETX_STR_ERRORCODE "ErrorCode" 195 | #define NETX_STR_INFORMATION "Information" 196 | 197 | 198 | #if defined(LINUX) 199 | #define NETX_MEMCPY(a,b,c) memmove(a,b,c) 200 | #else 201 | #define NETX_MEMCPY(a,b,c) memcpy(a,b,c) 202 | #endif 203 | 204 | 205 | #if defined(_WIN32) 206 | 207 | #define NETX_WSASOCKET netx_so.p_WSASocket 208 | #define NETX_WSAGETLASTERROR netx_so.p_WSAGetLastError 209 | #define NETX_WSASTARTUP netx_so.p_WSAStartup 210 | #define NETX_WSACLEANUP netx_so.p_WSACleanup 211 | #define NETX_WSAFDISET netx_so.p_WSAFDIsSet 212 | #define NETX_WSARECV netx_so.p_WSARecv 213 | #define NETX_WSASEND netx_so.p_WSASend 214 | 215 | #define NETX_WSASTRINGTOADDRESS netx_so.p_WSAStringToAddress 216 | #define NETX_WSAADDRESSTOSTRING netx_so.p_WSAAddressToString 217 | #define NETX_GETADDRINFO netx_so.p_getaddrinfo 218 | #define NETX_FREEADDRINFO netx_so.p_freeaddrinfo 219 | #define NETX_GETNAMEINFO netx_so.p_getnameinfo 220 | #define NETX_GETPEERNAME netx_so.p_getpeername 221 | #define NETX_INET_NTOP netx_so.p_inet_ntop 222 | #define NETX_INET_PTON netx_so.p_inet_pton 223 | 224 | #define NETX_CLOSESOCKET netx_so.p_closesocket 225 | #define NETX_GETHOSTNAME netx_so.p_gethostname 226 | #define NETX_GETHOSTBYNAME netx_so.p_gethostbyname 227 | #define NETX_SETSERVBYNAME netx_so.p_getservbyname 228 | #define NETX_GETHOSTBYADDR netx_so.p_gethostbyaddr 229 | #define NETX_HTONS netx_so.p_htons 230 | #define NETX_HTONL netx_so.p_htonl 231 | #define NETX_NTOHL netx_so.p_ntohl 232 | #define NETX_NTOHS netx_so.p_ntohs 233 | #define NETX_CONNECT netx_so.p_connect 234 | #define NETX_INET_ADDR netx_so.p_inet_addr 235 | #define NETX_INET_NTOA netx_so.p_inet_ntoa 236 | #define NETX_SOCKET netx_so.p_socket 237 | #define NETX_IOCTLSOCKET netx_so.p_ioctlsocket 238 | #define NETX_SETSOCKOPT netx_so.p_setsockopt 239 | #define NETX_GETSOCKOPT netx_so.p_getsockopt 240 | #define NETX_GETSOCKNAME netx_so.p_getsockname 241 | #define NETX_SELECT netx_so.p_select 242 | #define NETX_RECV netx_so.p_recv 243 | #define NETX_SEND netx_so.p_send 244 | #define NETX_SHUTDOWN netx_so.p_shutdown 245 | #define NETX_BIND netx_so.p_bind 246 | #define NETX_LISTEN netx_so.p_listen 247 | #define NETX_ACCEPT netx_so.p_accept 248 | 249 | #define NETX_FD_ISSET(fd, set) netx_so.p_WSAFDIsSet((SOCKET)(fd), (fd_set *)(set)) 250 | 251 | typedef int (WINAPI * LPFN_WSAFDISSET) (SOCKET, fd_set *); 252 | 253 | typedef DWORD NETXTHID; 254 | typedef HINSTANCE NETXPLIB; 255 | typedef FARPROC NETXPROC; 256 | typedef LPSOCKADDR xLPSOCKADDR; 257 | typedef u_long *xLPIOCTL; 258 | typedef const char *xLPSENDBUF; 259 | typedef char *xLPRECVBUF; 260 | 261 | #ifdef _WIN64 262 | typedef int socklen_netx; 263 | #else 264 | typedef size_t socklen_netx; 265 | #endif 266 | 267 | #define SOCK_ERROR(n) (n == SOCKET_ERROR) 268 | #define INVALID_SOCK(n) (n == INVALID_SOCKET) 269 | #define NOT_BLOCKING(n) (n != WSAEWOULDBLOCK) 270 | 271 | #define BZERO(b,len) (memset((b), '\0', (len)), (void) 0) 272 | 273 | #else /* #if defined(_WIN32) */ 274 | 275 | #define NETX_WSASOCKET WSASocket 276 | #define NETX_WSAGETLASTERROR WSAGetLastError 277 | #define NETX_WSASTARTUP WSAStartup 278 | #define NETX_WSACLEANUP WSACleanup 279 | #define NETX_WSAFDIsSet WSAFDIsSet 280 | #define NETX_WSARECV WSARecv 281 | #define NETX_WSASEND WSASend 282 | 283 | #define NETX_WSASTRINGTOADDRESS WSAStringToAddress 284 | #define NETX_WSAADDRESSTOSTRING WSAAddressToString 285 | #define NETX_GETADDRINFO getaddrinfo 286 | #define NETX_FREEADDRINFO freeaddrinfo 287 | #define NETX_GETNAMEINFO getnameinfo 288 | #define NETX_GETPEERNAME getpeername 289 | #define NETX_INET_NTOP inet_ntop 290 | #define NETX_INET_PTON inet_pton 291 | 292 | #define NETX_CLOSESOCKET closesocket 293 | #define NETX_GETHOSTNAME gethostname 294 | #define NETX_GETHOSTBYNAME gethostbyname 295 | #define NETX_SETSERVBYNAME getservbyname 296 | #define NETX_GETHOSTBYADDR gethostbyaddr 297 | #define NETX_HTONS htons 298 | #define NETX_HTONL htonl 299 | #define NETX_NTOHL ntohl 300 | #define NETX_NTOHS ntohs 301 | #define NETX_CONNECT connect 302 | #define NETX_INET_ADDR inet_addr 303 | #define NETX_INET_NTOA inet_ntoa 304 | #define NETX_SOCKET socket 305 | #define NETX_IOCTLSOCKET ioctlsocket 306 | #define NETX_SETSOCKOPT setsockopt 307 | #define NETX_GETSOCKOPT getsockopt 308 | #define NETX_GETSOCKNAME getsockname 309 | #define NETX_SELECT select 310 | #define NETX_RECV recv 311 | #define NETX_SEND send 312 | #define NETX_SHUTDOWN shutdown 313 | #define NETX_BIND bind 314 | #define NETX_LISTEN listen 315 | #define NETX_ACCEPT accept 316 | 317 | #define NETX_FD_ISSET(fd, set) FD_ISSET(fd, set) 318 | 319 | typedef pthread_t NETXTHID; 320 | typedef void *NETXPLIB; 321 | typedef void *NETXPROC; 322 | #if !defined(NODE_ENGINE_CHAKRACORE) 323 | typedef unsigned long DWORD; 324 | #endif 325 | typedef unsigned long WORD; 326 | typedef int WSADATA; 327 | typedef int SOCKET; 328 | typedef struct sockaddr SOCKADDR; 329 | typedef struct sockaddr * LPSOCKADDR; 330 | typedef struct hostent HOSTENT; 331 | typedef struct hostent * LPHOSTENT; 332 | typedef struct servent SERVENT; 333 | typedef struct servent * LPSERVENT; 334 | 335 | #ifdef NETX_BS_GEN_PTR 336 | typedef const void * xLPSOCKADDR; 337 | typedef void * xLPIOCTL; 338 | typedef const void * xLPSENDBUF; 339 | typedef void * xLPRECVBUF; 340 | #else 341 | typedef LPSOCKADDR xLPSOCKADDR; 342 | typedef char * xLPIOCTL; 343 | typedef const char * xLPSENDBUF; 344 | typedef char * xLPRECVBUF; 345 | #endif /* #ifdef NETX_BS_GEN_PTR */ 346 | 347 | #if defined(OSF1) || defined(HPUX) || defined(HPUX10) || defined(HPUX11) 348 | typedef int socklen_netx; 349 | #elif defined(LINUX) || defined(AIX) || defined(AIX5) || defined(MACOSX) 350 | typedef socklen_t socklen_netx; 351 | #else 352 | typedef size_t socklen_netx; 353 | #endif 354 | 355 | #ifndef INADDR_NONE 356 | #define INADDR_NONE -1 357 | #endif 358 | 359 | #define SOCK_ERROR(n) (n < 0) 360 | #define INVALID_SOCK(n) (n < 0) 361 | #define NOT_BLOCKING(n) (n != EWOULDBLOCK && n != 2) 362 | 363 | #define BZERO(b, len) (bzero(b, len)) 364 | 365 | 366 | #endif /* #if defined(_WIN32) */ 367 | 368 | #define NETX_METHOD_VERSION 1 369 | #define NETX_METHOD_CONNECT 2 370 | #define NETX_METHOD_READ 3 371 | #define NETX_METHOD_WRITE 4 372 | #define NETX_METHOD_HTTP 5 373 | #define NETX_METHOD_DISCONNECT 6 374 | 375 | typedef struct tagNETXSOCK { 376 | 377 | unsigned char winsock_ready; 378 | short sock; 379 | short load_attempted; 380 | short nagle_algorithm; 381 | short winsock; 382 | short ipv6; 383 | NETXPLIB plibrary; 384 | 385 | char libnam[256]; 386 | 387 | #if defined(_WIN32) 388 | WSADATA wsadata; 389 | int wsastartup; 390 | WORD version_requested; 391 | LPFN_WSASOCKET p_WSASocket; 392 | LPFN_WSAGETLASTERROR p_WSAGetLastError; 393 | LPFN_WSASTARTUP p_WSAStartup; 394 | LPFN_WSACLEANUP p_WSACleanup; 395 | LPFN_WSAFDISSET p_WSAFDIsSet; 396 | LPFN_WSARECV p_WSARecv; 397 | LPFN_WSASEND p_WSASend; 398 | 399 | #if defined(NETX_IPV6) 400 | LPFN_WSASTRINGTOADDRESS p_WSAStringToAddress; 401 | LPFN_WSAADDRESSTOSTRING p_WSAAddressToString; 402 | LPFN_GETADDRINFO p_getaddrinfo; 403 | LPFN_FREEADDRINFO p_freeaddrinfo; 404 | LPFN_GETNAMEINFO p_getnameinfo; 405 | LPFN_GETPEERNAME p_getpeername; 406 | LPFN_INET_NTOP p_inet_ntop; 407 | LPFN_INET_PTON p_inet_pton; 408 | #else 409 | LPVOID p_WSAStringToAddress; 410 | LPVOID p_WSAAddressToString; 411 | LPVOID p_getaddrinfo; 412 | LPVOID p_freeaddrinfo; 413 | LPVOID p_getnameinfo; 414 | LPVOID p_getpeername; 415 | LPVOID p_inet_ntop; 416 | LPVOID p_inet_pton; 417 | #endif 418 | 419 | LPFN_CLOSESOCKET p_closesocket; 420 | LPFN_GETHOSTNAME p_gethostname; 421 | LPFN_GETHOSTBYNAME p_gethostbyname; 422 | LPFN_GETHOSTBYADDR p_gethostbyaddr; 423 | LPFN_GETSERVBYNAME p_getservbyname; 424 | 425 | LPFN_HTONS p_htons; 426 | LPFN_HTONL p_htonl; 427 | LPFN_NTOHL p_ntohl; 428 | LPFN_NTOHS p_ntohs; 429 | LPFN_CONNECT p_connect; 430 | LPFN_INET_ADDR p_inet_addr; 431 | LPFN_INET_NTOA p_inet_ntoa; 432 | 433 | LPFN_SOCKET p_socket; 434 | LPFN_IOCTLSOCKET p_ioctlsocket; 435 | LPFN_SETSOCKOPT p_setsockopt; 436 | LPFN_GETSOCKOPT p_getsockopt; 437 | LPFN_GETSOCKNAME p_getsockname; 438 | LPFN_SELECT p_select; 439 | LPFN_RECV p_recv; 440 | LPFN_SEND p_send; 441 | LPFN_SHUTDOWN p_shutdown; 442 | LPFN_BIND p_bind; 443 | LPFN_LISTEN p_listen; 444 | LPFN_ACCEPT p_accept; 445 | #endif /* #if defined(_WIN32) */ 446 | 447 | } NETXSOCK, *PNETXSOCK; 448 | 449 | 450 | typedef struct tagNETXSRV { 451 | char ip_address[64]; 452 | int port; 453 | int timeout; /* v1.3.13 */ 454 | char trace_dev[128]; 455 | short trace; 456 | FILE *pftrace; 457 | } NETXSRV; 458 | 459 | 460 | typedef struct tagNETXCON { 461 | short connected; 462 | int port; 463 | char ip_address[128]; 464 | int error_no; 465 | char error[512]; 466 | char info[256]; 467 | int length; 468 | int timeout; 469 | SOCKET cli_socket; 470 | int method; 471 | int hlen; 472 | int keepalive; 473 | int eof; 474 | int send_buf_size; 475 | int send_buf_len; 476 | unsigned char *send_buf; 477 | int recv_buf_size; 478 | int recv_buf_len; 479 | unsigned char *recv_buf; 480 | short trace; 481 | FILE * pftrace; 482 | } NETXCON; 483 | 484 | 485 | #if NETX_NODE_VERSION >= 120000 486 | #define NETX_GET(a,b) a->Get(icontext,b).ToLocalChecked() 487 | #define NETX_SET(a,b,c) a->Set(icontext,b,c).FromJust() 488 | #define NETX_TO_OBJECT(a) a->ToObject(icontext).ToLocalChecked() 489 | #define NETX_TO_STRING(a) a->ToString(icontext).ToLocalChecked() 490 | #define NETX_NUMBER_VALUE(a) a->NumberValue(icontext).ToChecked() 491 | #define NETX_INT32_VALUE(a) a->Int32Value(icontext).FromJust() 492 | 493 | #define NDC_INTEGER_NEW(a) Integer::New(isolate, a) 494 | #define NDC_OBJECT_NEW() Object::New(isolate) 495 | #define NDC_ARRAY_NEW(a) Array::New(isolate, a) 496 | #define NDC_ARRAY_NEW(a) Array::New(isolate, a) 497 | #define NDC_NUMBER_NEW(a) Number::New(isolate, a) 498 | #define NDC_BOOLEAN_NEW(a) Boolean::New(isolate, a) 499 | #define NDC_NULL() Null(isolate) 500 | 501 | #elif NETX_NODE_VERSION >= 100000 502 | #define NETX_GET(a,b) a->Get(icontext,b).ToLocalChecked() 503 | #define NETX_SET(a,b,c) a->Set(icontext,b,c).FromJust() 504 | #define NETX_TO_OBJECT(a) a->ToObject(icontext).ToLocalChecked() 505 | #define NETX_TO_STRING(a) a->ToString(icontext).ToLocalChecked() 506 | #define NETX_NUMBER_VALUE(a) a->NumberValue(icontext).ToChecked() 507 | #define NETX_INT32_VALUE(a) a->Int32Value(icontext).FromJust() 508 | #else 509 | #define NETX_GET(a,b) a->Get(b) 510 | #define NETX_SET(a,b,c) a->Set(b,c) 511 | #define NETX_TO_OBJECT(a) a->ToObject() 512 | #define NETX_TO_STRING(a) a->ToString() 513 | #define NETX_NUMBER_VALUE(a) a->NumberValue() 514 | #if NETX_NODE_VERSION >= 70000 515 | #define NETX_INT32_VALUE(a) a->Int32Value() 516 | #else 517 | #define NETX_INT32_VALUE(a) a->ToInt32()->Value(); 518 | #endif 519 | #endif 520 | 521 | /* 522 | #if NETX_NODE_VERSION >= 70000 523 | s->pcon->length = request->Get(length_name)->Int32Value(); 524 | #else 525 | s->pcon->length = request->Get(length_name)->ToInt32()->Value(); 526 | #endif 527 | */ 528 | 529 | static NETXSOCK netx_so = {0, 0, 0, 0, 0, 0, 0, {'\0'}}; 530 | 531 | #if defined(_WIN32) 532 | CRITICAL_SECTION netx_async_mutex; 533 | #else 534 | pthread_mutex_t netx_async_mutex = PTHREAD_MUTEX_INITIALIZER; 535 | #endif 536 | 537 | 538 | using namespace node; 539 | using namespace v8; 540 | 541 | 542 | int netx_connect (NETXCON *pcon); 543 | int netx_read (NETXCON *pcon); 544 | int netx_write (NETXCON *pcon); 545 | int netx_http (NETXCON *pcon); 546 | int netx_disconnect (NETXCON *pcon); 547 | 548 | int netx_init_vars (NETXCON *pcon, NETXSRV *psrv); 549 | int netx_format_buffer (char *obuffer, char *ibuffer, int len, int max); 550 | int netx_ucase (char *string); 551 | int netx_lcase (char *string); 552 | void * netx_malloc (int size, short id); 553 | int netx_free (void *p, short id); 554 | int netx_resize (NETXCON *pcon, unsigned char **ppbuf, int *psize, int retain, int size); 555 | NETXPLIB netx_dso_load (char * library); 556 | NETXPROC netx_dso_sym (NETXPLIB plibrary, char * symbol); 557 | int netx_dso_unload (NETXPLIB plibrary); 558 | int netx_load_winsock (NETXCON *pcon, int context); 559 | int netx_tcp_connect (NETXCON *pcon, int context); 560 | int netx_tcp_connect_ex (NETXCON *pcon, xLPSOCKADDR p_srv_addr, socklen_netx srv_addr_len, int timeout); 561 | int netx_tcp_disconnect (NETXCON *pcon, int context); 562 | int netx_tcp_write (NETXCON *pcon, unsigned char *data, int size); 563 | int netx_tcp_read (NETXCON *pcon, unsigned char *data, int size, int timeout, int context); 564 | int netx_get_last_error (int context); 565 | #if !defined(_WIN32) 566 | /* v1.4.14 */ 567 | char* netx_strerror_r (int result, char *buffer, int buffer_size, int error_code); 568 | char* netx_strerror_r (char *result, char *buffer, int buffer_size, int error_code); 569 | #endif 570 | int netx_get_error_message (int error_code, char *message, int size, int context); 571 | int netx_get_std_error_message (int error_code, char *message, int size, int context); 572 | int netx_enter_critical_section(void *p_crit); 573 | int netx_leave_critical_section(void *p_crit); 574 | 575 | 576 | 577 | #if defined(_WIN32) 578 | BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) 579 | { 580 | switch (fdwReason) 581 | { 582 | case DLL_PROCESS_ATTACH: 583 | InitializeCriticalSection(&netx_async_mutex); 584 | break; 585 | case DLL_THREAD_ATTACH: 586 | break; 587 | case DLL_THREAD_DETACH: 588 | break; 589 | case DLL_PROCESS_DETACH: 590 | DeleteCriticalSection(&netx_async_mutex); 591 | break; 592 | } 593 | return TRUE; 594 | } 595 | #endif 596 | 597 | 598 | class server : public node::ObjectWrap 599 | { 600 | 601 | private: 602 | 603 | int s_count; 604 | short binary; 605 | 606 | public: 607 | 608 | NETXSRV srv; /* v1.3.13 */ 609 | NETXSRV *psrv; 610 | NETXCON *pcon; 611 | 612 | static Persistent s_ct; 613 | 614 | #if NETX_NODE_VERSION >= 100000 615 | static void Init(Local exports) 616 | #else 617 | static void Init(Handle exports) 618 | #endif 619 | { 620 | Isolate* isolate = Isolate::GetCurrent(); 621 | Local t = FunctionTemplate::New(isolate, New); 622 | t->SetClassName(netx_new_string8(isolate, (char *) "server", 1)); 623 | t->InstanceTemplate()->SetInternalFieldCount(1); 624 | 625 | NODE_SET_PROTOTYPE_METHOD(t, "version", version); 626 | NODE_SET_PROTOTYPE_METHOD(t, "timeout", timeout); 627 | NODE_SET_PROTOTYPE_METHOD(t, "settrace", settrace); 628 | NODE_SET_PROTOTYPE_METHOD(t, "connect", connect); 629 | NODE_SET_PROTOTYPE_METHOD(t, "read", read); 630 | NODE_SET_PROTOTYPE_METHOD(t, "readbin", readbinary); 631 | NODE_SET_PROTOTYPE_METHOD(t, "readbinary", readbinary); 632 | NODE_SET_PROTOTYPE_METHOD(t, "write", write); 633 | NODE_SET_PROTOTYPE_METHOD(t, "writebin", writebinary); 634 | NODE_SET_PROTOTYPE_METHOD(t, "writebinary", writebinary); 635 | NODE_SET_PROTOTYPE_METHOD(t, "http", http); 636 | NODE_SET_PROTOTYPE_METHOD(t, "disconnect", disconnect); 637 | 638 | #if NETX_NODE_VERSION >= 120000 639 | Local icontext = isolate->GetCurrentContext(); 640 | s_ct.Reset(isolate, t->GetFunction(icontext).ToLocalChecked()); 641 | exports->Set(icontext, netx_new_string8(isolate, (char *) "server", 1), t->GetFunction(icontext).ToLocalChecked()).FromJust(); 642 | #else 643 | s_ct.Reset(isolate, t->GetFunction()); 644 | exports->Set(netx_new_string8(isolate, (char *) "server", 1), t->GetFunction()); 645 | #endif 646 | 647 | 648 | 649 | return; 650 | } 651 | 652 | 653 | server() : 654 | s_count(0) 655 | { 656 | } 657 | 658 | 659 | ~server() 660 | { 661 | } 662 | 663 | 664 | static void New(const FunctionCallbackInfo& args) 665 | { 666 | int narg; 667 | Isolate* isolate = Isolate::GetCurrent(); 668 | #if NETX_NODE_VERSION >= 100000 669 | Local icontext = isolate->GetCurrentContext(); 670 | #endif 671 | HandleScope scope(isolate); 672 | 673 | server *s = new server(); 674 | s->Wrap(args.This()); 675 | 676 | s->psrv = &(s->srv); /* v1.3.13 */ 677 | 678 | narg = args.Length(); 679 | if (narg < 2) { 680 | isolate->ThrowException(Exception::TypeError(netx_new_string8(isolate, (char *) "Unable to process arguments", 1))); 681 | return; 682 | } 683 | 684 | Local ip = NETX_TO_STRING(args[0]); 685 | netx_write_char8(isolate, ip, s->psrv->ip_address, sizeof(s->psrv->ip_address), 1); 686 | s->psrv->port = (int) NETX_INT32_VALUE(args[1]); 687 | s->pcon = NULL; 688 | s->psrv->timeout = NETX_TIMEOUT; /* v1.3.13 */ 689 | s->psrv->pftrace = NULL; 690 | s->psrv->trace = 0; 691 | s->psrv->trace_dev[0] = '\0'; 692 | 693 | args.GetReturnValue().Set(args.This()); 694 | 695 | return; 696 | } 697 | 698 | 699 | struct netx_baton_t { 700 | server *s; 701 | int increment_by; 702 | Persistent cb; 703 | Isolate *isolate; 704 | }; 705 | 706 | 707 | static netx_baton_t * netx_make_baton(server *s, int js_narg, const FunctionCallbackInfo& args) 708 | { 709 | netx_baton_t *baton; 710 | 711 | baton = new netx_baton_t(); 712 | 713 | if (!baton) { 714 | netx_destroy_baton(baton); 715 | return NULL; 716 | } 717 | 718 | baton->increment_by = 1; 719 | baton->s = s; 720 | 721 | return baton; 722 | } 723 | 724 | 725 | static int netx_destroy_baton(netx_baton_t *baton) 726 | { 727 | if (baton) { 728 | delete baton; 729 | } 730 | 731 | return 0; 732 | } 733 | 734 | 735 | /* v1.2.12 */ 736 | static int netx_queue_task(void *work_cb, void *after_work_cb, netx_baton_t *baton, short context) 737 | { 738 | uv_work_t *_req = new uv_work_t; 739 | _req->data = baton; 740 | 741 | /* v1.2.12 */ 742 | #if NETX_NODE_VERSION >= 120000 743 | uv_queue_work(GetCurrentEventLoop(baton->isolate), _req, (uv_work_cb) work_cb, (uv_after_work_cb) after_work_cb); 744 | #else 745 | uv_queue_work(uv_default_loop(), _req, (uv_work_cb) work_cb, (uv_after_work_cb) after_work_cb); 746 | #endif 747 | 748 | return 0; 749 | } 750 | 751 | 752 | static int netx_string8_length(Isolate * isolate, Local str, int utf8) 753 | { 754 | if (utf8) { 755 | #if NETX_NODE_VERSION >= 240000 756 | return str->Utf8LengthV2(isolate); 757 | #elif NETX_NODE_VERSION >= 120000 758 | return str->Utf8Length(isolate); 759 | #else 760 | return str->Utf8Length(); 761 | #endif 762 | } 763 | else { 764 | return str->Length(); 765 | } 766 | } 767 | 768 | 769 | static Local netx_new_string8(Isolate * isolate, char * buffer, int utf8) 770 | { 771 | if (utf8) { 772 | #if NETX_NODE_VERSION >= 120000 773 | return String::NewFromUtf8(isolate, buffer, NewStringType::kNormal).ToLocalChecked(); 774 | #elif NETX_NODE_VERSION >= 1200 775 | return String::NewFromUtf8(isolate, buffer); 776 | #else 777 | return String::NewFromUtf8(buffer); 778 | #endif 779 | } 780 | else { 781 | #if NETX_NODE_VERSION >= 100000 782 | return String::NewFromOneByte(isolate, (uint8_t *) buffer, NewStringType::kInternalized).ToLocalChecked(); 783 | #elif NETX_NODE_VERSION >= 1200 784 | return String::NewFromOneByte(isolate, (uint8_t *) buffer); 785 | #else 786 | return String::New(buffer); 787 | #endif 788 | } 789 | } 790 | 791 | 792 | static Local netx_new_string8n(Isolate * isolate, char * buffer, unsigned long len, int utf8) 793 | { 794 | if (utf8) { 795 | #if NETX_NODE_VERSION >= 120000 796 | return String::NewFromUtf8(isolate, buffer, NewStringType::kNormal, len).ToLocalChecked(); 797 | #elif NETX_NODE_VERSION >= 1200 798 | return String::NewFromUtf8(isolate, buffer, String::kNormalString, len); 799 | #else 800 | return String::NewFromUtf8(buffer, len); 801 | #endif 802 | } 803 | else { 804 | #if NETX_NODE_VERSION >= 100000 805 | return String::NewFromOneByte(isolate, (uint8_t *) buffer, NewStringType::kInternalized, len).ToLocalChecked(); 806 | #elif NETX_NODE_VERSION >= 1200 807 | return String::NewFromOneByte(isolate, (uint8_t *) buffer, String::kNormalString, len); 808 | #else 809 | return String::New(buffer); 810 | #endif 811 | } 812 | } 813 | 814 | 815 | static int netx_write_char8(v8::Isolate * isolate, Local str, char * buffer, int buffer_size, int utf8) 816 | { 817 | if (utf8) { 818 | #if NETX_NODE_VERSION >= 240000 819 | return str->WriteUtf8V2(isolate, buffer, buffer_size, v8::String::WriteFlags::kNullTerminate); 820 | #elif NETX_NODE_VERSION >= 120000 821 | return str->WriteUtf8(isolate, buffer); 822 | #else 823 | return str->WriteUtf8(buffer); 824 | #endif 825 | } 826 | else { 827 | #if NETX_NODE_VERSION >= 240000 828 | str->WriteOneByteV2(isolate, 0, str->Length(), (uint8_t *) buffer, v8::String::WriteFlags::kNullTerminate); 829 | return 0; 830 | #elif NETX_NODE_VERSION >= 120000 831 | return str->WriteOneByte(isolate, (uint8_t *) buffer); 832 | #elif NETX_NODE_VERSION >= 1200 833 | return str->WriteOneByte((uint8_t *) buffer); 834 | #else 835 | return str->WriteAscii((char *) buffer); 836 | #endif 837 | } 838 | } 839 | 840 | 841 | static void netx_invoke_callback(uv_work_t *req, int status) 842 | { 843 | Isolate* isolate = Isolate::GetCurrent(); 844 | HandleScope scope(isolate); 845 | 846 | netx_baton_t *baton = static_cast(req->data); 847 | baton->s->Unref(); 848 | Local argv[2]; 849 | 850 | if (baton->s->pcon->error[0]) { 851 | argv[0] = Integer::New(isolate, true); 852 | } 853 | else { 854 | argv[0] = Integer::New(isolate, false); 855 | } 856 | argv[1] = netx_result_object(baton->s, 1); 857 | 858 | #if NETX_NODE_VERSION >= 40000 859 | TryCatch try_catch(isolate); 860 | #else 861 | TryCatch try_catch; 862 | #endif 863 | 864 | Local cb = Local::New(isolate, baton->cb); 865 | 866 | #if NETX_NODE_VERSION >= 120000 867 | /* cb->Call(isolate->GetCurrentContext(), isolate->GetCurrentContext()->Global(), 2, argv); */ 868 | cb->Call(isolate->GetCurrentContext(), Null(isolate), 2, argv).ToLocalChecked(); 869 | #else 870 | cb->Call(isolate->GetCurrentContext()->Global(), 2, argv); 871 | #endif 872 | 873 | #if NETX_NODE_VERSION >= 40000 874 | if (try_catch.HasCaught()) { 875 | FatalException(isolate, try_catch); 876 | } 877 | #else 878 | if (try_catch.HasCaught()) { 879 | FatalException(isolate, try_catch); 880 | } 881 | #endif 882 | 883 | baton->cb.Reset(); 884 | netx_destroy_baton(baton); 885 | delete req; 886 | 887 | return; 888 | } 889 | 890 | 891 | static Local netx_result_object(server * s, int context) 892 | { 893 | Isolate* isolate = Isolate::GetCurrent(); 894 | #if NETX_NODE_VERSION >= 100000 895 | Local icontext = isolate->GetCurrentContext(); 896 | #endif 897 | EscapableHandleScope handle_scope(isolate); 898 | 899 | Local key; 900 | Local error; 901 | 902 | Local result = Object::New(isolate); 903 | 904 | if (s->pcon->error[0]) { 905 | key = netx_new_string8(isolate, (char *) NETX_STR_OK, 1); 906 | NETX_SET(result, key, Integer::New(isolate, false)); 907 | 908 | error = netx_new_string8(isolate, s->pcon->error, 1); 909 | key = netx_new_string8(isolate, (char *) NETX_STR_ERRORMESSAGE, 1); 910 | NETX_SET(result, key, error); 911 | 912 | key = netx_new_string8(isolate, (char *) NETX_STR_ERRORCODE, 1); 913 | NETX_SET(result, key, Integer::New(isolate, s->pcon->error_no)); 914 | 915 | if (s->pcon->method == NETX_METHOD_HTTP || s->pcon->method == NETX_METHOD_READ) { 916 | s->pcon->eof = 1; 917 | key = netx_new_string8(isolate, (char *) NETX_STR_EOF, 1); 918 | NETX_SET(result, key, Integer::New(isolate, s->pcon->eof)); 919 | } 920 | if (s->pcon->method == NETX_METHOD_HTTP) { 921 | key = netx_new_string8(isolate, (char *) NETX_STR_CONTENT, 1); 922 | NETX_SET(result, key, netx_new_string8(isolate, (char *) "", 1)); 923 | } 924 | else if (s->pcon->method == NETX_METHOD_READ) { 925 | key = netx_new_string8(isolate, (char *) NETX_STR_DATA, 1); 926 | NETX_SET(result, key, netx_new_string8(isolate, (char *) "", 1)); 927 | } 928 | 929 | 930 | } 931 | else { 932 | key = netx_new_string8(isolate, (char *) NETX_STR_OK, 1); 933 | NETX_SET(result, key, Integer::New(isolate, true)); 934 | 935 | if (s->pcon->info[0]) { 936 | key = netx_new_string8(isolate, (char *) NETX_STR_INFORMATION, 1); 937 | NETX_SET(result, key, netx_new_string8(isolate, (char *) s->pcon->info, 1)); 938 | } 939 | 940 | if (s->pcon->method == NETX_METHOD_HTTP) { 941 | key = netx_new_string8(isolate, (char *) NETX_STR_KEEPALIVE, 1); 942 | NETX_SET(result, key, Integer::New(isolate, s->pcon->keepalive)); 943 | 944 | key = netx_new_string8(isolate, (char *) NETX_STR_EOF, 1); 945 | NETX_SET(result, key, Integer::New(isolate, s->pcon->eof)); 946 | if (s->pcon->hlen) { 947 | key = netx_new_string8(isolate, (char *) NETX_STR_HEADERS, 1); 948 | NETX_SET(result, key, netx_new_string8n(isolate, (char *) s->pcon->recv_buf, s->pcon->hlen, 1)); 949 | key = netx_new_string8(isolate, (char *) NETX_STR_CONTENT, 1); 950 | NETX_SET(result, key, netx_new_string8n(isolate, (char *) (s->pcon->recv_buf + s->pcon->hlen), s->pcon->recv_buf_len- s->pcon->hlen, 1)); 951 | } 952 | else { 953 | key = netx_new_string8(isolate, (char *) NETX_STR_CONTENT, 1); 954 | NETX_SET(result, key, netx_new_string8n(isolate, (char *) s->pcon->recv_buf, s->pcon->recv_buf_len, 1)); 955 | } 956 | } 957 | else if (s->pcon->method == NETX_METHOD_READ) { 958 | key = netx_new_string8(isolate, (char *) NETX_STR_EOF, 1); 959 | NETX_SET(result, key, Integer::New(isolate, s->pcon->eof)); 960 | key = netx_new_string8(isolate, (char *) NETX_STR_DATA, 1); 961 | NETX_SET(result, key, netx_new_string8n(isolate, (char *) s->pcon->recv_buf, s->pcon->recv_buf_len, s->binary ? 0 : 1)); 962 | } 963 | } 964 | 965 | return handle_scope.Escape(result); 966 | } 967 | 968 | 969 | static void version(const FunctionCallbackInfo& args) 970 | { 971 | Isolate* isolate = args.GetIsolate(); 972 | HandleScope scope(isolate); 973 | int narg; 974 | char buffer[245]; 975 | 976 | server * s = ObjectWrap::Unwrap(args.This()); 977 | s->s_count ++; 978 | 979 | narg = args.Length(); 980 | if (narg > 0) { 981 | isolate->ThrowException(Exception::TypeError(netx_new_string8(isolate, (char *) "The version method does not take any arguments", 1))); 982 | return; 983 | } 984 | 985 | sprintf(buffer, "%d.%d.%d", NETX_VERSION_MAJOR, NETX_VERSION_MINOR, NETX_VERSION_BUILD); 986 | Local result = netx_new_string8(isolate, buffer, 1); 987 | args.GetReturnValue().Set(result); 988 | 989 | return; 990 | } 991 | 992 | 993 | static void timeout(const FunctionCallbackInfo& args) 994 | { 995 | Isolate* isolate = args.GetIsolate(); 996 | #if NETX_NODE_VERSION >= 100000 997 | Local icontext = isolate->GetCurrentContext(); 998 | #endif 999 | HandleScope scope(isolate); 1000 | int narg, timeout; 1001 | 1002 | server * s = ObjectWrap::Unwrap(args.This()); 1003 | s->s_count ++; 1004 | 1005 | narg = args.Length(); 1006 | if (narg > 1) { 1007 | isolate->ThrowException(Exception::TypeError(netx_new_string8(isolate, (char *) "The timeout method takes a maximum of one argument", 1))); 1008 | return; 1009 | } 1010 | if (narg > 0 && args[0]->IsInt32()) { 1011 | timeout = NETX_INT32_VALUE(args[0]); 1012 | if (timeout >= 0) { 1013 | s->psrv->timeout = timeout; 1014 | if (s->pcon) { 1015 | s->pcon->timeout = s->psrv->timeout; 1016 | } 1017 | } 1018 | } 1019 | 1020 | Local result = Int32::New(isolate, s->psrv->timeout); 1021 | args.GetReturnValue().Set(result); 1022 | 1023 | return; 1024 | } 1025 | 1026 | 1027 | static void settrace(const FunctionCallbackInfo& args) 1028 | { 1029 | Isolate* isolate = args.GetIsolate(); 1030 | #if NETX_NODE_VERSION >= 100000 1031 | Local icontext = isolate->GetCurrentContext(); 1032 | #endif 1033 | HandleScope scope(isolate); 1034 | int narg, result; 1035 | char buffer[256]; 1036 | 1037 | server * s = ObjectWrap::Unwrap(args.This()); 1038 | s->s_count ++; 1039 | 1040 | narg = args.Length(); 1041 | if (narg < 1) { 1042 | isolate->ThrowException(Exception::TypeError(netx_new_string8(isolate, (char *) "The settrace method takes one argument", 1))); 1043 | return; 1044 | } 1045 | 1046 | netx_write_char8(isolate, NETX_TO_STRING(args[0]), buffer, sizeof(buffer), 1); 1047 | 1048 | result = 0; 1049 | if (buffer[0] == '0') { 1050 | if (s->psrv->pftrace) { 1051 | fprintf(s->psrv->pftrace, "\r\n"); 1052 | fflush(s->psrv->pftrace); 1053 | fclose(s->psrv->pftrace); 1054 | } 1055 | s->psrv->trace = 0; 1056 | s->psrv->pftrace = NULL; 1057 | s->psrv->trace_dev[0] = '\0'; 1058 | } 1059 | else { 1060 | if (buffer[0] == '1' || !strcmp(buffer, "stdout")) { 1061 | s->psrv->trace = 1; 1062 | s->psrv->pftrace = stdout; 1063 | } 1064 | else if (buffer[0] != '0') { 1065 | s->psrv->trace = 1; 1066 | s->psrv->pftrace = fopen(buffer, "a"); 1067 | if (s->psrv->pftrace) { 1068 | fprintf(s->psrv->pftrace, "\r\n-> fopen(%s, \"a\") (Trace file opened)", buffer); 1069 | fflush(s->psrv->pftrace); 1070 | strcpy(s->psrv->trace_dev, buffer); 1071 | } 1072 | else { 1073 | result = -1; 1074 | s->psrv->pftrace = stdout; 1075 | fprintf(s->psrv->pftrace, "\r\n-> fopen(%s, \"a\") (Cannot open trace file specified - using stdout instead)", buffer); 1076 | fflush(s->psrv->pftrace); 1077 | } 1078 | } 1079 | } 1080 | 1081 | if (s->pcon) { 1082 | s->pcon->trace = s->psrv->trace; 1083 | s->pcon->pftrace = s->psrv->pftrace; 1084 | } 1085 | 1086 | args.GetReturnValue().Set(Integer::New(isolate, result)); 1087 | 1088 | return; 1089 | } 1090 | 1091 | 1092 | static void connect(const FunctionCallbackInfo& args) 1093 | { 1094 | Isolate* isolate = args.GetIsolate(); 1095 | #if NETX_NODE_VERSION >= 100000 1096 | Local icontext = isolate->GetCurrentContext(); 1097 | #endif 1098 | HandleScope scope(isolate); 1099 | short async; 1100 | int narg; 1101 | 1102 | server * s = ObjectWrap::Unwrap(args.This()); 1103 | s->s_count ++; 1104 | 1105 | if (!s->pcon) { 1106 | s->pcon = (NETXCON *) netx_malloc(sizeof(NETXCON), 0); 1107 | 1108 | if (!s->pcon) { 1109 | isolate->ThrowException(Exception::TypeError(netx_new_string8(isolate, (char *) "Unable to allocate connection memory block", 1))); 1110 | return; 1111 | } 1112 | memset((void *) s->pcon, 0, sizeof(NETXCON)); 1113 | 1114 | s->pcon->trace = s->psrv->trace; 1115 | s->pcon->pftrace = s->psrv->pftrace; 1116 | 1117 | s->pcon->send_buf = (unsigned char *) netx_malloc(sizeof(char) * NETX_RECV_BUFFER, 0); 1118 | if (!s->pcon->send_buf) { 1119 | isolate->ThrowException(Exception::TypeError(netx_new_string8(isolate, (char *) "Unable to allocate memory for send buffer", 1))); 1120 | return; 1121 | } 1122 | s->pcon->send_buf[0] = '\0'; 1123 | s->pcon->send_buf_size = NETX_RECV_BUFFER - 1; 1124 | s->pcon->recv_buf = (unsigned char *) netx_malloc(sizeof(char) * NETX_RECV_BUFFER, 0); 1125 | if (!s->pcon->recv_buf) { 1126 | isolate->ThrowException(Exception::TypeError(netx_new_string8(isolate, (char *) "Unable to allocate memory for recv buffer", 1))); 1127 | return; 1128 | } 1129 | s->pcon->recv_buf[0] = '\0'; 1130 | s->pcon->recv_buf_size = NETX_RECV_BUFFER - 1; 1131 | } 1132 | 1133 | s->pcon->method = NETX_METHOD_CONNECT; 1134 | s->pcon->timeout = s->psrv->timeout; /* v1.3.13 */ 1135 | 1136 | narg = args.Length(); 1137 | if (narg < 0) { 1138 | isolate->ThrowException(Exception::TypeError(netx_new_string8(isolate, (char *) "Unable to process arguments", 1))); 1139 | return; 1140 | } 1141 | if (narg > 0 && args[narg - 1]->IsFunction()) { 1142 | async = 1; 1143 | narg --; 1144 | } 1145 | else { 1146 | async = 0; 1147 | } 1148 | 1149 | if (narg > 0 && args[0]->IsObject()) { 1150 | 1151 | Local request; 1152 | Local timeout_name = netx_new_string8(isolate, (char *) NETX_STR_TIMEOUT, 1); 1153 | 1154 | request = NETX_TO_OBJECT(args[0]); 1155 | 1156 | if (!NETX_GET(request, timeout_name)->IsUndefined()) { 1157 | if (NETX_GET(request, timeout_name)->IsInt32()) { 1158 | s->pcon->timeout = NETX_INT32_VALUE(NETX_GET(request, timeout_name)); /* v1.3.13 */ 1159 | if (s->pcon->timeout < 0) { 1160 | s->pcon->timeout = s->psrv->timeout; 1161 | } 1162 | } 1163 | } 1164 | } 1165 | 1166 | strcpy(s->pcon->ip_address, s->psrv->ip_address); 1167 | s->pcon->port = s->psrv->port; 1168 | 1169 | if (async) { 1170 | 1171 | Local cb = Local::Cast(args[narg]); 1172 | netx_baton_t *baton = netx_make_baton(s, narg, args); 1173 | baton->isolate = isolate; 1174 | baton->cb.Reset(isolate, cb); 1175 | 1176 | s->Ref(); 1177 | 1178 | netx_queue_task((void *) EIO_connect, (void *) netx_invoke_callback, baton, 0); /* v1.2.12 */ 1179 | 1180 | return; 1181 | } 1182 | 1183 | netx_connect(s->pcon); 1184 | Local result = netx_result_object(s, 0); 1185 | args.GetReturnValue().Set(result); 1186 | 1187 | return; 1188 | } 1189 | 1190 | 1191 | static void EIO_connect(uv_work_t *req) 1192 | { 1193 | netx_baton_t *baton = static_cast(req->data); 1194 | 1195 | netx_connect(baton->s->pcon); 1196 | baton->s->s_count += baton->increment_by; 1197 | 1198 | return; 1199 | } 1200 | 1201 | 1202 | static void read(const FunctionCallbackInfo& args) 1203 | { 1204 | read_ex(args, 0); 1205 | return; 1206 | } 1207 | 1208 | 1209 | static void readbinary(const FunctionCallbackInfo& args) 1210 | { 1211 | read_ex(args, 1); 1212 | return; 1213 | } 1214 | 1215 | 1216 | static void read_ex(const FunctionCallbackInfo& args, short binary) 1217 | { 1218 | Isolate* isolate = args.GetIsolate(); 1219 | #if NETX_NODE_VERSION >= 100000 1220 | Local icontext = isolate->GetCurrentContext(); 1221 | #endif 1222 | HandleScope scope(isolate); 1223 | short async; 1224 | int narg; 1225 | 1226 | server * s = ObjectWrap::Unwrap(args.This()); 1227 | s->s_count ++; 1228 | s->binary = binary; 1229 | 1230 | if (!s->pcon) { 1231 | isolate->ThrowException(Exception::TypeError(netx_new_string8(isolate, (char *) "No connection to server established", 1))); 1232 | return; 1233 | } 1234 | 1235 | s->pcon->method = NETX_METHOD_READ; 1236 | s->pcon->timeout = s->psrv->timeout; /* v1.3.13 */ 1237 | 1238 | narg = args.Length(); 1239 | if (narg < 0) { 1240 | isolate->ThrowException(Exception::TypeError(netx_new_string8(isolate, (char *) "Unable to process arguments", 1))); 1241 | return; 1242 | } 1243 | if (narg > 0 && args[narg - 1]->IsFunction()) { 1244 | async = 1; 1245 | narg --; 1246 | } 1247 | else { 1248 | async = 0; 1249 | } 1250 | 1251 | Local request; 1252 | 1253 | Local length_name = netx_new_string8(isolate, (char *) NETX_STR_LENGTH, 1); 1254 | Local timeout_name = netx_new_string8(isolate, (char *) NETX_STR_TIMEOUT, 1); 1255 | 1256 | netx_init_vars(s->pcon, s->psrv); 1257 | 1258 | if (narg && args[0]->IsObject()) { 1259 | request = NETX_TO_OBJECT(args[0]); 1260 | 1261 | if (!NETX_GET(request, length_name)->IsUndefined()) { 1262 | s->pcon->length = NETX_INT32_VALUE(NETX_GET(request, length_name)); 1263 | 1264 | } 1265 | if (!NETX_GET(request, timeout_name)->IsUndefined()) { 1266 | if (NETX_GET(request, timeout_name)->IsInt32()) { 1267 | s->pcon->timeout = NETX_INT32_VALUE(NETX_GET(request, timeout_name)); /* v1.3.13 */ 1268 | if (s->pcon->timeout < 0) { 1269 | s->pcon->timeout = s->psrv->timeout; 1270 | } 1271 | } 1272 | } 1273 | } 1274 | 1275 | if (async) { 1276 | 1277 | Local cb = Local::Cast(args[narg]); 1278 | netx_baton_t *baton = netx_make_baton(s, narg, args); 1279 | baton->isolate = isolate; 1280 | baton->cb.Reset(isolate, cb); 1281 | 1282 | s->Ref(); 1283 | 1284 | netx_queue_task((void *) EIO_read, (void *) netx_invoke_callback, baton, 0); /* v1.2.12 */ 1285 | 1286 | return; 1287 | } 1288 | 1289 | netx_read(s->pcon); 1290 | Local result = netx_result_object(s, 0); 1291 | args.GetReturnValue().Set(result); 1292 | 1293 | return; 1294 | } 1295 | 1296 | 1297 | static void EIO_read(uv_work_t *req) 1298 | { 1299 | netx_baton_t *baton = static_cast(req->data); 1300 | 1301 | netx_read(baton->s->pcon); 1302 | baton->s->s_count += baton->increment_by; 1303 | 1304 | return; 1305 | } 1306 | 1307 | 1308 | static void write(const FunctionCallbackInfo& args) 1309 | { 1310 | write_ex(args, 0); 1311 | return; 1312 | } 1313 | 1314 | 1315 | static void writebinary(const FunctionCallbackInfo& args) 1316 | { 1317 | write_ex(args, 1); 1318 | return; 1319 | } 1320 | 1321 | 1322 | static void write_ex(const FunctionCallbackInfo& args, short binary) { 1323 | Isolate* isolate = args.GetIsolate(); 1324 | #if NETX_NODE_VERSION >= 100000 1325 | Local icontext = isolate->GetCurrentContext(); 1326 | #endif 1327 | HandleScope scope(isolate); 1328 | short async; 1329 | int narg; 1330 | 1331 | server * s = ObjectWrap::Unwrap(args.This()); 1332 | s->s_count ++; 1333 | s->binary = binary; 1334 | if (!s->pcon) { 1335 | isolate->ThrowException(Exception::TypeError(netx_new_string8(isolate, (char *) "No connection to server established", 1))); 1336 | return; 1337 | } 1338 | 1339 | s->pcon->method = NETX_METHOD_WRITE; 1340 | 1341 | narg = args.Length(); 1342 | if (narg < 0) { 1343 | isolate->ThrowException(Exception::TypeError(netx_new_string8(isolate, (char *) "Unable to process arguments", 1))); 1344 | return; 1345 | } 1346 | if (narg > 0 && args[narg - 1]->IsFunction()) { 1347 | async = 1; 1348 | narg --; 1349 | } 1350 | else { 1351 | async = 0; 1352 | } 1353 | 1354 | Local request; 1355 | 1356 | Local content_name = netx_new_string8(isolate, (char *) NETX_STR_DATA, 1); 1357 | Local content_value; 1358 | 1359 | netx_init_vars(s->pcon, s->psrv); 1360 | 1361 | if (args[0]->IsObject()) { 1362 | request = NETX_TO_OBJECT(args[0]); 1363 | 1364 | if (!NETX_GET(request, content_name)->IsUndefined()) { 1365 | content_value = NETX_TO_STRING(NETX_GET(request, content_name)); 1366 | s->pcon->send_buf_len = content_value->Length(); 1367 | if (s->pcon->send_buf_len >= s->pcon->send_buf_size) { 1368 | if (netx_resize(s->pcon, &(s->pcon->send_buf), &(s->pcon->send_buf_size), 0, s->pcon->send_buf_len + 32) < 0) { 1369 | isolate->ThrowException(Exception::TypeError(netx_new_string8(isolate, (char *) "Unable to allocate memory for send buffer", 1))); 1370 | return; 1371 | } 1372 | } 1373 | netx_write_char8(isolate, content_value, (char *) s->pcon->send_buf, s->pcon->send_buf_size, s->binary ? 0 : 1); 1374 | } 1375 | else { 1376 | isolate->ThrowException(Exception::TypeError(netx_new_string8(isolate, (char *) "Missing 'data' property", 1))); 1377 | return; 1378 | } 1379 | } 1380 | else { 1381 | isolate->ThrowException(Exception::TypeError(netx_new_string8(isolate, (char *) "Missing data object", 1))); 1382 | return; 1383 | } 1384 | 1385 | if (async) { 1386 | 1387 | Local cb = Local::Cast(args[narg]); 1388 | netx_baton_t *baton = netx_make_baton(s, narg, args); 1389 | baton->isolate = isolate; 1390 | baton->cb.Reset(isolate, cb); 1391 | 1392 | s->Ref(); 1393 | 1394 | netx_queue_task((void *) EIO_write, (void *) netx_invoke_callback, baton, 0); /* v1.2.12 */ 1395 | 1396 | return; 1397 | } 1398 | 1399 | netx_write(s->pcon); 1400 | Local result = netx_result_object(s, 0); 1401 | args.GetReturnValue().Set(result); 1402 | 1403 | return; 1404 | } 1405 | 1406 | 1407 | static void EIO_write(uv_work_t *req) 1408 | { 1409 | netx_baton_t *baton = static_cast(req->data); 1410 | 1411 | netx_write(baton->s->pcon); 1412 | baton->s->s_count += baton->increment_by; 1413 | 1414 | return; 1415 | } 1416 | 1417 | 1418 | static void http(const FunctionCallbackInfo& args) 1419 | { 1420 | Isolate* isolate = args.GetIsolate(); 1421 | #if NETX_NODE_VERSION >= 100000 1422 | Local icontext = isolate->GetCurrentContext(); 1423 | #endif 1424 | HandleScope scope(isolate); 1425 | 1426 | short async; 1427 | int narg; 1428 | 1429 | server * s = ObjectWrap::Unwrap(args.This()); 1430 | s->s_count ++; 1431 | if (!s->pcon) { 1432 | isolate->ThrowException(Exception::TypeError(netx_new_string8(isolate, (char *) "No connection to server established", 1))); 1433 | return; 1434 | } 1435 | if (s->pcon->connected == 0) { 1436 | isolate->ThrowException(Exception::TypeError(netx_new_string8(isolate, (char *) "Disconnected from server", 1))); 1437 | return; 1438 | } 1439 | 1440 | s->pcon->method = NETX_METHOD_HTTP; 1441 | s->pcon->timeout = s->psrv->timeout; /* v1.3.13 */ 1442 | 1443 | narg = args.Length(); 1444 | if (narg < 1) { 1445 | isolate->ThrowException(Exception::TypeError(netx_new_string8(isolate, (char *) "Unable to process arguments", 1))); 1446 | return; 1447 | } 1448 | if (narg > 1 && args[narg - 1]->IsFunction()) { 1449 | async = 1; 1450 | narg --; 1451 | } 1452 | else { 1453 | async = 0; 1454 | } 1455 | 1456 | Local request; 1457 | 1458 | Local headers_name = netx_new_string8(isolate, (char *) NETX_STR_HEADERS, 1); 1459 | Local headers_value; 1460 | 1461 | Local content_name = netx_new_string8(isolate, (char *) NETX_STR_CONTENT, 1); 1462 | Local content_value; 1463 | 1464 | Local length_name = netx_new_string8(isolate, (char *) NETX_STR_LENGTH, 1); 1465 | Local timeout_name = netx_new_string8(isolate, (char *) NETX_STR_TIMEOUT, 1); 1466 | 1467 | netx_init_vars(s->pcon, s->psrv); 1468 | 1469 | if (args[0]->IsObject()) { 1470 | int hlen, clen; 1471 | 1472 | hlen = 0; 1473 | clen = 0; 1474 | request = NETX_TO_OBJECT(args[0]); 1475 | if (!NETX_GET(request, headers_name)->IsUndefined()) { 1476 | headers_value = NETX_TO_STRING(NETX_GET(request, headers_name)); 1477 | hlen = headers_value->Length(); 1478 | } 1479 | else { 1480 | isolate->ThrowException(Exception::TypeError(netx_new_string8(isolate, (char *) "Missing 'headers' property", 1))); 1481 | return; 1482 | } 1483 | 1484 | if (!NETX_GET(request, content_name)->IsUndefined()) { 1485 | content_value = NETX_TO_STRING(NETX_GET(request, content_name)); 1486 | clen = content_value->Length(); 1487 | } 1488 | 1489 | if ((hlen + clen) >= s->pcon->send_buf_size) { 1490 | if (netx_resize(s->pcon, &(s->pcon->send_buf), &(s->pcon->send_buf_size), 0, hlen + clen + 32) < 0) { 1491 | isolate->ThrowException(Exception::TypeError(netx_new_string8(isolate, (char *) "Unable to allocate memory for send buffer", 1))); 1492 | return; 1493 | } 1494 | } 1495 | netx_write_char8(isolate, headers_value, (char *) s->pcon->send_buf, s->pcon->send_buf_size, 1); 1496 | 1497 | if (clen) { 1498 | netx_write_char8(isolate, content_value, (char *) s->pcon->send_buf + hlen, s->pcon->send_buf_size - hlen, 1); 1499 | } 1500 | s->pcon->send_buf_len = hlen + clen; 1501 | 1502 | if (!NETX_GET(request, length_name)->IsUndefined()) { 1503 | s->pcon->length = NETX_INT32_VALUE(NETX_GET(request, length_name)); 1504 | } 1505 | if (!NETX_GET(request, timeout_name)->IsUndefined()) { 1506 | if (NETX_GET(request, timeout_name)->IsInt32()) { 1507 | s->pcon->timeout = NETX_INT32_VALUE(NETX_GET(request, timeout_name)); /* v1.3.13 */ 1508 | if (s->pcon->timeout < 0) { 1509 | s->pcon->timeout = s->psrv->timeout; 1510 | } 1511 | } 1512 | } 1513 | } 1514 | else { 1515 | isolate->ThrowException(Exception::TypeError(netx_new_string8(isolate, (char *) "Missing request object", 1))); 1516 | return; 1517 | } 1518 | 1519 | if (async) { 1520 | 1521 | Local cb = Local::Cast(args[narg]); 1522 | netx_baton_t *baton = netx_make_baton(s, narg, args); 1523 | baton->isolate = isolate; 1524 | baton->cb.Reset(isolate, cb); 1525 | 1526 | s->Ref(); 1527 | 1528 | netx_queue_task((void *) EIO_http, (void *) netx_invoke_callback, baton, 0); /* v1.2.12 */ 1529 | 1530 | return; 1531 | } 1532 | 1533 | netx_http(s->pcon); 1534 | 1535 | Local result = netx_result_object(s, 0); 1536 | args.GetReturnValue().Set(result); 1537 | 1538 | return; 1539 | } 1540 | 1541 | 1542 | static void EIO_http(uv_work_t *req) 1543 | { 1544 | netx_baton_t *baton = static_cast(req->data); 1545 | 1546 | netx_http(baton->s->pcon); 1547 | baton->s->s_count += baton->increment_by; 1548 | 1549 | return; 1550 | } 1551 | 1552 | 1553 | static void disconnect(const FunctionCallbackInfo& args) 1554 | { 1555 | Isolate* isolate = args.GetIsolate(); 1556 | HandleScope scope(isolate); 1557 | short async; 1558 | int narg; 1559 | 1560 | server * s = ObjectWrap::Unwrap(args.This()); 1561 | s->s_count ++; 1562 | if (!s->pcon) { 1563 | isolate->ThrowException(Exception::TypeError(netx_new_string8(isolate, (char *) "No connection to server established", 1))); 1564 | return; 1565 | } 1566 | 1567 | s->pcon->method = NETX_METHOD_DISCONNECT; 1568 | 1569 | narg = args.Length(); 1570 | if (narg < 0) { 1571 | isolate->ThrowException(Exception::TypeError(netx_new_string8(isolate, (char *) "Unable to process arguments", 1))); 1572 | return; 1573 | } 1574 | if (narg > 0 && args[narg - 1]->IsFunction()) { 1575 | async = 1; 1576 | narg --; 1577 | } 1578 | else { 1579 | async = 0; 1580 | } 1581 | 1582 | if (async) { 1583 | 1584 | Local cb = Local::Cast(args[narg]); 1585 | netx_baton_t *baton = netx_make_baton(s, narg, args); 1586 | baton->isolate = isolate; 1587 | baton->cb.Reset(isolate, cb); 1588 | 1589 | s->Ref(); 1590 | 1591 | netx_queue_task((void *) EIO_disconnect, (void *) netx_invoke_callback, baton, 0); /* v1.2.12 */ 1592 | 1593 | return; 1594 | } 1595 | 1596 | netx_disconnect(s->pcon); 1597 | 1598 | Local result = netx_result_object(s, 0); 1599 | args.GetReturnValue().Set(result); 1600 | 1601 | return; 1602 | } 1603 | 1604 | 1605 | static void EIO_disconnect(uv_work_t *req) 1606 | { 1607 | netx_baton_t *baton = static_cast(req->data); 1608 | 1609 | netx_disconnect(baton->s->pcon); 1610 | 1611 | baton->s->s_count += baton->increment_by; 1612 | 1613 | return; 1614 | } 1615 | 1616 | }; 1617 | 1618 | 1619 | /* v1.2.11 */ 1620 | #if NETX_NODE_VERSION >= 120000 1621 | class netx_addon_data 1622 | { 1623 | 1624 | public: 1625 | 1626 | netx_addon_data(Isolate* isolate, Local exports): 1627 | call_count(0) { 1628 | /* Link the existence of this object instance to the existence of exports. */ 1629 | exports_.Reset(isolate, exports); 1630 | exports_.SetWeak(this, DeleteMe, WeakCallbackType::kParameter); 1631 | } 1632 | 1633 | ~netx_addon_data() { 1634 | if (!exports_.IsEmpty()) { 1635 | /* Reset the reference to avoid leaking data. */ 1636 | exports_.ClearWeak(); 1637 | exports_.Reset(); 1638 | } 1639 | } 1640 | 1641 | /* Per-addon data. */ 1642 | int call_count; 1643 | 1644 | private: 1645 | 1646 | /* Method to call when "exports" is about to be garbage-collected. */ 1647 | static void DeleteMe(const WeakCallbackInfo& info) { 1648 | delete info.GetParameter(); 1649 | } 1650 | 1651 | /* 1652 | Weak handle to the "exports" object. An instance of this class will be 1653 | destroyed along with the exports object to which it is weakly bound. 1654 | */ 1655 | v8::Persistent exports_; 1656 | }; 1657 | #endif 1658 | 1659 | 1660 | Persistent server::s_ct; 1661 | 1662 | 1663 | extern "C" { 1664 | #if defined(_WIN32) 1665 | #if NETX_NODE_VERSION >= 100000 1666 | void __declspec(dllexport) init (Local exports) 1667 | #else 1668 | void __declspec(dllexport) init (Handle exports) 1669 | #endif 1670 | #else 1671 | #if NETX_NODE_VERSION >= 100000 1672 | static void init (Local exports) 1673 | #else 1674 | static void init (Handle exports) 1675 | #endif 1676 | #endif 1677 | { 1678 | server::Init(exports); 1679 | } 1680 | 1681 | #if NETX_NODE_VERSION >= 120000 1682 | 1683 | /* exports, module, context */ 1684 | extern "C" NODE_MODULE_EXPORT void 1685 | NODE_MODULE_INITIALIZER(Local exports, 1686 | Local module, 1687 | Local context) { 1688 | Isolate* isolate = context->GetIsolate(); 1689 | 1690 | /* Create a new instance of netx_addon_data for this instance of the addon. */ 1691 | netx_addon_data * data = new netx_addon_data(isolate, exports); 1692 | /* Wrap the data in a v8::External so we can pass it to the method we expose. */ 1693 | /* Local external = External::New(isolate, data); */ 1694 | External::New(isolate, data); 1695 | 1696 | init(exports); 1697 | 1698 | /* 1699 | Expose the method "Method" to JavaScript, and make sure it receives the 1700 | per-addon-instance data we created above by passing `external` as the 1701 | third parameter to the FunctionTemplate constructor. 1702 | exports->Set(context, String::NewFromUtf8(isolate, "method", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, Method, external)->GetFunction(context).ToLocalChecked()).FromJust(); 1703 | */ 1704 | 1705 | } 1706 | 1707 | #else 1708 | 1709 | NODE_MODULE(server, init) 1710 | 1711 | #endif 1712 | } 1713 | 1714 | 1715 | int netx_connect(NETXCON *pcon) 1716 | { 1717 | int rc; 1718 | 1719 | if (pcon->trace == 1) { 1720 | fprintf(pcon->pftrace, "\r\n-> netx_connect"); 1721 | fflush(pcon->pftrace); 1722 | } 1723 | 1724 | #if defined(_WIN32) 1725 | netx_enter_critical_section((void *) &netx_async_mutex); 1726 | if (netx_so.winsock_ready == 0) { 1727 | 1728 | rc = netx_load_winsock(pcon, 0); 1729 | if (rc) { 1730 | netx_leave_critical_section((void *) &netx_async_mutex); 1731 | return 0; 1732 | } 1733 | } 1734 | netx_leave_critical_section((void *) &netx_async_mutex); 1735 | #endif 1736 | if (pcon->connected) { 1737 | rc = 0; 1738 | strcpy(pcon->info, "Already connected to server"); 1739 | } 1740 | else { 1741 | rc = netx_tcp_connect(pcon, 0); 1742 | } 1743 | 1744 | if (rc) { 1745 | return 0; 1746 | } 1747 | 1748 | return rc; 1749 | } 1750 | 1751 | 1752 | int netx_read(NETXCON *pcon) 1753 | { 1754 | int rc, block; 1755 | 1756 | if (pcon->trace == 1) { 1757 | fprintf(pcon->pftrace, "\r\n-> netx_read"); 1758 | fflush(pcon->pftrace); 1759 | } 1760 | 1761 | if (pcon->connected == 0) { 1762 | strcpy(pcon->error, "Disconnected from server"); 1763 | return -1; 1764 | } 1765 | 1766 | if (pcon->length) { 1767 | block = 0; 1768 | pcon->recv_buf_len = pcon->length; 1769 | if (pcon->recv_buf_len >= pcon->recv_buf_size) { 1770 | if (netx_resize(pcon, &(pcon->recv_buf), &(pcon->recv_buf_size), 0, pcon->recv_buf_len + 32) < 0) 1771 | return -1; 1772 | } 1773 | } 1774 | else { 1775 | block = 0; 1776 | pcon->recv_buf_len = pcon->recv_buf_size - 2; 1777 | } 1778 | 1779 | rc = netx_tcp_read(pcon, (unsigned char *) pcon->recv_buf, (int) pcon->recv_buf_len, pcon->timeout, block); 1780 | if (rc < 0) { 1781 | return rc; 1782 | } 1783 | 1784 | if (rc > 0) { 1785 | pcon->recv_buf_len = rc; 1786 | pcon->recv_buf[pcon->recv_buf_len] = '\0'; 1787 | } 1788 | else { 1789 | pcon->recv_buf_len = 0; 1790 | pcon->recv_buf[0] = '\0'; 1791 | } 1792 | 1793 | return rc; 1794 | } 1795 | 1796 | 1797 | int netx_write(NETXCON *pcon) 1798 | { 1799 | int rc; 1800 | 1801 | if (pcon->trace == 1) { 1802 | fprintf(pcon->pftrace, "\r\n-> netx_write"); 1803 | fflush(pcon->pftrace); 1804 | } 1805 | 1806 | if (pcon->connected == 0) { 1807 | strcpy(pcon->error, "Disconnected from server"); 1808 | return -1; 1809 | } 1810 | 1811 | rc = netx_tcp_write(pcon, (unsigned char *) pcon->send_buf, (int) pcon->send_buf_len); 1812 | 1813 | return rc; 1814 | } 1815 | 1816 | 1817 | int netx_http(NETXCON *pcon) 1818 | { 1819 | int rc, size, clen, chunked, total, n, bsize, blen, bptr, bptrcz, avail, chunk_size, eof; 1820 | char headers[2048], buffer[NETX_RECV_BUFFER]; 1821 | unsigned char *p, *p1; 1822 | 1823 | if (pcon->trace == 1) { 1824 | fprintf(pcon->pftrace, "\r\n-> netx_http"); 1825 | fflush(pcon->pftrace); 1826 | } 1827 | 1828 | if (pcon->connected == 0) { 1829 | strcpy(pcon->error, "Disconnected from server"); 1830 | return -1; 1831 | } 1832 | 1833 | rc = netx_tcp_write(pcon, (unsigned char *) pcon->send_buf, (int) pcon->send_buf_len); 1834 | if (rc < 0) { 1835 | return rc; 1836 | } 1837 | 1838 | pcon->eof = 0; 1839 | pcon->hlen = 0; 1840 | pcon->keepalive = 1; 1841 | 1842 | p = NULL; 1843 | headers[0] = '\0'; 1844 | clen = 0; 1845 | chunked = 0; 1846 | eof = 0; 1847 | size = NETX_RECV_BUFFER - 2; 1848 | pcon->recv_buf_len = 0; 1849 | for (;;) { 1850 | rc = netx_tcp_read(pcon, (unsigned char *) (pcon->recv_buf + pcon->recv_buf_len), (int) (size - pcon->recv_buf_len), pcon->timeout, 0); 1851 | if (rc < 1) { 1852 | eof = 1; 1853 | break; 1854 | } 1855 | 1856 | pcon->recv_buf_len += rc; 1857 | pcon->recv_buf[pcon->recv_buf_len] = '\0'; 1858 | 1859 | p = (unsigned char *) strstr((char *) pcon->recv_buf, "\r\n\r\n"); 1860 | if (p) { 1861 | pcon->hlen = (int) (p - pcon->recv_buf) + 4; 1862 | if (pcon->hlen > 2040) 1863 | pcon->hlen = 2040; 1864 | strncpy(headers, (char *) pcon->recv_buf, pcon->hlen); 1865 | headers[pcon->hlen] = '\0'; 1866 | break; 1867 | } 1868 | if (pcon->recv_buf_len == size) { 1869 | break; 1870 | } 1871 | } 1872 | 1873 | if (eof || pcon->recv_buf_len == 0) { 1874 | strcpy(pcon->error, "No response from server. Previous request may have closed the connection (check 'HTTP keepalive' status)"); 1875 | rc = -1; 1876 | goto netx_http_exit; 1877 | } 1878 | 1879 | if (headers[0]) { 1880 | netx_lcase(headers); 1881 | 1882 | p = (unsigned char *) strstr(headers, "content-length"); 1883 | if (p) { 1884 | p = (unsigned char *) strstr((char *) p, ":"); 1885 | if (p) { 1886 | while (*(++ p) == ' ') 1887 | ; 1888 | clen = (int) strtol((char *) p, NULL, 10); 1889 | } 1890 | } 1891 | p = (unsigned char *) strstr(headers, "transfer-encoding"); 1892 | if (p) { 1893 | p = (unsigned char *) strstr((char *) p, ":"); 1894 | if (p) { 1895 | while (*(++ p) == ' ') 1896 | ; 1897 | p1 = (unsigned char *) strstr((char *) p, "\r\n"); 1898 | if (p1) { 1899 | *p1 = '\0'; 1900 | if (strstr((char *) p, "chunked")) { 1901 | chunked = 1; 1902 | } 1903 | *p1 = '\r'; 1904 | } 1905 | } 1906 | } 1907 | p = (unsigned char *) strstr(headers, "connection"); 1908 | if (p) { 1909 | p = (unsigned char *) strstr((char *) p, ":"); 1910 | if (p) { 1911 | while (*(++ p) == ' ') 1912 | ; 1913 | p1 = (unsigned char *) strstr((char *) p, "\r\n"); 1914 | if (p1) { 1915 | *p1 = '\0'; 1916 | if (strstr((char *) p, "close")) { 1917 | pcon->keepalive = 0; 1918 | } 1919 | *p1 = '\r'; 1920 | } 1921 | } 1922 | } 1923 | } 1924 | 1925 | if (clen) { 1926 | total = pcon->hlen + clen; 1927 | if (total >= pcon->recv_buf_size) { 1928 | if (netx_resize(pcon, &(pcon->recv_buf), &(pcon->recv_buf_size), pcon->recv_buf_len, total + 32) < 0) { 1929 | eof = 1; 1930 | rc = -1; 1931 | goto netx_http_exit; 1932 | } 1933 | } 1934 | if (total > pcon->recv_buf_len) { 1935 | rc = netx_tcp_read(pcon, (unsigned char *) (pcon->recv_buf + pcon->recv_buf_len), (int) (total - pcon->recv_buf_len), pcon->timeout, 1); 1936 | if (rc < 1) { 1937 | eof = 1; 1938 | goto netx_http_exit; 1939 | } 1940 | pcon->recv_buf_len += rc; 1941 | } 1942 | } 1943 | 1944 | else if (chunked) { 1945 | bsize = NETX_RECV_BUFFER - 2; 1946 | blen = pcon->recv_buf_len - pcon->hlen; 1947 | bptr = 0; 1948 | memcpy((void *) buffer, (void *) (pcon->recv_buf + pcon->hlen), blen); 1949 | buffer[blen] = '\0'; 1950 | 1951 | pcon->recv_buf_len = pcon->hlen; /* reset to end of header */ 1952 | 1953 | for (;;) { 1954 | if (bptr >= blen) { 1955 | bptr = 0; 1956 | blen = 0; 1957 | } 1958 | else if (bptr > (bsize - 32)) { 1959 | n = 0; 1960 | avail = (blen - bptr); 1961 | while (bptr < blen) { 1962 | buffer[n ++] = buffer[bptr ++]; 1963 | } 1964 | bptr = 0; 1965 | blen = avail; 1966 | } 1967 | bptrcz = 0; 1968 | for (;;) { 1969 | if (bptr < blen) { 1970 | while (buffer[bptr] == '\r' || buffer[bptr] == '\n') 1971 | bptr ++; 1972 | for (n = bptr; n < blen; n ++) { 1973 | if (n > 1 && buffer[n - 1] == '\r' && buffer[n] == '\n') { 1974 | bptrcz = (n - 1); 1975 | break; 1976 | } 1977 | } 1978 | if (bptrcz) { 1979 | break; 1980 | } 1981 | } 1982 | rc = netx_tcp_read(pcon, (unsigned char *) buffer + blen, (int) bsize - blen, pcon->timeout, 0); 1983 | if (rc < 1) { 1984 | eof = 1; 1985 | break; 1986 | } 1987 | blen += rc; 1988 | } 1989 | 1990 | if (eof && blen == 0) { 1991 | break; 1992 | } 1993 | 1994 | if (bptrcz) { 1995 | buffer[bptrcz] = '\0'; 1996 | chunk_size = (int) strtol((char *) (buffer + bptr), NULL, 16); 1997 | if (chunk_size == 0) { 1998 | break; 1999 | } 2000 | bptr = bptrcz + 2; 2001 | total = pcon->recv_buf_len + chunk_size; 2002 | if (total >= pcon->recv_buf_size) { 2003 | if (netx_resize(pcon, &(pcon->recv_buf), &(pcon->recv_buf_size), pcon->recv_buf_len, total + 32) < 0) { 2004 | eof = 1; 2005 | rc = -1; 2006 | break; 2007 | } 2008 | } 2009 | for (;;) { 2010 | avail = (blen - bptr); 2011 | if (avail < chunk_size) { 2012 | memcpy((void *) (pcon->recv_buf + pcon->recv_buf_len), (void *) (buffer + bptr), avail); 2013 | pcon->recv_buf_len += avail; 2014 | bptr += avail; 2015 | chunk_size -= avail; 2016 | } 2017 | else { 2018 | memcpy((void *) (pcon->recv_buf + pcon->recv_buf_len), (void *) (buffer + bptr), chunk_size); 2019 | pcon->recv_buf_len += chunk_size; 2020 | bptr += chunk_size; 2021 | chunk_size = 0; 2022 | break; 2023 | } 2024 | if (bptr >= blen) { 2025 | rc = netx_tcp_read(pcon, (unsigned char *) buffer, (int) bsize, pcon->timeout, 0); 2026 | if (rc < 1) { 2027 | eof = 1; 2028 | break; 2029 | } 2030 | blen = rc; 2031 | bptr = 0; 2032 | } 2033 | } 2034 | if (eof) { 2035 | break; 2036 | } 2037 | } 2038 | } 2039 | } 2040 | 2041 | else if (!eof) { 2042 | total = 4096; 2043 | while (eof == 0) { 2044 | if ((pcon->recv_buf_len + total) >= pcon->recv_buf_size) { 2045 | if (netx_resize(pcon, &(pcon->recv_buf), &(pcon->recv_buf_size), pcon->recv_buf_len, pcon->recv_buf_size + total + 32) < 0) { 2046 | eof = 1; 2047 | rc = -1; 2048 | break; 2049 | } 2050 | } 2051 | rc = netx_tcp_read(pcon, (unsigned char *) (pcon->recv_buf + pcon->recv_buf_len), (int) total, pcon->timeout, 0); 2052 | if (rc < 1) { 2053 | eof = 1; 2054 | break; 2055 | } 2056 | pcon->recv_buf_len += rc; 2057 | } 2058 | } 2059 | 2060 | netx_http_exit: 2061 | 2062 | /* 2063 | printf("\r\n *** eof=%d; clen=%d; chunked=%d; hlen=%d; pcon->recv_buf_len=%d; %d\r\n\r\n", eof, clen, chunked, pcon->hlen, pcon->recv_buf_len, clen + pcon->hlen); 2064 | */ 2065 | return rc; 2066 | } 2067 | 2068 | 2069 | int netx_disconnect(NETXCON *pcon) 2070 | { 2071 | int rc; 2072 | 2073 | if (pcon->trace == 1) { 2074 | fprintf(pcon->pftrace, "\r\n-> netx_disconnect"); 2075 | fflush(pcon->pftrace); 2076 | } 2077 | 2078 | rc = netx_tcp_disconnect(pcon, 0); 2079 | 2080 | if (pcon->trace == 1) { 2081 | fprintf(pcon->pftrace, "\r\n\r\n"); 2082 | fflush(pcon->pftrace); 2083 | } 2084 | 2085 | return rc; 2086 | } 2087 | 2088 | 2089 | int netx_init_vars(NETXCON *pcon, NETXSRV *psrv) 2090 | { 2091 | pcon->timeout = psrv->timeout; /* v1.3.13 */ 2092 | pcon->length = 0; 2093 | pcon->eof = 0; 2094 | pcon->hlen = 0; 2095 | pcon->keepalive = 0; 2096 | pcon->send_buf[0] = '\0'; 2097 | pcon->send_buf_len = 0; 2098 | pcon->recv_buf[0] = '\0'; 2099 | pcon->recv_buf_len = 0; 2100 | pcon->error[0] = '\0'; 2101 | pcon->info[0] = '\0'; 2102 | pcon->error_no = 0; 2103 | 2104 | return 0; 2105 | } 2106 | 2107 | 2108 | int netx_format_buffer(char *obuffer, char *ibuffer, int len, int max) 2109 | { 2110 | int ni, no; 2111 | unsigned int c; 2112 | char buffer[32]; 2113 | 2114 | if (len < 0) 2115 | len = 0; 2116 | 2117 | obuffer[0] = '\0'; 2118 | no = 0; 2119 | for (ni = 0; ni < len; ni ++) { 2120 | c = (unsigned int) ibuffer[ni]; 2121 | if ((c < 32) || (c > 126)) { 2122 | sprintf(buffer, "\\x%02x", c); 2123 | strcpy(obuffer + no, buffer); 2124 | no += (int) strlen(buffer); 2125 | } 2126 | else { 2127 | obuffer[no ++] = (char) c; 2128 | } 2129 | } 2130 | obuffer[no] = '\0'; 2131 | 2132 | return no; 2133 | } 2134 | 2135 | 2136 | int netx_ucase(char *string) 2137 | { 2138 | int n, chr; 2139 | 2140 | n = 0; 2141 | while (string[n] != '\0') { 2142 | chr = (int) string[n]; 2143 | if (chr >= 97 && chr <= 122) 2144 | string[n] = (char) (chr - 32); 2145 | n ++; 2146 | } 2147 | return 1; 2148 | } 2149 | 2150 | 2151 | int netx_lcase(char *string) 2152 | { 2153 | int n, chr; 2154 | 2155 | n = 0; 2156 | while (string[n] != '\0') { 2157 | chr = (int) string[n]; 2158 | if (chr >= 65 && chr <= 90) 2159 | string[n] = (char) (chr + 32); 2160 | n ++; 2161 | } 2162 | return 1; 2163 | } 2164 | 2165 | 2166 | void * netx_malloc(int size, short id) 2167 | { 2168 | void *p; 2169 | 2170 | p = (void *) malloc(size); 2171 | 2172 | return p; 2173 | } 2174 | 2175 | 2176 | int netx_free(void *p, short id) 2177 | { 2178 | free((void *) p); 2179 | 2180 | return 0; 2181 | } 2182 | 2183 | 2184 | NETXPLIB netx_dso_load(char * library) 2185 | { 2186 | NETXPLIB plibrary; 2187 | 2188 | #if defined(_WIN32) 2189 | plibrary = LoadLibraryA(library); 2190 | #else 2191 | plibrary = dlopen(library, RTLD_NOW); 2192 | #endif 2193 | 2194 | return plibrary; 2195 | } 2196 | 2197 | 2198 | int netx_resize(NETXCON *pcon, unsigned char **ppbuf, int *psize, int retain, int size) 2199 | { 2200 | int rc; 2201 | unsigned char *p; 2202 | p = *ppbuf; 2203 | 2204 | *ppbuf = (unsigned char *) netx_malloc(sizeof(char) * (size + 32), 0); 2205 | if (*ppbuf) { 2206 | if (retain) { 2207 | memcpy((void *) *ppbuf, (void *) p, retain); 2208 | } 2209 | netx_free((void *) p, 0); 2210 | *psize = size; 2211 | rc = 0; 2212 | } 2213 | else { 2214 | *ppbuf = p; 2215 | if (pcon) { 2216 | strcpy(pcon->error, "No Memory"); 2217 | } 2218 | rc = -1; 2219 | } 2220 | return rc; 2221 | } 2222 | 2223 | 2224 | NETXPROC netx_dso_sym(NETXPLIB plibrary, char * symbol) 2225 | { 2226 | NETXPROC pproc; 2227 | 2228 | #if defined(_WIN32) 2229 | pproc = GetProcAddress(plibrary, symbol); 2230 | #else 2231 | pproc = (void *) dlsym(plibrary, symbol); 2232 | #endif 2233 | 2234 | return pproc; 2235 | } 2236 | 2237 | 2238 | 2239 | int netx_dso_unload(NETXPLIB plibrary) 2240 | { 2241 | 2242 | #if defined(_WIN32) 2243 | FreeLibrary(plibrary); 2244 | #else 2245 | dlclose(plibrary); 2246 | #endif 2247 | 2248 | return 1; 2249 | } 2250 | 2251 | 2252 | int netx_load_winsock(NETXCON *pcon, int context) 2253 | { 2254 | #if defined(_WIN32) 2255 | int result, mem_locked; 2256 | char buffer[1024]; 2257 | 2258 | result = 0; 2259 | mem_locked = 0; 2260 | *buffer = '\0'; 2261 | netx_so.version_requested = 0; 2262 | 2263 | if (netx_so.load_attempted) 2264 | return result; 2265 | 2266 | if (netx_so.load_attempted) 2267 | goto netx_load_winsock_no_so; 2268 | 2269 | netx_so.sock = 0; 2270 | 2271 | /* Try to Load the Winsock 2 library */ 2272 | 2273 | netx_so.winsock = 2; 2274 | strcpy(netx_so.libnam, "WS2_32.DLL"); 2275 | 2276 | netx_so.plibrary = netx_dso_load(netx_so.libnam); 2277 | 2278 | if (pcon->trace == 1) { 2279 | fprintf(pcon->pftrace, "\r\n >>> %p==netx_dso_load(%s)", netx_so.plibrary, netx_so.libnam); 2280 | fflush(pcon->pftrace); 2281 | } 2282 | 2283 | if (!netx_so.plibrary) { 2284 | netx_so.winsock = 1; 2285 | strcpy(netx_so.libnam, "WSOCK32.DLL"); 2286 | netx_so.plibrary = netx_dso_load(netx_so.libnam); 2287 | 2288 | if (pcon->trace == 1) { 2289 | fprintf(pcon->pftrace, "\r\n >>> %p==netx_dso_load(%s)", netx_so.plibrary, netx_so.libnam); 2290 | fflush(pcon->pftrace); 2291 | } 2292 | 2293 | if (!netx_so.plibrary) { 2294 | goto netx_load_winsock_no_so; 2295 | } 2296 | } 2297 | 2298 | netx_so.p_WSASocket = (LPFN_WSASOCKET) netx_dso_sym(netx_so.plibrary, (char *) "WSASocketA"); 2299 | netx_so.p_WSAGetLastError = (LPFN_WSAGETLASTERROR) netx_dso_sym(netx_so.plibrary, (char *) "WSAGetLastError"); 2300 | netx_so.p_WSAStartup = (LPFN_WSASTARTUP) netx_dso_sym(netx_so.plibrary, (char *) "WSAStartup"); 2301 | netx_so.p_WSACleanup = (LPFN_WSACLEANUP) netx_dso_sym(netx_so.plibrary, (char *) "WSACleanup"); 2302 | netx_so.p_WSAFDIsSet = (LPFN_WSAFDISSET) netx_dso_sym(netx_so.plibrary, (char *) "__WSAFDIsSet"); 2303 | netx_so.p_WSARecv = (LPFN_WSARECV) netx_dso_sym(netx_so.plibrary, (char *) "WSARecv"); 2304 | netx_so.p_WSASend = (LPFN_WSASEND) netx_dso_sym(netx_so.plibrary, (char *) "WSASend"); 2305 | 2306 | #if defined(NETX_IPV6) 2307 | netx_so.p_WSAStringToAddress = (LPFN_WSASTRINGTOADDRESS) netx_dso_sym(netx_so.plibrary, (char *) "WSAStringToAddressA"); 2308 | netx_so.p_WSAAddressToString = (LPFN_WSAADDRESSTOSTRING) netx_dso_sym(netx_so.plibrary, (char *) "WSAAddressToStringA"); 2309 | netx_so.p_getaddrinfo = (LPFN_GETADDRINFO) netx_dso_sym(netx_so.plibrary, (char *) "getaddrinfo"); 2310 | netx_so.p_freeaddrinfo = (LPFN_FREEADDRINFO) netx_dso_sym(netx_so.plibrary, (char *) "freeaddrinfo"); 2311 | netx_so.p_getnameinfo = (LPFN_GETNAMEINFO) netx_dso_sym(netx_so.plibrary, (char *) "getnameinfo"); 2312 | netx_so.p_getpeername = (LPFN_GETPEERNAME) netx_dso_sym(netx_so.plibrary, (char *) "getpeername"); 2313 | netx_so.p_inet_ntop = (LPFN_INET_NTOP) netx_dso_sym(netx_so.plibrary, (char *) "InetNtop"); 2314 | netx_so.p_inet_pton = (LPFN_INET_PTON) netx_dso_sym(netx_so.plibrary, (char *) "InetPton"); 2315 | #else 2316 | netx_so.p_WSAStringToAddress = NULL; 2317 | netx_so.p_WSAAddressToString = NULL; 2318 | netx_so.p_getaddrinfo = NULL; 2319 | netx_so.p_freeaddrinfo = NULL; 2320 | netx_so.p_getnameinfo = NULL; 2321 | netx_so.p_getpeername = NULL; 2322 | netx_so.p_inet_ntop = NULL; 2323 | netx_so.p_inet_pton = NULL; 2324 | #endif 2325 | 2326 | netx_so.p_closesocket = (LPFN_CLOSESOCKET) netx_dso_sym(netx_so.plibrary, (char *) "closesocket"); 2327 | netx_so.p_gethostname = (LPFN_GETHOSTNAME) netx_dso_sym(netx_so.plibrary, (char *) "gethostname"); 2328 | netx_so.p_gethostbyname = (LPFN_GETHOSTBYNAME) netx_dso_sym(netx_so.plibrary, (char *) "gethostbyname"); 2329 | netx_so.p_getservbyname = (LPFN_GETSERVBYNAME) netx_dso_sym(netx_so.plibrary, (char *) "getservbyname"); 2330 | netx_so.p_gethostbyaddr = (LPFN_GETHOSTBYADDR) netx_dso_sym(netx_so.plibrary, (char *) "gethostbyaddr"); 2331 | netx_so.p_htons = (LPFN_HTONS) netx_dso_sym(netx_so.plibrary, (char *) "htons"); 2332 | netx_so.p_htonl = (LPFN_HTONL) netx_dso_sym(netx_so.plibrary, (char *) "htonl"); 2333 | netx_so.p_ntohl = (LPFN_NTOHL) netx_dso_sym(netx_so.plibrary, (char *) "ntohl"); 2334 | netx_so.p_ntohs = (LPFN_NTOHS) netx_dso_sym(netx_so.plibrary, (char *) "ntohs"); 2335 | netx_so.p_connect = (LPFN_CONNECT) netx_dso_sym(netx_so.plibrary, (char *) "connect"); 2336 | netx_so.p_inet_addr = (LPFN_INET_ADDR) netx_dso_sym(netx_so.plibrary, (char *) "inet_addr"); 2337 | netx_so.p_inet_ntoa = (LPFN_INET_NTOA) netx_dso_sym(netx_so.plibrary, (char *) "inet_ntoa"); 2338 | 2339 | netx_so.p_socket = (LPFN_SOCKET) netx_dso_sym(netx_so.plibrary, (char *) "socket"); 2340 | netx_so.p_ioctlsocket = (LPFN_IOCTLSOCKET) netx_dso_sym(netx_so.plibrary, (char *) "ioctlsocket"); 2341 | netx_so.p_setsockopt = (LPFN_SETSOCKOPT) netx_dso_sym(netx_so.plibrary, (char *) "setsockopt"); 2342 | netx_so.p_getsockopt = (LPFN_GETSOCKOPT) netx_dso_sym(netx_so.plibrary, (char *) "getsockopt"); 2343 | netx_so.p_getsockname = (LPFN_GETSOCKNAME) netx_dso_sym(netx_so.plibrary, (char *) "getsockname"); 2344 | 2345 | netx_so.p_select = (LPFN_SELECT) netx_dso_sym(netx_so.plibrary, (char *) "select"); 2346 | netx_so.p_recv = (LPFN_RECV) netx_dso_sym(netx_so.plibrary, (char *) "recv"); 2347 | netx_so.p_send = (LPFN_SEND) netx_dso_sym(netx_so.plibrary, (char *) "send"); 2348 | netx_so.p_shutdown = (LPFN_SHUTDOWN) netx_dso_sym(netx_so.plibrary, (char *) "shutdown"); 2349 | netx_so.p_bind = (LPFN_BIND) netx_dso_sym(netx_so.plibrary, (char *) "bind"); 2350 | netx_so.p_listen = (LPFN_LISTEN) netx_dso_sym(netx_so.plibrary, (char *) "listen"); 2351 | netx_so.p_accept = (LPFN_ACCEPT) netx_dso_sym(netx_so.plibrary, (char *) "accept"); 2352 | 2353 | if ( (netx_so.p_WSASocket == NULL && netx_so.winsock == 2) 2354 | || netx_so.p_WSAGetLastError == NULL 2355 | || netx_so.p_WSAStartup == NULL 2356 | || netx_so.p_WSACleanup == NULL 2357 | || netx_so.p_WSAFDIsSet == NULL 2358 | || (netx_so.p_WSARecv == NULL && netx_so.winsock == 2) 2359 | || (netx_so.p_WSASend == NULL && netx_so.winsock == 2) 2360 | 2361 | #if defined(NETX_IPV6) 2362 | || (netx_so.p_WSAStringToAddress == NULL && netx_so.winsock == 2) 2363 | || (netx_so.p_WSAAddressToString == NULL && netx_so.winsock == 2) 2364 | || netx_so.p_getpeername == NULL 2365 | #endif 2366 | 2367 | || netx_so.p_closesocket == NULL 2368 | || netx_so.p_gethostname == NULL 2369 | || netx_so.p_gethostbyname == NULL 2370 | || netx_so.p_getservbyname == NULL 2371 | || netx_so.p_gethostbyaddr == NULL 2372 | || netx_so.p_htons == NULL 2373 | || netx_so.p_htonl == NULL 2374 | || netx_so.p_ntohl == NULL 2375 | || netx_so.p_ntohs == NULL 2376 | || netx_so.p_connect == NULL 2377 | || netx_so.p_inet_addr == NULL 2378 | || netx_so.p_inet_ntoa == NULL 2379 | || netx_so.p_socket == NULL 2380 | || netx_so.p_setsockopt == NULL 2381 | || netx_so.p_getsockopt == NULL 2382 | || netx_so.p_getsockname == NULL 2383 | || netx_so.p_select == NULL 2384 | || netx_so.p_recv == NULL 2385 | || netx_so.p_send == NULL 2386 | || netx_so.p_shutdown == NULL 2387 | || netx_so.p_bind == NULL 2388 | || netx_so.p_listen == NULL 2389 | || netx_so.p_accept == NULL 2390 | ) { 2391 | 2392 | sprintf(buffer, "Cannot use Winsock library (WSASocket=%p; WSAGetLastError=%p; WSAStartup=%p; WSACleanup=%p; WSAFDIsSet=%p; WSARecv=%p; WSASend=%p; WSAStringToAddress=%p; WSAAddressToString=%p; closesocket=%p; gethostname=%p; gethostbyname=%p; getservbyname=%p; gethostbyaddr=%p; getaddrinfo=%p; freeaddrinfo=%p; getnameinfo=%p; getpeername=%p; htons=%p; htonl=%p; ntohl=%p; ntohs=%p; connect=%p; inet_addr=%p; inet_ntoa=%p; socket=%p; setsockopt=%p; getsockopt=%p; getsockname=%p; select=%p; recv=%p; p_send=%p; shutdown=%p; bind=%p; listen=%p; accept=%p;)", 2393 | netx_so.p_WSASocket, 2394 | netx_so.p_WSAGetLastError, 2395 | netx_so.p_WSAStartup, 2396 | netx_so.p_WSACleanup, 2397 | netx_so.p_WSAFDIsSet, 2398 | netx_so.p_WSARecv, 2399 | netx_so.p_WSASend, 2400 | 2401 | netx_so.p_WSAStringToAddress, 2402 | netx_so.p_WSAAddressToString, 2403 | 2404 | netx_so.p_closesocket, 2405 | netx_so.p_gethostname, 2406 | netx_so.p_gethostbyname, 2407 | netx_so.p_getservbyname, 2408 | netx_so.p_gethostbyaddr, 2409 | 2410 | netx_so.p_getaddrinfo, 2411 | netx_so.p_freeaddrinfo, 2412 | netx_so.p_getnameinfo, 2413 | netx_so.p_getpeername, 2414 | 2415 | netx_so.p_htons, 2416 | netx_so.p_htonl, 2417 | netx_so.p_ntohl, 2418 | netx_so.p_ntohs, 2419 | netx_so.p_connect, 2420 | netx_so.p_inet_addr, 2421 | netx_so.p_inet_ntoa, 2422 | netx_so.p_socket, 2423 | netx_so.p_setsockopt, 2424 | netx_so.p_getsockopt, 2425 | netx_so.p_getsockname, 2426 | netx_so.p_select, 2427 | netx_so.p_recv, 2428 | netx_so.p_send, 2429 | netx_so.p_shutdown, 2430 | netx_so.p_bind, 2431 | netx_so.p_listen, 2432 | netx_so.p_accept 2433 | ); 2434 | netx_dso_unload((NETXPLIB) netx_so.plibrary); 2435 | } 2436 | else { 2437 | netx_so.sock = 1; 2438 | } 2439 | 2440 | if (netx_so.sock) 2441 | result = 0; 2442 | else 2443 | result = -1; 2444 | 2445 | netx_so.load_attempted = 1; 2446 | 2447 | if (netx_so.p_getaddrinfo == NULL || netx_so.p_freeaddrinfo == NULL || netx_so.p_getnameinfo == NULL) 2448 | netx_so.ipv6 = 0; 2449 | 2450 | netx_load_winsock_no_so: 2451 | 2452 | if (result == 0) { 2453 | 2454 | if (netx_so.winsock == 2) 2455 | netx_so.version_requested = MAKEWORD(2, 2); 2456 | else 2457 | netx_so.version_requested = MAKEWORD(1, 1); 2458 | 2459 | netx_so.wsastartup = NETX_WSASTARTUP(netx_so.version_requested, &(netx_so.wsadata)); 2460 | if (pcon->trace == 1) { 2461 | fprintf(pcon->pftrace, "\r\n -> %d<=WSAStartup(%d, %p)", netx_so.wsastartup, netx_so.version_requested, &(netx_so.wsadata)); 2462 | fflush(pcon->pftrace); 2463 | } 2464 | 2465 | if (netx_so.wsastartup != 0 && netx_so.winsock == 2) { 2466 | netx_so.version_requested = MAKEWORD(2, 0); 2467 | netx_so.wsastartup = NETX_WSASTARTUP(netx_so.version_requested, &(netx_so.wsadata)); 2468 | if (netx_so.wsastartup != 0) { 2469 | netx_so.winsock = 1; 2470 | netx_so.version_requested = MAKEWORD(1, 1); 2471 | netx_so.wsastartup = NETX_WSASTARTUP(netx_so.version_requested, &(netx_so.wsadata)); 2472 | } 2473 | } 2474 | if (netx_so.wsastartup == 0) { 2475 | if ((netx_so.winsock == 2 && LOBYTE(netx_so.wsadata.wVersion) != 2) 2476 | || (netx_so.winsock == 1 && (LOBYTE(netx_so.wsadata.wVersion) != 1 || HIBYTE(netx_so.wsadata.wVersion) != 1))) { 2477 | 2478 | sprintf(pcon->error, "Initialization Error: Wrong version of Winsock library (%s) (%d.%d)", netx_so.libnam, LOBYTE(netx_so.wsadata.wVersion), HIBYTE(netx_so.wsadata.wVersion)); 2479 | NETX_WSACLEANUP(); 2480 | netx_so.wsastartup = -1; 2481 | } 2482 | else { 2483 | if (strlen(netx_so.libnam)) 2484 | sprintf(pcon->info, "Initialization: Windows Sockets library loaded (%s) Version: %d.%d", netx_so.libnam, LOBYTE(netx_so.wsadata.wVersion), HIBYTE(netx_so.wsadata.wVersion)); 2485 | else 2486 | sprintf(pcon->info, "Initialization: Windows Sockets library Version: %d.%d", LOBYTE(netx_so.wsadata.wVersion), HIBYTE(netx_so.wsadata.wVersion)); 2487 | netx_so.winsock_ready = 1; 2488 | } 2489 | } 2490 | else { 2491 | strcpy(pcon->error, "Initialization Error: Unusable Winsock library"); 2492 | } 2493 | } 2494 | 2495 | return result; 2496 | 2497 | #else 2498 | 2499 | return 0; 2500 | 2501 | #endif /* #if defined(_WIN32) */ 2502 | 2503 | } 2504 | 2505 | 2506 | int netx_tcp_connect(NETXCON *pcon, int context) 2507 | { 2508 | short physical_ip, ipv6, connected, getaddrinfo_ok; 2509 | int n, errorno; 2510 | unsigned long inetaddr; 2511 | DWORD spin_count; 2512 | char ansi_ip_address[64]; 2513 | struct sockaddr_in srv_addr, cli_addr; 2514 | struct hostent *hp; 2515 | struct in_addr **pptr; 2516 | 2517 | pcon->connected = 0; 2518 | pcon->error_no = 0; 2519 | connected = 0; 2520 | getaddrinfo_ok = 0; 2521 | spin_count = 0; 2522 | 2523 | ipv6 = 1; 2524 | #if !defined(NETX_IPV6) 2525 | ipv6 = 0; 2526 | #endif 2527 | 2528 | if (pcon->trace == 1) { 2529 | fprintf(pcon->pftrace, "\r\n -> netx_tcp_connect(ip=%s, port=%d)", pcon->ip_address, pcon->port); 2530 | fflush(pcon->pftrace); 2531 | } 2532 | 2533 | strcpy(ansi_ip_address, (char *) pcon->ip_address); 2534 | 2535 | #if defined(_WIN32) 2536 | 2537 | n = netx_so.wsastartup; 2538 | if (n != 0) { 2539 | strcpy(pcon->error, (char *) "DLL Load Error: Unusable Winsock Library"); 2540 | return n; 2541 | } 2542 | 2543 | #endif /* #if defined(_WIN32) */ 2544 | 2545 | #if defined(NETX_IPV6) 2546 | 2547 | if (ipv6) { 2548 | short mode; 2549 | struct addrinfo hints, *res; 2550 | struct addrinfo *ai; 2551 | char port_str[32]; 2552 | 2553 | res = NULL; 2554 | sprintf(port_str, "%d", pcon->port); 2555 | connected = 0; 2556 | pcon->error_no = 0; 2557 | 2558 | for (mode = 0; mode < 3; mode ++) { 2559 | 2560 | if (res) { 2561 | NETX_FREEADDRINFO(res); 2562 | if (pcon->trace == 1) { 2563 | fprintf(pcon->pftrace, "\r\n -> (void)<=freeaddrinfo(%p)", res); 2564 | fflush(pcon->pftrace); 2565 | } 2566 | res = NULL; 2567 | } 2568 | 2569 | memset(&hints, 0, sizeof hints); 2570 | hints.ai_family = AF_UNSPEC; /* Use IPv4 or IPv6 */ 2571 | hints.ai_socktype = SOCK_STREAM; 2572 | /* hints.ai_flags = AI_PASSIVE; */ 2573 | if (mode == 0) 2574 | hints.ai_flags = AI_NUMERICHOST | AI_CANONNAME; 2575 | else if (mode == 1) 2576 | hints.ai_flags = AI_CANONNAME; 2577 | else if (mode == 2) { 2578 | /* Apparently an error can occur with AF_UNSPEC (See RJW1564) */ 2579 | /* This iteration will return IPV6 addresses if any */ 2580 | hints.ai_flags = AI_CANONNAME; 2581 | hints.ai_family = AF_INET6; 2582 | } 2583 | else 2584 | break; 2585 | 2586 | n = NETX_GETADDRINFO(ansi_ip_address, port_str, &hints, &res); 2587 | if (pcon->trace == 1) { 2588 | fprintf(pcon->pftrace, "\r\n -> %d<=getaddrinfo(%s, %s, %p, %p)", n, ansi_ip_address, port_str, &hints, &res); 2589 | fflush(pcon->pftrace); 2590 | } 2591 | 2592 | if (n != 0) { 2593 | continue; 2594 | } 2595 | 2596 | getaddrinfo_ok = 1; 2597 | spin_count = 0; 2598 | for (ai = res; ai != NULL; ai = ai->ai_next) { 2599 | 2600 | spin_count ++; 2601 | 2602 | if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) { 2603 | continue; 2604 | } 2605 | 2606 | /* Open a socket with the correct address family for this address. */ 2607 | pcon->cli_socket = NETX_SOCKET(ai->ai_family, ai->ai_socktype, ai->ai_protocol); 2608 | if (pcon->trace == 1) { 2609 | fprintf(pcon->pftrace, "\r\n -> %d<=socket(%d, %d, %d)", (int) pcon->cli_socket, ai->ai_family, ai->ai_socktype, ai->ai_protocol); 2610 | fflush(pcon->pftrace); 2611 | } 2612 | 2613 | /* NETX_BIND(pcon->cli_socket, ai->ai_addr, (int) (ai->ai_addrlen)); */ 2614 | /* NETX_CONNECT(pcon->cli_socket, ai->ai_addr, (int) (ai->ai_addrlen)); */ 2615 | 2616 | if (netx_so.nagle_algorithm == 0) { 2617 | 2618 | int flag = 1; 2619 | int result; 2620 | 2621 | result = NETX_SETSOCKOPT(pcon->cli_socket, IPPROTO_TCP, TCP_NODELAY, (const char *) &flag, sizeof(int)); 2622 | if (pcon->trace == 1) { 2623 | fprintf(pcon->pftrace, "\r\n -> %d<=setsockopt(%d, %d, %d, %p, %d)", result, (int) pcon->cli_socket, IPPROTO_TCP, TCP_NODELAY, (const char *) &flag, (int) sizeof(int)); 2624 | fflush(pcon->pftrace); 2625 | } 2626 | 2627 | if (result < 0) { 2628 | strcpy(pcon->error, "Connection Error: Unable to disable the Nagle Algorithm"); 2629 | } 2630 | 2631 | } 2632 | 2633 | pcon->error_no = 0; 2634 | n = netx_tcp_connect_ex(pcon, (xLPSOCKADDR) ai->ai_addr, (socklen_netx) (ai->ai_addrlen), pcon->timeout); 2635 | if (n == -2) { 2636 | pcon->error_no = n; 2637 | n = -737; 2638 | continue; 2639 | } 2640 | if (SOCK_ERROR(n)) { 2641 | errorno = (int) netx_get_last_error(0); 2642 | pcon->error_no = errorno; 2643 | netx_tcp_disconnect(pcon, 0); 2644 | continue; 2645 | } 2646 | else { 2647 | connected = 1; 2648 | break; 2649 | } 2650 | } 2651 | if (connected) 2652 | break; 2653 | } 2654 | 2655 | if (pcon->error_no) { 2656 | char message[256]; 2657 | netx_get_error_message(pcon->error_no, message, 250, 0); 2658 | sprintf(pcon->error, "Connection Error: Cannot Connect to Server (%s:%d): Error Code: %d (%s)", (char *) pcon->ip_address, pcon->port, pcon->error_no, message); 2659 | n = -5; 2660 | } 2661 | 2662 | if (res) { 2663 | NETX_FREEADDRINFO(res); 2664 | res = NULL; 2665 | } 2666 | } 2667 | #endif 2668 | 2669 | if (ipv6) { 2670 | if (connected) { 2671 | pcon->connected = 1; 2672 | return 0; 2673 | } 2674 | else { 2675 | if (getaddrinfo_ok) { 2676 | netx_tcp_disconnect(pcon, 0); 2677 | return -5; 2678 | } 2679 | else { 2680 | char message[256]; 2681 | 2682 | errorno = (int) netx_get_last_error(0); 2683 | netx_get_error_message(errorno, message, 250, 0); 2684 | sprintf(pcon->error, "Connection Error: Cannot identify Server: Error Code: %d (%s)", errorno, message); 2685 | netx_tcp_disconnect(pcon, 0); 2686 | return -5; 2687 | } 2688 | } 2689 | } 2690 | 2691 | ipv6 = 0; 2692 | inetaddr = NETX_INET_ADDR(ansi_ip_address); 2693 | if (pcon->trace == 1) { 2694 | fprintf(pcon->pftrace, "\r\n -> %lu<=inet_addr(%s)", inetaddr, ansi_ip_address); 2695 | fflush(pcon->pftrace); 2696 | } 2697 | 2698 | physical_ip = 0; 2699 | if (isdigit(ansi_ip_address[0])) { 2700 | char *p; 2701 | 2702 | if ((p = strstr(ansi_ip_address, "."))) { 2703 | if (isdigit(*(++ p))) { 2704 | if ((p = strstr(p, "."))) { 2705 | if (isdigit(*(++ p))) { 2706 | if ((p = strstr(p, "."))) { 2707 | if (isdigit(*(++ p))) { 2708 | physical_ip = 1; 2709 | } 2710 | } 2711 | } 2712 | } 2713 | } 2714 | } 2715 | } 2716 | 2717 | if (inetaddr == INADDR_NONE || !physical_ip) { 2718 | 2719 | hp = NETX_GETHOSTBYNAME((const char *) ansi_ip_address); 2720 | if (pcon->trace == 1) { 2721 | fprintf(pcon->pftrace, "\r\n -> %p<=gethostbyname(%s)", hp, ansi_ip_address); 2722 | fflush(pcon->pftrace); 2723 | } 2724 | if (hp == NULL) { 2725 | n = -2; 2726 | strcpy(pcon->error, "Connection Error: Invalid Host"); 2727 | return n; 2728 | } 2729 | 2730 | pptr = (struct in_addr **) hp->h_addr_list; 2731 | connected = 0; 2732 | 2733 | spin_count = 0; 2734 | 2735 | for (; *pptr != NULL; pptr ++) { 2736 | 2737 | spin_count ++; 2738 | 2739 | pcon->cli_socket = NETX_SOCKET(AF_INET, SOCK_STREAM, 0); 2740 | if (pcon->trace == 1) { 2741 | fprintf(pcon->pftrace, "\r\n -> %d<=socket(%d, %d, %d)", (int) pcon->cli_socket, AF_INET, SOCK_STREAM, 0); 2742 | fflush(pcon->pftrace); 2743 | } 2744 | 2745 | if (INVALID_SOCK(pcon->cli_socket)) { 2746 | char message[256]; 2747 | 2748 | n = -2; 2749 | errorno = (int) netx_get_last_error(0); 2750 | netx_get_error_message(errorno, message, 250, 0); 2751 | sprintf(pcon->error, "Connection Error: Invalid Socket: Context=1: Error Code: %d (%s)", errorno, message); 2752 | break; 2753 | } 2754 | 2755 | #if !defined(_WIN32) 2756 | BZERO((char *) &cli_addr, sizeof(cli_addr)); 2757 | BZERO((char *) &srv_addr, sizeof(srv_addr)); 2758 | #endif 2759 | 2760 | cli_addr.sin_family = AF_INET; 2761 | srv_addr.sin_port = NETX_HTONS((unsigned short) pcon->port); 2762 | if (pcon->trace == 1) { 2763 | fprintf(pcon->pftrace, "\r\n -> %d<=htons(%d)", (int) srv_addr.sin_port, (int) pcon->port); 2764 | fflush(pcon->pftrace); 2765 | } 2766 | 2767 | cli_addr.sin_addr.s_addr = NETX_HTONL(INADDR_ANY); 2768 | cli_addr.sin_port = NETX_HTONS(0); 2769 | 2770 | n = NETX_BIND(pcon->cli_socket, (xLPSOCKADDR) &cli_addr, sizeof(cli_addr)); 2771 | if (pcon->trace == 1) { 2772 | fprintf(pcon->pftrace, "\r\n -> %d<=bind(%d, %p, %lu)", n, (int) pcon->cli_socket, &cli_addr, (unsigned long) sizeof(cli_addr)); 2773 | fflush(pcon->pftrace); 2774 | } 2775 | 2776 | if (SOCK_ERROR(n)) { 2777 | char message[256]; 2778 | 2779 | n = -3; 2780 | errorno = (int) netx_get_last_error(0); 2781 | netx_get_error_message(errorno, message, 250, 0); 2782 | sprintf(pcon->error, "Connection Error: Cannot bind to Socket: Error Code: %d (%s)", errorno, message); 2783 | 2784 | break; 2785 | } 2786 | 2787 | if (netx_so.nagle_algorithm == 0) { 2788 | 2789 | int flag = 1; 2790 | int result; 2791 | 2792 | result = NETX_SETSOCKOPT(pcon->cli_socket, IPPROTO_TCP, TCP_NODELAY, (const char *) &flag, sizeof(int)); 2793 | if (result < 0) { 2794 | strcpy(pcon->error, "Connection Error: Unable to disable the Nagle Algorithm"); 2795 | } 2796 | } 2797 | 2798 | srv_addr.sin_family = AF_INET; 2799 | srv_addr.sin_port = NETX_HTONS((unsigned short) pcon->port); 2800 | if (pcon->trace == 1) { 2801 | fprintf(pcon->pftrace, "\r\n -> %d<=htons(%d)", (int) srv_addr.sin_port, (int) pcon->port); 2802 | fflush(pcon->pftrace); 2803 | } 2804 | 2805 | NETX_MEMCPY(&srv_addr.sin_addr, *pptr, sizeof(struct in_addr)); 2806 | 2807 | n = netx_tcp_connect_ex(pcon, (xLPSOCKADDR) &srv_addr, sizeof(srv_addr), pcon->timeout); 2808 | 2809 | if (n == -2) { 2810 | pcon->error_no = n; 2811 | n = -737; 2812 | 2813 | continue; 2814 | } 2815 | 2816 | if (SOCK_ERROR(n)) { 2817 | char message[256]; 2818 | 2819 | errorno = (int) netx_get_last_error(0); 2820 | netx_get_error_message(errorno, message, 250, 0); 2821 | 2822 | pcon->error_no = errorno; 2823 | sprintf(pcon->error, "Connection Error: Cannot Connect to Server (%s:%d): Error Code: %d (%s)", (char *) pcon->ip_address, pcon->port, errorno, message); 2824 | n = -5; 2825 | netx_tcp_disconnect(pcon, 0); 2826 | continue; 2827 | } 2828 | else { 2829 | connected = 1; 2830 | break; 2831 | } 2832 | } 2833 | if (!connected) { 2834 | 2835 | netx_tcp_disconnect(pcon, 0); 2836 | 2837 | strcpy(pcon->error, "Connection Error: Failed to find the Server via a DNS Lookup"); 2838 | 2839 | return n; 2840 | } 2841 | } 2842 | else { 2843 | 2844 | pcon->cli_socket = NETX_SOCKET(AF_INET, SOCK_STREAM, 0); 2845 | if (pcon->trace == 1) { 2846 | fprintf(pcon->pftrace, "\r\n -> %d<=socket(%d, %d, %d)", (int) pcon->cli_socket, AF_INET, SOCK_STREAM, 0); 2847 | fflush(pcon->pftrace); 2848 | } 2849 | 2850 | if (INVALID_SOCK(pcon->cli_socket)) { 2851 | char message[256]; 2852 | 2853 | n = -2; 2854 | errorno = (int) netx_get_last_error(0); 2855 | netx_get_error_message(errorno, message, 250, 0); 2856 | sprintf(pcon->error, "Connection Error: Invalid Socket: Context=2: Error Code: %d (%s)", errorno, message); 2857 | 2858 | return n; 2859 | } 2860 | 2861 | #if !defined(_WIN32) 2862 | BZERO((char *) &cli_addr, sizeof(cli_addr)); 2863 | BZERO((char *) &srv_addr, sizeof(srv_addr)); 2864 | #endif 2865 | 2866 | cli_addr.sin_family = AF_INET; 2867 | cli_addr.sin_addr.s_addr = NETX_HTONL(INADDR_ANY); 2868 | cli_addr.sin_port = NETX_HTONS(0); 2869 | 2870 | n = NETX_BIND(pcon->cli_socket, (xLPSOCKADDR) &cli_addr, sizeof(cli_addr)); 2871 | if (pcon->trace == 1) { 2872 | fprintf(pcon->pftrace, "\r\n -> %d<=bind(%d, %p, %lu)", n, (int) pcon->cli_socket, &cli_addr, (unsigned long) sizeof(cli_addr)); 2873 | fflush(pcon->pftrace); 2874 | } 2875 | 2876 | if (SOCK_ERROR(n)) { 2877 | char message[256]; 2878 | 2879 | n = -3; 2880 | 2881 | errorno = (int) netx_get_last_error(0); 2882 | netx_get_error_message(errorno, message, 250, 0); 2883 | 2884 | sprintf(pcon->error, "Connection Error: Cannot bind to Socket: Error Code: %d (%s)", errorno, message); 2885 | 2886 | netx_tcp_disconnect(pcon, 0); 2887 | 2888 | return n; 2889 | } 2890 | 2891 | if (netx_so.nagle_algorithm == 0) { 2892 | 2893 | int flag = 1; 2894 | int result; 2895 | 2896 | result = NETX_SETSOCKOPT(pcon->cli_socket, IPPROTO_TCP, TCP_NODELAY, (const char *) &flag, sizeof(int)); 2897 | if (pcon->trace == 1) { 2898 | fprintf(pcon->pftrace, "\r\n -> %d<=setsockopt(%d, %d, %d, %p, %lu)", result, (int) pcon->cli_socket, IPPROTO_TCP, TCP_NODELAY, &flag, (unsigned long) sizeof(int)); 2899 | fflush(pcon->pftrace); 2900 | } 2901 | if (result < 0) { 2902 | strcpy(pcon->error, "Connection Error: Unable to disable the Nagle Algorithm"); 2903 | 2904 | } 2905 | } 2906 | 2907 | srv_addr.sin_port = NETX_HTONS((unsigned short) pcon->port); 2908 | srv_addr.sin_family = AF_INET; 2909 | srv_addr.sin_addr.s_addr = NETX_INET_ADDR(ansi_ip_address); 2910 | 2911 | n = netx_tcp_connect_ex(pcon, (xLPSOCKADDR) &srv_addr, sizeof(srv_addr), pcon->timeout); 2912 | if (n == -2) { 2913 | pcon->error_no = n; 2914 | n = -737; 2915 | 2916 | netx_tcp_disconnect(pcon, 0); 2917 | 2918 | return n; 2919 | } 2920 | 2921 | if (SOCK_ERROR(n)) { 2922 | char message[256]; 2923 | 2924 | errorno = (int) netx_get_last_error(0); 2925 | netx_get_error_message(errorno, message, 250, 0); 2926 | pcon->error_no = errorno; 2927 | sprintf(pcon->error, "Connection Error: Cannot Connect to Server (%s:%d): Error Code: %d (%s)", (char *) pcon->ip_address, pcon->port, errorno, message); 2928 | n = -5; 2929 | netx_tcp_disconnect(pcon, 0); 2930 | return n; 2931 | } 2932 | } 2933 | 2934 | pcon->connected = 1; 2935 | 2936 | return 0; 2937 | } 2938 | 2939 | 2940 | int netx_tcp_connect_ex(NETXCON *pcon, xLPSOCKADDR p_srv_addr, socklen_netx srv_addr_len, int timeout) 2941 | { 2942 | #if defined(_WIN32) 2943 | int n; 2944 | unsigned long imode; 2945 | fd_set eset, wset; 2946 | struct timeval tval; 2947 | #else 2948 | int flags, n, error; 2949 | socklen_netx len; 2950 | fd_set rset, wset; 2951 | struct timeval tval; 2952 | #endif 2953 | 2954 | #if defined(SOLARIS) 2955 | timeout = 0; 2956 | #endif 2957 | 2958 | if (timeout != 0) { 2959 | 2960 | #if defined(_WIN32) 2961 | 2962 | /* v1.3.13 */ 2963 | imode = 1; 2964 | n = NETX_IOCTLSOCKET(pcon->cli_socket, FIONBIO, &imode); 2965 | if (pcon->trace == 1) { 2966 | fprintf(pcon->pftrace, "\r\n -> %d<=ioctlsocket(%d, FIONBIO, %d)", n, (int) pcon->cli_socket, (int) imode); 2967 | fflush(pcon->pftrace); 2968 | } 2969 | if (n == SOCKET_ERROR) { 2970 | NETX_CLOSESOCKET(pcon->cli_socket); 2971 | return (-1); 2972 | } 2973 | 2974 | n = NETX_CONNECT(pcon->cli_socket, (xLPSOCKADDR) p_srv_addr, (socklen_netx) srv_addr_len); 2975 | if (pcon->trace == 1) { 2976 | fprintf(pcon->pftrace, "\r\n -> %d<=connect(%d, %p, %d)", n, (int) pcon->cli_socket, p_srv_addr, (int) srv_addr_len); 2977 | fflush(pcon->pftrace); 2978 | } 2979 | 2980 | if (n == SOCKET_ERROR) { 2981 | 2982 | if (NETX_WSAGETLASTERROR() != WSAEWOULDBLOCK) { 2983 | NETX_CLOSESOCKET(pcon->cli_socket); 2984 | return (-1); 2985 | } 2986 | 2987 | FD_ZERO(&wset); 2988 | FD_ZERO(&eset); 2989 | FD_SET(pcon->cli_socket, &wset); 2990 | FD_SET(pcon->cli_socket, &eset); 2991 | 2992 | tval.tv_sec = timeout; 2993 | tval.tv_usec = 0; 2994 | 2995 | n = NETX_SELECT((int) (pcon->cli_socket + 1), NULL, &wset, &eset, &tval); 2996 | if (pcon->trace == 1) { 2997 | fprintf(pcon->pftrace, "\r\n -> %d<=select(%d, %p, %p, %p, %p{tv_sec=%d; tv_usec=%d})", n, (int) pcon->cli_socket + 1, (void *) 0, &wset, &eset, &tval, (int) tval.tv_sec, (int) tval.tv_usec); 2998 | fflush(pcon->pftrace); 2999 | } 3000 | 3001 | if (n == 0) { /* timeout */ 3002 | NETX_CLOSESOCKET(pcon->cli_socket); 3003 | return (-2); 3004 | } 3005 | if (!NETX_FD_ISSET(pcon->cli_socket, &wset)) { 3006 | n = NETX_CLOSESOCKET(pcon->cli_socket); 3007 | return (-1); 3008 | } 3009 | } 3010 | 3011 | imode = 0; 3012 | n = NETX_IOCTLSOCKET(pcon->cli_socket, FIONBIO, &imode); 3013 | if (pcon->trace == 1) { 3014 | fprintf(pcon->pftrace, "\r\n -> %d<=ioctlsocket(%d, FIONBIO, %d)", n, (int) pcon->cli_socket, (int) imode); 3015 | fflush(pcon->pftrace); 3016 | } 3017 | if (n == SOCKET_ERROR) { 3018 | NETX_CLOSESOCKET(pcon->cli_socket); 3019 | return (-1); 3020 | } 3021 | 3022 | return 0; 3023 | 3024 | #else 3025 | 3026 | flags = fcntl(pcon->cli_socket, F_GETFL, 0); 3027 | n = fcntl(pcon->cli_socket, F_SETFL, flags | O_NONBLOCK); 3028 | if (pcon->trace == 1) { 3029 | fprintf(pcon->pftrace, "\r\n -> %d<=fnctl(%d, %d, %d)", n, (int) pcon->cli_socket, F_SETFL, flags | O_NONBLOCK); 3030 | fflush(pcon->pftrace); 3031 | } 3032 | 3033 | error = 0; 3034 | 3035 | n = NETX_CONNECT(pcon->cli_socket, (xLPSOCKADDR) p_srv_addr, (socklen_netx) srv_addr_len); 3036 | if (pcon->trace == 1) { 3037 | fprintf(pcon->pftrace, "\r\n -> %d<=connect(%d, %p, %d)", n, (int) pcon->cli_socket, p_srv_addr, (int) srv_addr_len); 3038 | fflush(pcon->pftrace); 3039 | } 3040 | 3041 | if (n < 0) { 3042 | 3043 | if (errno != EINPROGRESS) { 3044 | 3045 | #if defined(SOLARIS) 3046 | 3047 | if (errno != 2 && errno != 146) { 3048 | sprintf((char *) pcon->error, "Diagnostic: Solaris: Initial Connection Error errno=%d; EINPROGRESS=%d", errno, EINPROGRESS); 3049 | return -1; 3050 | } 3051 | #else 3052 | return -1; 3053 | #endif 3054 | 3055 | } 3056 | } 3057 | 3058 | if (n != 0) { 3059 | 3060 | FD_ZERO(&rset); 3061 | FD_SET(pcon->cli_socket, &rset); 3062 | 3063 | wset = rset; 3064 | tval.tv_sec = timeout; 3065 | tval.tv_usec = 0; 3066 | 3067 | n = NETX_SELECT((int) (pcon->cli_socket + 1), &rset, &wset, NULL, &tval); 3068 | 3069 | if (n == 0) { 3070 | close(pcon->cli_socket); 3071 | errno = ETIMEDOUT; 3072 | 3073 | return (-2); 3074 | } 3075 | if (NETX_FD_ISSET(pcon->cli_socket, &rset) || NETX_FD_ISSET(pcon->cli_socket, &wset)) { 3076 | 3077 | len = sizeof(error); 3078 | if (NETX_GETSOCKOPT(pcon->cli_socket, SOL_SOCKET, SO_ERROR, (void *) &error, &len) < 0) { 3079 | 3080 | sprintf((char *) pcon->error, "Diagnostic: Solaris: Pending Error %d", errno); 3081 | 3082 | return (-1); /* Solaris pending error */ 3083 | } 3084 | } 3085 | else { 3086 | ; 3087 | } 3088 | } 3089 | 3090 | fcntl(pcon->cli_socket, F_SETFL, flags); /* Restore file status flags */ 3091 | 3092 | if (error) { 3093 | 3094 | close(pcon->cli_socket); 3095 | errno = error; 3096 | return (-1); 3097 | } 3098 | 3099 | return 0; 3100 | 3101 | #endif 3102 | 3103 | } 3104 | else { 3105 | 3106 | n = NETX_CONNECT(pcon->cli_socket, (xLPSOCKADDR) p_srv_addr, (socklen_netx) srv_addr_len); 3107 | 3108 | return n; 3109 | } 3110 | 3111 | } 3112 | 3113 | 3114 | int netx_tcp_disconnect(NETXCON *pcon, int context) 3115 | { 3116 | int n; 3117 | 3118 | if (!pcon) { 3119 | return 0; 3120 | } 3121 | 3122 | if (pcon->cli_socket != (SOCKET) 0) { 3123 | 3124 | #if defined(_WIN32) 3125 | n = NETX_CLOSESOCKET(pcon->cli_socket); 3126 | /* 3127 | NETX_WSACLEANUP(); 3128 | */ 3129 | if (pcon->trace == 1) { 3130 | fprintf(pcon->pftrace, "\r\n -> %d<=closesocket(%d)", n, (int) pcon->cli_socket); 3131 | fflush(pcon->pftrace); 3132 | } 3133 | #else 3134 | n = close(pcon->cli_socket); 3135 | if (pcon->trace == 1) { 3136 | fprintf(pcon->pftrace, "\r\n -> %d<=close(%d)", n, (int) pcon->cli_socket); 3137 | fflush(pcon->pftrace); 3138 | } 3139 | #endif 3140 | 3141 | } 3142 | 3143 | pcon->connected = 0; 3144 | 3145 | return 0; 3146 | 3147 | } 3148 | 3149 | 3150 | int netx_tcp_write(NETXCON *pcon, unsigned char *data, int size) 3151 | { 3152 | int n = 0, errorno = 0, char_sent = 0; 3153 | int total; 3154 | char errormessage[512]; 3155 | 3156 | *errormessage = '\0'; 3157 | 3158 | if (pcon->trace == 1) { 3159 | fprintf(pcon->pftrace, "\r\n -> netx_tcp_write(data=%p, size=%d)", data, size); 3160 | fflush(pcon->pftrace); 3161 | } 3162 | 3163 | if (pcon->connected == 0) { 3164 | strcpy(pcon->error, "TCP Write Error: Socket is Closed"); 3165 | return -1; 3166 | } 3167 | 3168 | total = 0; 3169 | for (;;) { 3170 | n = NETX_SEND(pcon->cli_socket, (xLPSENDBUF) (data + total), size - total, 0); 3171 | 3172 | if (pcon->trace == 1) { 3173 | fprintf(pcon->pftrace, "\r\n -> %d<=send(%d, %p, %d)", n, (int) pcon->cli_socket, data + total, size - total); 3174 | fflush(pcon->pftrace); 3175 | if (n > 0) { 3176 | char buffer[256]; 3177 | netx_format_buffer(buffer, (char *) (data + total), n, 250); 3178 | fprintf(pcon->pftrace, "\r\n -> %s", buffer); 3179 | } 3180 | } 3181 | 3182 | if (SOCK_ERROR(n)) { 3183 | 3184 | errorno = (int) netx_get_last_error(0); 3185 | 3186 | if (NOT_BLOCKING(errorno) && errorno != 0) { 3187 | 3188 | char message[256]; 3189 | 3190 | netx_get_error_message(errorno, message, 250, 0); 3191 | sprintf(pcon->error, "TCP Write Error: Cannot Write Data: Error Code: %d (%s)", errorno, message); 3192 | 3193 | char_sent = -1; 3194 | break; 3195 | } 3196 | } 3197 | else { 3198 | 3199 | total += n; 3200 | if (total == size) { 3201 | break; 3202 | } 3203 | } 3204 | } 3205 | 3206 | if (char_sent < 0) 3207 | return char_sent; 3208 | else 3209 | return size; 3210 | 3211 | } 3212 | 3213 | 3214 | 3215 | int netx_tcp_read(NETXCON *pcon, unsigned char *data, int size, int timeout, int context) 3216 | { 3217 | int result, n; 3218 | int len; 3219 | fd_set rset, eset; 3220 | struct timeval tval; 3221 | unsigned long spin_count; 3222 | 3223 | 3224 | if (!pcon) { 3225 | return NETX_READ_ERROR; 3226 | } 3227 | 3228 | if (pcon->trace == 1) { 3229 | fprintf(pcon->pftrace, "\r\n -> netx_tcp_read(data=%p, size=%d, timeout=%d)", data, size, timeout); 3230 | fflush(pcon->pftrace); 3231 | } 3232 | 3233 | result = 0; 3234 | 3235 | tval.tv_sec = timeout; 3236 | tval.tv_usec = 0; 3237 | 3238 | spin_count = 0; 3239 | len = 0; 3240 | for (;;) { 3241 | spin_count ++; 3242 | 3243 | FD_ZERO(&rset); 3244 | FD_ZERO(&eset); 3245 | FD_SET(pcon->cli_socket, &rset); 3246 | FD_SET(pcon->cli_socket, &eset); 3247 | 3248 | n = NETX_SELECT((int) (pcon->cli_socket + 1), &rset, NULL, &eset, &tval); 3249 | 3250 | if (pcon->trace == 1) { 3251 | fprintf(pcon->pftrace, "\r\n -> %d<=select(%d, %p, %p, %p, %p{tv_sec=%d; tv_usec=%d})", n, (int) pcon->cli_socket + 1, &rset, (void *) 0, &eset, &tval, (int) tval.tv_sec, (int) tval.tv_usec); 3252 | fflush(pcon->pftrace); 3253 | } 3254 | 3255 | if (n == 0) { 3256 | sprintf(pcon->error, "TCP Read Error: Server did not respond within the timeout period (%d seconds)", timeout); 3257 | result = NETX_READ_TIMEOUT; 3258 | break; 3259 | } 3260 | 3261 | if (n < 0 || !NETX_FD_ISSET(pcon->cli_socket, &rset)) { 3262 | strcpy(pcon->error, "TCP Read Error: Server closed the connection without having returned any data"); 3263 | result = NETX_READ_ERROR; 3264 | break; 3265 | } 3266 | 3267 | n = NETX_RECV(pcon->cli_socket, (char *) data + len, size - len, 0); 3268 | 3269 | if (pcon->trace == 1) { 3270 | fprintf(pcon->pftrace, "\r\n -> %d<=recv(%d, %p, %d, 0)", n, (int) pcon->cli_socket, data + len, size - len); 3271 | if (n > 0) { 3272 | char buffer[256]; 3273 | netx_format_buffer(buffer, (char *) (data + len), n, 250); 3274 | fprintf(pcon->pftrace, "\r\n -> %s", buffer); 3275 | } 3276 | fflush(pcon->pftrace); 3277 | } 3278 | 3279 | if (n < 1) { 3280 | if (n == 0) { 3281 | result = NETX_READ_EOF; 3282 | pcon->connected = 0; 3283 | pcon->eof = 1; 3284 | } 3285 | else { 3286 | result = NETX_READ_ERROR; 3287 | len = 0; 3288 | pcon->connected = 0; 3289 | } 3290 | break; 3291 | } 3292 | 3293 | len += n; 3294 | if (context) { /* Must read length requested v1.1.10 */ 3295 | if (len == size) { 3296 | break; 3297 | } 3298 | } 3299 | else { 3300 | break; 3301 | } 3302 | } 3303 | 3304 | if (len) { 3305 | result = len; 3306 | } 3307 | return result; 3308 | } 3309 | 3310 | 3311 | 3312 | int netx_get_last_error(int context) 3313 | { 3314 | int error_code; 3315 | 3316 | #if defined(_WIN32) 3317 | if (context) 3318 | error_code = (int) GetLastError(); 3319 | else 3320 | error_code = (int) NETX_WSAGETLASTERROR(); 3321 | #else 3322 | error_code = (int) errno; 3323 | #endif 3324 | 3325 | return error_code; 3326 | } 3327 | 3328 | /* v1.4.14 */ 3329 | #if !defined(_WIN32) 3330 | 3331 | /* 3332 | strerror_r: Reentrant version of `strerror'. 3333 | There are 2 flavours of `strerror_r', GNU which returns the string and may or may not use the supplied temporary buffer 3334 | and the POSIX one which fills the string into the buffer. 3335 | To use the POSIX version, -D_XOPEN_SOURCE=600 or -D_POSIX_C_SOURCE=200112L without -D_GNU_SOURCE is needed, 3336 | otherwise the GNU version is preferred. 3337 | For the benefit of Alpine Linux we'll use these overloaded functions. 3338 | */ 3339 | 3340 | char * netx_strerror_r(int result, char *buffer, int buffer_size, int error_code) 3341 | { 3342 | if (result) { 3343 | sprintf(buffer, "Unknown error: %d", error_code); 3344 | } 3345 | return buffer; 3346 | } 3347 | 3348 | char * netx_strerror_r(char *result, char *buffer, int buffer_size, int error_code) 3349 | { 3350 | if (result && result != buffer) { 3351 | strncpy(buffer, result, buffer_size - 1); 3352 | buffer[buffer_size - 1] = '\0'; 3353 | } 3354 | return buffer; 3355 | } 3356 | #endif 3357 | 3358 | 3359 | int netx_get_error_message(int error_code, char *message, int size, int context) 3360 | { 3361 | *message = '\0'; 3362 | 3363 | #if defined(_WIN32) 3364 | 3365 | if (context == 0) { 3366 | short ok; 3367 | int len; 3368 | char *p; 3369 | LPVOID lpMsgBuf; 3370 | 3371 | ok = 0; 3372 | lpMsgBuf = NULL; 3373 | len = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 3374 | NULL, 3375 | error_code, 3376 | /* MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), */ 3377 | MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), 3378 | (LPTSTR) &lpMsgBuf, 3379 | 0, 3380 | NULL 3381 | ); 3382 | if (len && lpMsgBuf) { 3383 | strncpy(message, (const char *) lpMsgBuf, size); 3384 | p = strstr(message, "\r\n"); 3385 | if (p) 3386 | *p = '\0'; 3387 | ok = 1; 3388 | } 3389 | if (lpMsgBuf) 3390 | LocalFree(lpMsgBuf); 3391 | 3392 | if (!ok) { 3393 | switch (error_code) { 3394 | case EXCEPTION_ACCESS_VIOLATION: 3395 | strncpy(message, "The thread attempted to read from or write to a virtual address for which it does not have the appropriate access.", size); 3396 | break; 3397 | case EXCEPTION_BREAKPOINT: 3398 | strncpy(message, "A breakpoint was encountered.", size); 3399 | break; 3400 | case EXCEPTION_DATATYPE_MISALIGNMENT: 3401 | strncpy(message, "The thread attempted to read or write data that is misaligned on hardware that does not provide alignment. For example, 16-bit values must be aligned on 2-byte boundaries, 32-bit values on 4-byte boundaries, and so on.", size); 3402 | break; 3403 | case EXCEPTION_SINGLE_STEP: 3404 | strncpy(message, "A trace trap or other single-instruction mechanism signaled that one instruction has been executed.", size); 3405 | break; 3406 | case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: 3407 | strncpy(message, "The thread attempted to access an array element that is out of bounds, and the underlying hardware supports bounds checking.", size); 3408 | break; 3409 | case EXCEPTION_FLT_DENORMAL_OPERAND: 3410 | strncpy(message, "One of the operands in a floating-point operation is denormal. A denormal value is one that is too small to represent as a standard floating-point value.", size); 3411 | break; 3412 | case EXCEPTION_FLT_DIVIDE_BY_ZERO: 3413 | strncpy(message, "The thread attempted to divide a floating-point value by a floating-point divisor of zero.", size); 3414 | break; 3415 | case EXCEPTION_FLT_INEXACT_RESULT: 3416 | strncpy(message, "The result of a floating-point operation cannot be represented exactly as a decimal fraction.", size); 3417 | break; 3418 | case EXCEPTION_FLT_INVALID_OPERATION: 3419 | strncpy(message, "This exception represents any floating-point exception not included in this list.", size); 3420 | break; 3421 | case EXCEPTION_FLT_OVERFLOW: 3422 | strncpy(message, "The exponent of a floating-point operation is greater than the magnitude allowed by the corresponding type.", size); 3423 | break; 3424 | case EXCEPTION_FLT_STACK_CHECK: 3425 | strncpy(message, "The stack overflowed or underflowed as the result of a floating-point operation.", size); 3426 | break; 3427 | case EXCEPTION_FLT_UNDERFLOW: 3428 | strncpy(message, "The exponent of a floating-point operation is less than the magnitude allowed by the corresponding type.", size); 3429 | break; 3430 | case EXCEPTION_INT_DIVIDE_BY_ZERO: 3431 | strncpy(message, "The thread attempted to divide an integer value by an integer divisor of zero.", size); 3432 | break; 3433 | case EXCEPTION_INT_OVERFLOW: 3434 | strncpy(message, "The result of an integer operation caused a carry out of the most significant bit of the result.", size); 3435 | break; 3436 | case EXCEPTION_PRIV_INSTRUCTION: 3437 | strncpy(message, "The thread attempted to execute an instruction whose operation is not allowed in the current machine mode.", size); 3438 | break; 3439 | case EXCEPTION_NONCONTINUABLE_EXCEPTION: 3440 | strncpy(message, "The thread attempted to continue execution after a noncontinuable exception occurred.", size); 3441 | break; 3442 | default: 3443 | strncpy(message, "Unrecognised system or hardware error.", size); 3444 | break; 3445 | } 3446 | } 3447 | } 3448 | 3449 | #else 3450 | 3451 | if (context == 0) { 3452 | strcpy(message, ""); 3453 | #if defined(LINUX) || defined(AIX) || defined(OSF1) || defined(MACOSX) 3454 | /* v1.4.14 */ 3455 | netx_strerror_r(strerror_r(error_code, message, (size_t) size), message, size, error_code); 3456 | size = (int) strlen(message); 3457 | #else 3458 | netx_get_std_error_message(error_code, message, size, context); 3459 | size = (int) strlen(message); 3460 | #endif 3461 | } 3462 | 3463 | #endif 3464 | 3465 | message[size - 1] = '\0'; 3466 | 3467 | return (int) strlen(message); 3468 | } 3469 | 3470 | 3471 | int netx_get_std_error_message(int error_code, char *message, int size, int context) 3472 | { 3473 | 3474 | strcpy(message, ""); 3475 | 3476 | #if !defined(_WIN32) 3477 | switch (error_code) { 3478 | case E2BIG: 3479 | strncpy(message, "Argument list too long.", size); 3480 | break; 3481 | case EACCES: 3482 | strncpy(message, "Permission denied.", size); 3483 | break; 3484 | case EADDRINUSE: 3485 | strncpy(message, "Address in use.", size); 3486 | break; 3487 | case EADDRNOTAVAIL: 3488 | strncpy(message, "Address not available.", size); 3489 | break; 3490 | case EAFNOSUPPORT: 3491 | strncpy(message, "Address family not supported.", size); 3492 | break; 3493 | case EAGAIN: 3494 | strncpy(message, "Resource unavailable, try again.", size); 3495 | break; 3496 | case EALREADY: 3497 | strncpy(message, "Connection already in progress.", size); 3498 | break; 3499 | case EBADF: 3500 | strncpy(message, "Bad file descriptor.", size); 3501 | break; 3502 | #if !defined(MACOSX) && !defined(FREEBSD) 3503 | case EBADMSG: 3504 | strncpy(message, "Bad message.", size); 3505 | break; 3506 | #endif 3507 | case EBUSY: 3508 | strncpy(message, "Device or resource busy.", size); 3509 | break; 3510 | case ECANCELED: 3511 | strncpy(message, "Operation canceled.", size); 3512 | break; 3513 | case ECHILD: 3514 | strncpy(message, "No child processes.", size); 3515 | break; 3516 | case ECONNABORTED: 3517 | strncpy(message, "Connection aborted.", size); 3518 | break; 3519 | case ECONNREFUSED: 3520 | strncpy(message, "Connection refused.", size); 3521 | break; 3522 | case ECONNRESET: 3523 | strncpy(message, "Connection reset.", size); 3524 | break; 3525 | case EDEADLK: 3526 | strncpy(message, "Resource deadlock would occur.", size); 3527 | break; 3528 | case EDESTADDRREQ: 3529 | strncpy(message, "Destination address required.", size); 3530 | break; 3531 | case EDOM: 3532 | strncpy(message, "Mathematics argument out of domain of function.", size); 3533 | break; 3534 | case EDQUOT: 3535 | strncpy(message, "Reserved.", size); 3536 | break; 3537 | case EEXIST: 3538 | strncpy(message, "File exists.", size); 3539 | break; 3540 | case EFAULT: 3541 | strncpy(message, "Bad address.", size); 3542 | break; 3543 | case EFBIG: 3544 | strncpy(message, "File too large.", size); 3545 | break; 3546 | case EHOSTUNREACH: 3547 | strncpy(message, "Host is unreachable.", size); 3548 | break; 3549 | case EIDRM: 3550 | strncpy(message, "Identifier removed.", size); 3551 | break; 3552 | case EILSEQ: 3553 | strncpy(message, "Illegal byte sequence.", size); 3554 | break; 3555 | case EINPROGRESS: 3556 | strncpy(message, "Operation in progress.", size); 3557 | break; 3558 | case EINTR: 3559 | strncpy(message, "Interrupted function.", size); 3560 | break; 3561 | case EINVAL: 3562 | strncpy(message, "Invalid argument.", size); 3563 | break; 3564 | case EIO: 3565 | strncpy(message, "I/O error.", size); 3566 | break; 3567 | case EISCONN: 3568 | strncpy(message, "Socket is connected.", size); 3569 | break; 3570 | case EISDIR: 3571 | strncpy(message, "Is a directory.", size); 3572 | break; 3573 | case ELOOP: 3574 | strncpy(message, "Too many levels of symbolic links.", size); 3575 | break; 3576 | case EMFILE: 3577 | strncpy(message, "Too many open files.", size); 3578 | break; 3579 | case EMLINK: 3580 | strncpy(message, "Too many links.", size); 3581 | break; 3582 | case EMSGSIZE: 3583 | strncpy(message, "Message too large.", size); 3584 | break; 3585 | #if !defined(MACOSX) && !defined(OSF1) && !defined(FREEBSD) 3586 | case EMULTIHOP: 3587 | strncpy(message, "Reserved.", size); 3588 | break; 3589 | #endif 3590 | case ENAMETOOLONG: 3591 | strncpy(message, "Filename too long.", size); 3592 | break; 3593 | case ENETDOWN: 3594 | strncpy(message, "Network is down.", size); 3595 | break; 3596 | case ENETRESET: 3597 | strncpy(message, "Connection aborted by network.", size); 3598 | break; 3599 | case ENETUNREACH: 3600 | strncpy(message, "Network unreachable.", size); 3601 | break; 3602 | case ENFILE: 3603 | strncpy(message, "Too many files open in system.", size); 3604 | break; 3605 | case ENOBUFS: 3606 | strncpy(message, "No buffer space available.", size); 3607 | break; 3608 | #if !defined(MACOSX) && !defined(FREEBSD) 3609 | case ENODATA: 3610 | strncpy(message, "[XSR] [Option Start] No message is available on the STREAM head read queue. [Option End]", size); 3611 | break; 3612 | #endif 3613 | case ENODEV: 3614 | strncpy(message, "No such device.", size); 3615 | break; 3616 | case ENOENT: 3617 | strncpy(message, "No such file or directory.", size); 3618 | break; 3619 | case ENOEXEC: 3620 | strncpy(message, "Executable file format error.", size); 3621 | break; 3622 | case ENOLCK: 3623 | strncpy(message, "No locks available.", size); 3624 | break; 3625 | #if !defined(MACOSX) && !defined(OSF1) && !defined(FREEBSD) 3626 | case ENOLINK: 3627 | strncpy(message, "Reserved.", size); 3628 | break; 3629 | #endif 3630 | case ENOMEM: 3631 | strncpy(message, "Not enough space.", size); 3632 | break; 3633 | case ENOMSG: 3634 | strncpy(message, "No message of the desired type.", size); 3635 | break; 3636 | case ENOPROTOOPT: 3637 | strncpy(message, "Protocol not available.", size); 3638 | break; 3639 | case ENOSPC: 3640 | strncpy(message, "No space left on device.", size); 3641 | break; 3642 | #if !defined(MACOSX) && !defined(FREEBSD) 3643 | case ENOSR: 3644 | strncpy(message, "[XSR] [Option Start] No STREAM resources. [Option End]", size); 3645 | break; 3646 | #endif 3647 | #if !defined(MACOSX) && !defined(FREEBSD) 3648 | case ENOSTR: 3649 | strncpy(message, "[XSR] [Option Start] Not a STREAM. [Option End]", size); 3650 | break; 3651 | #endif 3652 | case ENOSYS: 3653 | strncpy(message, "Function not supported.", size); 3654 | break; 3655 | case ENOTCONN: 3656 | strncpy(message, "The socket is not connected.", size); 3657 | break; 3658 | case ENOTDIR: 3659 | strncpy(message, "Not a directory.", size); 3660 | break; 3661 | #if !defined(AIX) && !defined(AIX5) 3662 | case ENOTEMPTY: 3663 | strncpy(message, "Directory not empty.", size); 3664 | break; 3665 | #endif 3666 | case ENOTSOCK: 3667 | strncpy(message, "Not a socket.", size); 3668 | break; 3669 | case ENOTSUP: 3670 | strncpy(message, "Not supported.", size); 3671 | break; 3672 | case ENOTTY: 3673 | strncpy(message, "Inappropriate I/O control operation.", size); 3674 | break; 3675 | case ENXIO: 3676 | strncpy(message, "No such device or address.", size); 3677 | break; 3678 | #if !defined(LINUX) && !defined(MACOSX) && !defined(FREEBSD) 3679 | case EOPNOTSUPP: 3680 | strncpy(message, "Operation not supported on socket.", size); 3681 | break; 3682 | #endif 3683 | #if !defined(OSF1) 3684 | case EOVERFLOW: 3685 | strncpy(message, "Value too large to be stored in data type.", size); 3686 | break; 3687 | #endif 3688 | case EPERM: 3689 | strncpy(message, "Operation not permitted.", size); 3690 | break; 3691 | case EPIPE: 3692 | strncpy(message, "Broken pipe.", size); 3693 | break; 3694 | #if !defined(MACOSX) && !defined(FREEBSD) 3695 | case EPROTO: 3696 | strncpy(message, "Protocol error.", size); 3697 | break; 3698 | #endif 3699 | case EPROTONOSUPPORT: 3700 | strncpy(message, "Protocol not supported.", size); 3701 | break; 3702 | case EPROTOTYPE: 3703 | strncpy(message, "Protocol wrong type for socket.", size); 3704 | break; 3705 | case ERANGE: 3706 | strncpy(message, "Result too large.", size); 3707 | break; 3708 | case EROFS: 3709 | strncpy(message, "Read-only file system.", size); 3710 | break; 3711 | case ESPIPE: 3712 | strncpy(message, "Invalid seek.", size); 3713 | break; 3714 | case ESRCH: 3715 | strncpy(message, "No such process.", size); 3716 | break; 3717 | case ESTALE: 3718 | strncpy(message, "Reserved.", size); 3719 | break; 3720 | #if !defined(MACOSX) && !defined(FREEBSD) 3721 | case ETIME: 3722 | strncpy(message, "[XSR] [Option Start] Stream ioctl() timeout. [Option End]", size); 3723 | break; 3724 | #endif 3725 | case ETIMEDOUT: 3726 | strncpy(message, "Connection timed out.", size); 3727 | break; 3728 | case ETXTBSY: 3729 | strncpy(message, "Text file busy.", size); 3730 | break; 3731 | #if !defined(LINUX) && !defined(AIX) && !defined(AIX5) && !defined(MACOSX) && !defined(OSF1) && !defined(SOLARIS) && !defined(FREEBSD) 3732 | case EWOULDBLOCK: 3733 | strncpy(message, "Operation would block.", size); 3734 | break; 3735 | #endif 3736 | case EXDEV: 3737 | strncpy(message, "Cross-device link.", size); 3738 | break; 3739 | default: 3740 | strcpy(message, ""); 3741 | break; 3742 | } 3743 | #endif 3744 | 3745 | return (int) strlen(message); 3746 | } 3747 | 3748 | 3749 | int netx_enter_critical_section(void *p_crit) 3750 | { 3751 | int result; 3752 | 3753 | #if defined(_WIN32) 3754 | EnterCriticalSection((LPCRITICAL_SECTION) p_crit); 3755 | result = 0; 3756 | #else 3757 | result = pthread_mutex_lock((pthread_mutex_t *) p_crit); 3758 | #endif 3759 | return result; 3760 | } 3761 | 3762 | 3763 | int netx_leave_critical_section(void *p_crit) 3764 | { 3765 | int result; 3766 | 3767 | #if defined(_WIN32) 3768 | LeaveCriticalSection((LPCRITICAL_SECTION) p_crit); 3769 | result = 0; 3770 | #else 3771 | result = pthread_mutex_unlock((pthread_mutex_t *) p_crit); 3772 | #endif 3773 | return result; 3774 | } -------------------------------------------------------------------------------- /src/tcp-netx.node: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisemunt/tcp-netx/c96b93637f22dad6fe83da6b84090ab009ebe5eb/src/tcp-netx.node --------------------------------------------------------------------------------