├── .gitmodules ├── README.md ├── nodejs ├── LICENSE ├── Makefile ├── README.md ├── dist │ ├── binding.gyp │ └── package.json ├── examples │ ├── client.js │ ├── echo.js │ ├── eventsource.js │ ├── http.js │ ├── http_demo.js │ ├── http_sillybenchmark.js │ ├── koa.js │ ├── paths.js │ ├── ssl.js │ └── test.js ├── make.bat ├── src │ ├── addon.cpp │ ├── addon.h │ ├── extension.cpp │ ├── http.h │ └── uws.js └── tests │ └── autobahn.js └── python ├── .gitignore ├── Bindings.cpp ├── Jenkinsfile ├── MANIFEST.in ├── Makefile ├── README.md ├── Vagrantfile ├── build-all-wheels.bat ├── build-all-wheels.sh ├── docker ├── devel │ ├── Dockerfile │ ├── README.md │ ├── docker-common.sh │ └── sources.list ├── docker-common.sh ├── manylinux │ ├── Dockerfile │ ├── README.md │ ├── docker-common.sh │ ├── ld-patch.sh │ └── link-options └── test │ ├── Dockerfile │ └── docker-common.sh ├── manylinux.map ├── setup.py ├── tests └── test_client.py └── windows └── windoze.md /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "uWebSockets"] 2 | path = uWebSockets 3 | url = https://github.com/uWebSockets/uWebSockets.git 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Various bindings for µWebSockets 2 | * Node.js binding lives here, report issues with µWS itself over at uWebSockets repo. Report issues with the Node.js binding here. 3 | * Python binding is third-party and currently client only (@szmoore). 4 | * Create new bindings and get them merged here. 5 | -------------------------------------------------------------------------------- /nodejs/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Alex Hultman and contributors 2 | 3 | This software is provided 'as-is', without any express or implied 4 | warranty. In no event will the authors be held liable for any damages 5 | arising from the use of this software. 6 | 7 | Permission is granted to anyone to use this software for any purpose, 8 | including commercial applications, and to alter it and redistribute it 9 | freely, subject to the following restrictions: 10 | 11 | 1. The origin of this software must not be misrepresented; you must not 12 | claim that you wrote the original software. If you use this software 13 | in a product, an acknowledgement in the product documentation would be 14 | appreciated but is not required. 15 | 2. Altered source versions must be plainly marked as such, and must not be 16 | misrepresented as being the original software. 17 | 3. This notice may not be removed or altered from any source distribution. 18 | -------------------------------------------------------------------------------- /nodejs/Makefile: -------------------------------------------------------------------------------- 1 | CPP_SHARED := -DUSE_LIBUV -std=c++11 -O3 -I ../uWebSockets/src -shared -fPIC ../uWebSockets/src/Extensions.cpp ../uWebSockets/src/Group.cpp ../uWebSockets/src/Networking.cpp ../uWebSockets/src/Hub.cpp ../uWebSockets/src/Node.cpp ../uWebSockets/src/WebSocket.cpp ../uWebSockets/src/HTTPSocket.cpp ../uWebSockets/src/Socket.cpp ../uWebSockets/src/Epoll.cpp src/addon.cpp 2 | CPP_OSX := -stdlib=libc++ -mmacosx-version-min=10.7 -undefined dynamic_lookup 3 | 4 | default: 5 | make targets 6 | NODE=targets/node-v8.1.2 ABI=57 make `(uname -s)` 7 | NODE=targets/node-v9.2.0 ABI=59 make `(uname -s)` 8 | NODE=targets/node-v10.0.0 ABI=64 make `(uname -s)` 9 | cp README.md dist/README.md 10 | cp ../uWebSockets/LICENSE dist/LICENSE 11 | cp -r ../uWebSockets/src dist/ 12 | cp src/addon.cpp dist/src/addon.cpp 13 | cp src/addon.h dist/src/addon.h 14 | cp src/http.h dist/src/http.h 15 | cp src/uws.js dist/uws.js 16 | for f in dist/*.node; do chmod +x $$f; done 17 | targets: 18 | mkdir targets 19 | curl https://nodejs.org/dist/v8.1.2/node-v8.1.2-headers.tar.gz | tar xz -C targets 20 | curl https://nodejs.org/dist/v9.2.0/node-v9.2.0-headers.tar.gz | tar xz -C targets 21 | curl https://nodejs.org/dist/v10.0.0/node-v10.0.0-headers.tar.gz | tar xz -C targets 22 | Linux: 23 | g++ $(CPP_SHARED) -static-libstdc++ -static-libgcc -I $$NODE/include/node -s -o dist/uws_linux_$$ABI.node 24 | Darwin: 25 | g++ $(CPP_SHARED) $(CPP_OSX) -I $$NODE/include/node -o dist/uws_darwin_$$ABI.node 26 | .PHONY: clean 27 | clean: 28 | rm -f dist/README.md 29 | rm -f dist/LICENSE 30 | rm -f dist/uws_*.node 31 | rm -f dist/uws.js 32 | rm -rf dist/src 33 | rm -rf targets 34 | -------------------------------------------------------------------------------- /nodejs/README.md: -------------------------------------------------------------------------------- 1 | # UWS IS *NOT* AN ELECTRON MODULE 2 | `uws` is a replacement module for `ws` which allows, but doesn't guarantee (certainly not when paired with Socket.IO), significant performance and memory-usage improvements. This module is specifically *only* compatible with Node.js and is installed *only* like so: 3 | 4 | `npm install uws` 5 | 6 | * uws *can* use node-gyp and *can* recompile itself at installation but does *not* require so. 7 | * npm installation never fails, but `require('uws')` will throw if all of the below points hold true: 8 | * There was no C++11 compiler available at installation. 9 | * Your system is not an official **Tier 1** Node.js platform. 10 | 11 | ## Keep in mind 12 | You can't fix a clogged up system by only fixing part of the problem. Swapping to uws can have *dramatical* effects if your entire pipeline works well. Socket.IO, SocketCluster and other such mass bloat will **not** give you desired results as those projects already, from the start, **are** the bottleneck. 13 | 14 | [Read more about other horrible Node.js projects here](https://github.com/alexhultman/The-Node.js-performance-palette) 15 | 16 | ## Usage 17 | `uws` tries to mimic `ws` as closely as possible without sacrificing too much performance. In most cases you simply swap `require('ws')` with `require('uws')`: 18 | 19 | ```javascript 20 | var WebSocketServer = require('uws').Server; 21 | var wss = new WebSocketServer({ port: 3000 }); 22 | 23 | function onMessage(message) { 24 | console.log('received: ' + message); 25 | } 26 | 27 | wss.on('connection', function(ws) { 28 | ws.on('message', onMessage); 29 | ws.send('something'); 30 | }); 31 | ``` 32 | 33 | ##### Deviations from ws 34 | There are some important incompatibilities with `ws` though, we aim to be ~90% compatible but will never implement behavior that is deemed too inefficient: 35 | 36 | * Binary data is passed zero-copy as an `ArrayBuffer`. This means you need to copy it to keep it past the callback. It also means you need to convert it with `Buffer.from(message)` if you expect a `Node.js Buffer`. 37 | * `webSocket._socket` is not a `net.Socket`, it is just a getter function with very basic functionalities. 38 | * `webSocket._socket.remote...` might fail, you need to cache it at connection. 39 | * `webSocket` acts like an `EventEmitter` with one listener per event maximum. 40 | * `webSocket.upgradeReq` is only valid during execution of the connection handler. If you want to keep properties of the upgradeReq for the entire lifetime of the webSocket you better attach that specific property to the webSocket at connection. 41 | -------------------------------------------------------------------------------- /nodejs/dist/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | 'targets': [ 3 | { 4 | 'target_name': 'uws', 5 | 'sources': [ 6 | 'src/Extensions.cpp', 7 | 'src/Group.cpp', 8 | 'src/Networking.cpp', 9 | 'src/Hub.cpp', 10 | 'src/Node.cpp', 11 | 'src/WebSocket.cpp', 12 | 'src/HTTPSocket.cpp', 13 | 'src/Socket.cpp', 14 | 'src/addon.cpp' 15 | ], 16 | 'conditions': [ 17 | ['OS=="linux"', { 18 | 'cflags_cc': [ '-std=c++11', '-DUSE_LIBUV' ], 19 | 'cflags_cc!': [ '-fno-exceptions', '-std=gnu++0x', '-fno-rtti' ], 20 | 'cflags!': [ '-fno-omit-frame-pointer' ], 21 | 'ldflags!': [ '-rdynamic' ], 22 | 'ldflags': [ '-s' ] 23 | }], 24 | ['OS=="mac"', { 25 | 'xcode_settings': { 26 | 'MACOSX_DEPLOYMENT_TARGET': '10.7', 27 | 'CLANG_CXX_LANGUAGE_STANDARD': 'c++11', 28 | 'CLANG_CXX_LIBRARY': 'libc++', 29 | 'GCC_GENERATE_DEBUGGING_SYMBOLS': 'NO', 30 | 'GCC_ENABLE_CPP_EXCEPTIONS': 'YES', 31 | 'GCC_THREADSAFE_STATICS': 'YES', 32 | 'GCC_OPTIMIZATION_LEVEL': '3', 33 | 'GCC_ENABLE_CPP_RTTI': 'YES', 34 | 'OTHER_CFLAGS!': [ '-fno-strict-aliasing' ], 35 | 'OTHER_CPLUSPLUSFLAGS': [ '-DUSE_LIBUV' ] 36 | } 37 | }], 38 | ['OS=="win"', { 39 | 'cflags_cc': [ '/DUSE_LIBUV' ], 40 | 'cflags_cc!': [] 41 | }] 42 | ] 43 | }, 44 | { 45 | 'target_name': 'action_after_build', 46 | 'type': 'none', 47 | 'dependencies': [ 'uws' ], 48 | 'conditions': [ 49 | ['OS!="win"', { 50 | 'actions': [ 51 | { 52 | 'action_name': 'move_lib', 53 | 'inputs': [ 54 | '<@(PRODUCT_DIR)/uws.node' 55 | ], 56 | 'outputs': [ 57 | 'uws' 58 | ], 59 | 'action': ['cp', '<@(PRODUCT_DIR)/uws.node', 'uws_ build_log.txt 2>&1 || exit 0" 6 | }, 7 | "main": "uws.js", 8 | "description": "Tiny WebSockets", 9 | "engines": { 10 | "node": ">=4" 11 | }, 12 | "keywords": [ 13 | "tiny", 14 | "websockets" 15 | ], 16 | "homepage": "https://github.com/uNetworking/uWebSockets", 17 | "license": "Zlib", 18 | "author": "Alex Hultman (https://github.com/alexhultman)", 19 | "repository": { 20 | "type": "git", 21 | "url": "https://github.com/uNetworking/uWebSockets.git" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /nodejs/examples/client.js: -------------------------------------------------------------------------------- 1 | var WebSocket = require('../dist/uws'); 2 | var ws = new WebSocket('ws://echo.websocket.org'); 3 | 4 | ws.on('open', function open() { 5 | console.log('Connected!'); 6 | ws.send('This will be sent!'); 7 | }); 8 | 9 | ws.on('error', function error() { 10 | console.log('Error connecting!'); 11 | }); 12 | 13 | ws.on('message', function(data, flags) { 14 | console.log('Message: ' + data); 15 | }); 16 | 17 | ws.on('close', function(code, message) { 18 | console.log('Disconnection: ' + code + ', ' + message); 19 | }); 20 | -------------------------------------------------------------------------------- /nodejs/examples/echo.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const WebSocketServer = require('../dist/uws').Server; 4 | const wss = new WebSocketServer({ port: 3000 }); 5 | 6 | function onMessage(message) { 7 | this.send(message); 8 | } 9 | 10 | wss.on('connection', function(ws) { 11 | // warning: never attach anonymous functions to the socket! 12 | // that will majorly harm scalability since the scope of this 13 | // context will be taken hostage and never released causing major 14 | // memory usage increases compared to having the function created 15 | // outside of this context (1.2 GB vs 781 MB for 1 million connections) 16 | ws.on('message', onMessage); 17 | }); 18 | 19 | wss.on('error', function(error) { 20 | console.log('Cannot start server'); 21 | }); 22 | -------------------------------------------------------------------------------- /nodejs/examples/eventsource.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const uws = require('../dist/uws'); 4 | 5 | // the page that will connect back over EventSource 6 | const document = ''; 7 | 8 | const server = uws.http.createServer((req, res) => { 9 | if (req.url === '/') { 10 | res.end(document); 11 | } else if (req.url === '/eventSource') { 12 | // write the event-stream HTTP head so that we can send chunks back later 13 | res.writeHead(200, {'Content-Type': 'text/event-stream'}); 14 | 15 | // start a timer that will send back events over this HTTP socket 16 | var interval = setInterval(() => { 17 | // important to not end the socket, but write instead! 18 | res.write('data: Some message from server here!\n\n'); 19 | }, 1000); 20 | 21 | // if the client disconnects we stop the timer 22 | res.on('close', () => { 23 | clearInterval(interval); 24 | }); 25 | } else { 26 | // todo: terminate 27 | console.log('Unsupported url: ' + req.url); 28 | res.end('Nope, nope!'); 29 | } 30 | }); 31 | 32 | server.listen(3000); 33 | -------------------------------------------------------------------------------- /nodejs/examples/http.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const uws = require('../dist/uws'); 4 | 5 | const document = Buffer.from('Hello world!'); 6 | 7 | const server = uws.http.createServer((req, res) => { 8 | // handle some POST data 9 | if (req.method === 'POST') { 10 | var postString = ''; 11 | req.on('data', (arrayBuffer) => { 12 | postString += Buffer.from(arrayBuffer).toString(); 13 | }).on('end', () => { 14 | res.end('You posted me this: ' + postString); 15 | }); 16 | // handle some GET url 17 | } else if (req.url === '/') { 18 | res.end(document); 19 | } else { 20 | res.end('Unknown request by: ' + req.headers['user-agent']); 21 | } 22 | }); 23 | 24 | const wss = new uws.Server({server: server}); 25 | 26 | wss.on('connection', (ws) => { 27 | ws.send('Welcome to the 10s!'); 28 | }); 29 | 30 | server.listen(3000); 31 | -------------------------------------------------------------------------------- /nodejs/examples/http_demo.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const uws = require('../dist/uws'); 4 | const document = Buffer.from('Hello world!'); 5 | 6 | const server = uws.http.createServer((req, res) => { 7 | // handle some POST data 8 | if (req.method === 'POST') { 9 | var body = []; 10 | req.on('data', (chunk) => { 11 | body.push(Buffer.from(chunk)); 12 | }).on('end', () => { 13 | res.end('You posted me this: ' + Buffer.concat(body).toString()); 14 | }); 15 | // handle some GET url 16 | } else if (req.url === '/') { 17 | res.end(document); 18 | } else { 19 | res.end('Unknown request by: ' + req.headers['user-agent']); 20 | } 21 | }); 22 | 23 | server.listen(3000); 24 | -------------------------------------------------------------------------------- /nodejs/examples/http_sillybenchmark.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const uws = require('../dist/uws'); 4 | const document = Buffer.from('Hello world!'); 5 | 6 | const server = uws.http.createServer((req, res) => { 7 | res.end(document); 8 | }); 9 | 10 | server.listen(3000); 11 | -------------------------------------------------------------------------------- /nodejs/examples/koa.js: -------------------------------------------------------------------------------- 1 | var koa = require('koa'); 2 | var app = koa(); 3 | var uhttp = require('../dist/uws').http; 4 | 5 | app.use(function *() { 6 | this.body = 'Hello World'; 7 | }); 8 | 9 | if (process.env.UWS_HTTP) { 10 | uhttp.createServer(app.callback()).listen(3000); 11 | } else { 12 | app.listen(3000); 13 | } 14 | -------------------------------------------------------------------------------- /nodejs/examples/paths.js: -------------------------------------------------------------------------------- 1 | // example showing usage with different behavior on a path basis 2 | 3 | const http = require('http'); 4 | const WebSocketServer = require('../dist/uws').Server; 5 | 6 | const httpServer = http.createServer((request, response) => { 7 | response.end(); 8 | }); 9 | 10 | // echo server on path /echo, echoes the verbose message 11 | const wssEcho = new WebSocketServer({ path: 'echo', server: httpServer }); 12 | wssEcho.on('connection', function connection(ws) { 13 | ws.on('message', function incoming(message) { 14 | ws.send(message, { binary: Buffer.isBuffer(message) }); 15 | }); 16 | }); 17 | 18 | // scream echo server on path /scream, echoes the uppercase message 19 | const wssScream = new WebSocketServer({ path: 'scream', server: httpServer }); 20 | wssScream.on('connection', function connection(ws) { 21 | ws.on('message', function incoming(message) { 22 | ws.send(message.toUpperCase(), { binary: Buffer.isBuffer(message) }); 23 | }); 24 | }); 25 | 26 | httpServer.listen(3000); 27 | -------------------------------------------------------------------------------- /nodejs/examples/ssl.js: -------------------------------------------------------------------------------- 1 | const https = require('https'); 2 | const fs = require('fs'); 3 | const wsServer = require('../dist/uws').Server; 4 | 5 | const options = { 6 | key: fs.readFileSync('/home/alexhultman/µWebSockets.key.pem'), 7 | cert: fs.readFileSync('/home/alexhultman/µWebSockets.pem') 8 | }; 9 | 10 | const httpsServer = https.createServer(options, (req, res) => { 11 | req.socket.write('Hello there'); 12 | req.socket.end(); 13 | }); 14 | 15 | const wss = new wsServer({ server: httpsServer, path: '/' }); 16 | 17 | wss.on('connection', (ws) => { 18 | ws.on('message', (message) => { 19 | ws.send(message, { binary: Buffer.isBuffer(message) }); 20 | }); 21 | }); 22 | 23 | httpsServer.listen(3000); 24 | -------------------------------------------------------------------------------- /nodejs/examples/test.js: -------------------------------------------------------------------------------- 1 | var WebSocket = require('../dist/uws'); 2 | var ws = new WebSocket('ws://echo.websocket.org'); 3 | 4 | ws.on('open', function open() { 5 | console.log('Connected!'); 6 | ws.send('This will be sent!'); 7 | }); 8 | 9 | ws.on('error', function error() { 10 | console.log('Connection error'); 11 | }); 12 | 13 | ws.on('message', function(data, flags) { 14 | console.log('Message: ' + data); 15 | }); 16 | 17 | ws.on('close', function(code, message) { 18 | console.log('Disconnection: ' + code + ', ' + message); 19 | }); 20 | -------------------------------------------------------------------------------- /nodejs/make.bat: -------------------------------------------------------------------------------- 1 | call "%VS140COMNTOOLS%..\..\vc\vcvarsall.bat" amd64 2 | 3 | if not exist targets ( 4 | mkdir targets 5 | curl https://nodejs.org/dist/v6.4.0/node-v6.4.0-headers.tar.gz | tar xz -C targets 6 | curl https://nodejs.org/dist/v6.4.0/win-x64/node.lib > targets/node-v6.4.0/node.lib 7 | curl https://nodejs.org/dist/v7.1.0/node-v7.1.0-headers.tar.gz | tar xz -C targets 8 | curl https://nodejs.org/dist/v7.1.0/win-x64/node.lib > targets/node-v7.1.0/node.lib 9 | curl https://nodejs.org/dist/v8.1.2/node-v8.1.2-headers.tar.gz | tar xz -C targets 10 | curl https://nodejs.org/dist/v8.1.2/win-x64/node.lib > targets/node-v8.1.2/node.lib 11 | curl https://nodejs.org/dist/v9.2.0/node-v9.2.0-headers.tar.gz | tar xz -C targets 12 | curl https://nodejs.org/dist/v9.2.0/win-x64/node.lib > targets/node-v9.2.0/node.lib 13 | ) 14 | 15 | cp README.md dist/README.md 16 | cp ../uWebSockets/LICENSE dist/LICENSE 17 | cp -r ../uWebSockets/src dist/ 18 | cp src/addon.cpp dist/src/addon.cpp 19 | cp src/addon.h dist/src/addon.h 20 | cp src/http.h dist/src/http.h 21 | cp src/uws.js dist/uws.js 22 | 23 | cl /I targets/node-v6.4.0/include/node /EHsc /Ox /LD /Fedist/uws_win32_48.node dist/src/*.cpp targets/node-v6.4.0/node.lib 24 | cl /I targets/node-v7.1.0/include/node /EHsc /Ox /LD /Fedist/uws_win32_51.node dist/src/*.cpp targets/node-v7.1.0/node.lib 25 | cl /I targets/node-v8.1.2/include/node /EHsc /Ox /LD /Fedist/uws_win32_57.node dist/src/*.cpp targets/node-v8.1.2/node.lib 26 | cl /I targets/node-v9.2.0/include/node /EHsc /Ox /LD /Fedist/uws_win32_59.node dist/src/*.cpp targets/node-v9.2.0/node.lib 27 | 28 | rm *.obj 29 | rm dist/*.exp 30 | rm dist/*.lib 31 | -------------------------------------------------------------------------------- /nodejs/src/addon.cpp: -------------------------------------------------------------------------------- 1 | #include "../src/uWS.h" 2 | #include "addon.h" 3 | #include "http.h" 4 | 5 | void Main(Local exports) { 6 | Isolate *isolate = exports->GetIsolate(); 7 | 8 | exports->Set(String::NewFromUtf8(isolate, "server"), Namespace(isolate).object); 9 | exports->Set(String::NewFromUtf8(isolate, "client"), Namespace(isolate).object); 10 | exports->Set(String::NewFromUtf8(isolate, "httpServer"), HttpServer::getHttpServer(isolate)); 11 | 12 | NODE_SET_METHOD(exports, "setUserData", setUserData); 13 | NODE_SET_METHOD(exports, "getUserData", getUserData); 14 | NODE_SET_METHOD(exports, "clearUserData", clearUserData); 15 | NODE_SET_METHOD(exports, "getAddress", getAddress); 16 | 17 | NODE_SET_METHOD(exports, "transfer", transfer); 18 | NODE_SET_METHOD(exports, "upgrade", upgrade); 19 | NODE_SET_METHOD(exports, "connect", connect); 20 | NODE_SET_METHOD(exports, "setNoop", setNoop); 21 | registerCheck(isolate); 22 | } 23 | 24 | NODE_MODULE(uws, Main) 25 | -------------------------------------------------------------------------------- /nodejs/src/addon.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | using namespace v8; 10 | 11 | uWS::Hub hub(0, true); 12 | uv_check_t check; 13 | Persistent noop; 14 | 15 | void registerCheck(Isolate *isolate) { 16 | uv_check_init((uv_loop_t *) hub.getLoop(), &check); 17 | check.data = isolate; 18 | uv_check_start(&check, [](uv_check_t *check) { 19 | Isolate *isolate = (Isolate *) check->data; 20 | HandleScope hs(isolate); 21 | node::MakeCallback(isolate, isolate->GetCurrentContext()->Global(), Local::New(isolate, noop), 0, nullptr); 22 | }); 23 | uv_unref((uv_handle_t *) &check); 24 | } 25 | 26 | class NativeString { 27 | char *data; 28 | size_t length; 29 | char utf8ValueMemory[sizeof(String::Utf8Value)]; 30 | String::Utf8Value *utf8Value = nullptr; 31 | public: 32 | NativeString(const Local &value) { 33 | if (value->IsUndefined()) { 34 | data = nullptr; 35 | length = 0; 36 | } else if (value->IsString()) { 37 | utf8Value = new (utf8ValueMemory) String::Utf8Value(value); 38 | data = (**utf8Value); 39 | length = utf8Value->length(); 40 | } else if (node::Buffer::HasInstance(value)) { 41 | data = node::Buffer::Data(value); 42 | length = node::Buffer::Length(value); 43 | } else if (value->IsTypedArray()) { 44 | Local arrayBufferView = Local::Cast(value); 45 | ArrayBuffer::Contents contents = arrayBufferView->Buffer()->GetContents(); 46 | length = contents.ByteLength(); 47 | data = (char *) contents.Data(); 48 | } else if (value->IsArrayBuffer()) { 49 | Local arrayBuffer = Local::Cast(value); 50 | ArrayBuffer::Contents contents = arrayBuffer->GetContents(); 51 | length = contents.ByteLength(); 52 | data = (char *) contents.Data(); 53 | } else { 54 | static char empty[] = ""; 55 | data = empty; 56 | length = 0; 57 | } 58 | } 59 | 60 | char *getData() {return data;} 61 | size_t getLength() {return length;} 62 | ~NativeString() { 63 | if (utf8Value) { 64 | utf8Value->~Utf8Value(); 65 | } 66 | } 67 | }; 68 | 69 | struct GroupData { 70 | Persistent connectionHandler, messageHandler, 71 | disconnectionHandler, pingHandler, 72 | pongHandler, errorHandler, httpRequestHandler, 73 | httpUpgradeHandler, httpCancelledRequestCallback; 74 | int size = 0; 75 | }; 76 | 77 | template 78 | void createGroup(const FunctionCallbackInfo &args) { 79 | uWS::Group *group = hub.createGroup(args[0]->IntegerValue(), args[1]->IntegerValue()); 80 | group->setUserData(new GroupData); 81 | args.GetReturnValue().Set(External::New(args.GetIsolate(), group)); 82 | } 83 | 84 | template 85 | void deleteGroup(const FunctionCallbackInfo &args) { 86 | uWS::Group *group = (uWS::Group *) args[0].As()->Value(); 87 | delete (GroupData *) group->getUserData(); 88 | delete group; 89 | } 90 | 91 | template 92 | inline Local wrapSocket(uWS::WebSocket *webSocket, Isolate *isolate) { 93 | return External::New(isolate, webSocket); 94 | } 95 | 96 | template 97 | inline uWS::WebSocket *unwrapSocket(Local external) { 98 | return (uWS::WebSocket *) external->Value(); 99 | } 100 | 101 | inline Local wrapMessage(const char *message, size_t length, uWS::OpCode opCode, Isolate *isolate) { 102 | return opCode == uWS::OpCode::BINARY ? (Local) ArrayBuffer::New(isolate, (char *) message, length) : (Local) String::NewFromUtf8(isolate, message, String::kNormalString, length); 103 | } 104 | 105 | template 106 | inline Local getDataV8(uWS::WebSocket *webSocket, Isolate *isolate) { 107 | return webSocket->getUserData() ? Local::New(isolate, *(Persistent *) webSocket->getUserData()) : Local::Cast(Undefined(isolate)); 108 | } 109 | 110 | template 111 | void getUserData(const FunctionCallbackInfo &args) { 112 | args.GetReturnValue().Set(getDataV8(unwrapSocket(args[0].As()), args.GetIsolate())); 113 | } 114 | 115 | template 116 | void clearUserData(const FunctionCallbackInfo &args) { 117 | uWS::WebSocket *webSocket = unwrapSocket(args[0].As()); 118 | ((Persistent *) webSocket->getUserData())->Reset(); 119 | delete (Persistent *) webSocket->getUserData(); 120 | } 121 | 122 | template 123 | void setUserData(const FunctionCallbackInfo &args) { 124 | uWS::WebSocket *webSocket = unwrapSocket(args[0].As()); 125 | if (webSocket->getUserData()) { 126 | ((Persistent *) webSocket->getUserData())->Reset(args.GetIsolate(), args[1]); 127 | } else { 128 | webSocket->setUserData(new Persistent(args.GetIsolate(), args[1])); 129 | } 130 | } 131 | 132 | template 133 | void getAddress(const FunctionCallbackInfo &args) 134 | { 135 | typename uWS::WebSocket::Address address = unwrapSocket(args[0].As())->getAddress(); 136 | Local array = Array::New(args.GetIsolate(), 3); 137 | array->Set(0, Integer::New(args.GetIsolate(), address.port)); 138 | array->Set(1, String::NewFromUtf8(args.GetIsolate(), address.address)); 139 | array->Set(2, String::NewFromUtf8(args.GetIsolate(), address.family)); 140 | args.GetReturnValue().Set(array); 141 | } 142 | 143 | uv_handle_t *getTcpHandle(void *handleWrap) { 144 | volatile char *memory = (volatile char *) handleWrap; 145 | for (volatile uv_handle_t *tcpHandle = (volatile uv_handle_t *) memory; tcpHandle->type != UV_TCP 146 | || tcpHandle->data != handleWrap || tcpHandle->loop != uv_default_loop(); tcpHandle = (volatile uv_handle_t *) memory) { 147 | memory++; 148 | } 149 | return (uv_handle_t *) memory; 150 | } 151 | 152 | struct SendCallbackData { 153 | Persistent jsCallback; 154 | Isolate *isolate; 155 | }; 156 | 157 | template 158 | void sendCallback(uWS::WebSocket *webSocket, void *data, bool cancelled, void *reserved) 159 | { 160 | SendCallbackData *sc = (SendCallbackData *) data; 161 | if (!cancelled) { 162 | HandleScope hs(sc->isolate); 163 | node::MakeCallback(sc->isolate, sc->isolate->GetCurrentContext()->Global(), Local::New(sc->isolate, sc->jsCallback), 0, nullptr); 164 | } 165 | sc->jsCallback.Reset(); 166 | delete sc; 167 | } 168 | 169 | template 170 | void send(const FunctionCallbackInfo &args) 171 | { 172 | uWS::OpCode opCode = (uWS::OpCode) args[2]->IntegerValue(); 173 | NativeString nativeString(args[1]); 174 | 175 | SendCallbackData *sc = nullptr; 176 | void (*callback)(uWS::WebSocket *, void *, bool, void *) = nullptr; 177 | 178 | if (args[3]->IsFunction()) { 179 | callback = sendCallback; 180 | sc = new SendCallbackData; 181 | sc->jsCallback.Reset(args.GetIsolate(), Local::Cast(args[3])); 182 | sc->isolate = args.GetIsolate(); 183 | } 184 | 185 | bool compress = args[4]->BooleanValue(); 186 | 187 | unwrapSocket(args[0].As())->send(nativeString.getData(), 188 | nativeString.getLength(), opCode, callback, sc, compress); 189 | } 190 | 191 | void connect(const FunctionCallbackInfo &args) { 192 | uWS::Group *clientGroup = (uWS::Group *) args[0].As()->Value(); 193 | NativeString uri(args[1]); 194 | hub.connect(std::string(uri.getData(), uri.getLength()), new Persistent(args.GetIsolate(), args[2]), {}, 5000, clientGroup); 195 | } 196 | 197 | struct Ticket { 198 | uv_os_sock_t fd; 199 | SSL *ssl; 200 | }; 201 | 202 | void upgrade(const FunctionCallbackInfo &args) { 203 | uWS::Group *serverGroup = (uWS::Group *) args[0].As()->Value(); 204 | Ticket *ticket = (Ticket *) args[1].As()->Value(); 205 | NativeString secKey(args[2]); 206 | NativeString extensions(args[3]); 207 | NativeString subprotocol(args[4]); 208 | 209 | // todo: move this check into core! 210 | if (ticket->fd != INVALID_SOCKET) { 211 | hub.upgrade(ticket->fd, secKey.getData(), ticket->ssl, extensions.getData(), extensions.getLength(), subprotocol.getData(), subprotocol.getLength(), serverGroup); 212 | } else { 213 | if (ticket->ssl) { 214 | SSL_free(ticket->ssl); 215 | } 216 | } 217 | delete ticket; 218 | } 219 | 220 | void transfer(const FunctionCallbackInfo &args) { 221 | // (_handle.fd OR _handle), SSL 222 | uv_handle_t *handle = nullptr; 223 | Ticket *ticket = new Ticket; 224 | if (args[0]->IsObject()) { 225 | uv_fileno((handle = getTcpHandle(args[0]->ToObject()->GetAlignedPointerFromInternalField(0))), (uv_os_fd_t *) &ticket->fd); 226 | } else { 227 | ticket->fd = args[0]->IntegerValue(); 228 | } 229 | 230 | ticket->fd = dup(ticket->fd); 231 | ticket->ssl = nullptr; 232 | if (args[1]->IsExternal()) { 233 | ticket->ssl = (SSL *) args[1].As()->Value(); 234 | SSL_up_ref(ticket->ssl); 235 | } 236 | 237 | // uv_close calls shutdown if not set on Windows 238 | if (handle) { 239 | // UV_HANDLE_SHARED_TCP_SOCKET 240 | handle->flags |= 0x40000000; 241 | } 242 | 243 | args.GetReturnValue().Set(External::New(args.GetIsolate(), ticket)); 244 | } 245 | 246 | template 247 | void onConnection(const FunctionCallbackInfo &args) { 248 | uWS::Group *group = (uWS::Group *) args[0].As()->Value(); 249 | GroupData *groupData = (GroupData *) group->getUserData(); 250 | 251 | Isolate *isolate = args.GetIsolate(); 252 | Persistent *connectionCallback = &groupData->connectionHandler; 253 | connectionCallback->Reset(isolate, Local::Cast(args[1])); 254 | group->onConnection([isolate, connectionCallback, groupData](uWS::WebSocket *webSocket, uWS::HttpRequest req) { 255 | groupData->size++; 256 | HandleScope hs(isolate); 257 | Local argv[] = {wrapSocket(webSocket, isolate)}; 258 | node::MakeCallback(isolate, isolate->GetCurrentContext()->Global(), Local::New(isolate, *connectionCallback), 1, argv); 259 | }); 260 | } 261 | 262 | template 263 | void onMessage(const FunctionCallbackInfo &args) { 264 | uWS::Group *group = (uWS::Group *) args[0].As()->Value(); 265 | GroupData *groupData = (GroupData *) group->getUserData(); 266 | 267 | Isolate *isolate = args.GetIsolate(); 268 | Persistent *messageCallback = &groupData->messageHandler; 269 | messageCallback->Reset(isolate, Local::Cast(args[1])); 270 | group->onMessage([isolate, messageCallback](uWS::WebSocket *webSocket, const char *message, size_t length, uWS::OpCode opCode) { 271 | HandleScope hs(isolate); 272 | Local argv[] = {wrapMessage(message, length, opCode, isolate), 273 | getDataV8(webSocket, isolate)}; 274 | Local::New(isolate, *messageCallback)->Call(isolate->GetCurrentContext()->Global(), 2, argv); 275 | }); 276 | } 277 | 278 | template 279 | void onPing(const FunctionCallbackInfo &args) { 280 | uWS::Group *group = (uWS::Group *) args[0].As()->Value(); 281 | GroupData *groupData = (GroupData *) group->getUserData(); 282 | 283 | Isolate *isolate = args.GetIsolate(); 284 | Persistent *pingCallback = &groupData->pingHandler; 285 | pingCallback->Reset(isolate, Local::Cast(args[1])); 286 | group->onPing([isolate, pingCallback](uWS::WebSocket *webSocket, const char *message, size_t length) { 287 | HandleScope hs(isolate); 288 | Local argv[] = {wrapMessage(message, length, uWS::OpCode::PING, isolate), 289 | getDataV8(webSocket, isolate)}; 290 | node::MakeCallback(isolate, isolate->GetCurrentContext()->Global(), Local::New(isolate, *pingCallback), 2, argv); 291 | }); 292 | } 293 | 294 | template 295 | void onPong(const FunctionCallbackInfo &args) { 296 | uWS::Group *group = (uWS::Group *) args[0].As()->Value(); 297 | GroupData *groupData = (GroupData *) group->getUserData(); 298 | 299 | Isolate *isolate = args.GetIsolate(); 300 | Persistent *pongCallback = &groupData->pongHandler; 301 | pongCallback->Reset(isolate, Local::Cast(args[1])); 302 | group->onPong([isolate, pongCallback](uWS::WebSocket *webSocket, const char *message, size_t length) { 303 | HandleScope hs(isolate); 304 | Local argv[] = {wrapMessage(message, length, uWS::OpCode::PONG, isolate), 305 | getDataV8(webSocket, isolate)}; 306 | node::MakeCallback(isolate, isolate->GetCurrentContext()->Global(), Local::New(isolate, *pongCallback), 2, argv); 307 | }); 308 | } 309 | 310 | template 311 | void onDisconnection(const FunctionCallbackInfo &args) { 312 | uWS::Group *group = (uWS::Group *) args[0].As()->Value(); 313 | GroupData *groupData = (GroupData *) group->getUserData(); 314 | 315 | Isolate *isolate = args.GetIsolate(); 316 | Persistent *disconnectionCallback = &groupData->disconnectionHandler; 317 | disconnectionCallback->Reset(isolate, Local::Cast(args[1])); 318 | 319 | group->onDisconnection([isolate, disconnectionCallback, groupData](uWS::WebSocket *webSocket, int code, char *message, size_t length) { 320 | groupData->size--; 321 | HandleScope hs(isolate); 322 | Local argv[] = {wrapSocket(webSocket, isolate), 323 | Integer::New(isolate, code), 324 | wrapMessage(message, length, uWS::OpCode::CLOSE, isolate), 325 | getDataV8(webSocket, isolate)}; 326 | node::MakeCallback(isolate, isolate->GetCurrentContext()->Global(), Local::New(isolate, *disconnectionCallback), 4, argv); 327 | }); 328 | } 329 | 330 | void onError(const FunctionCallbackInfo &args) { 331 | uWS::Group *group = (uWS::Group *) args[0].As()->Value(); 332 | GroupData *groupData = (GroupData *) group->getUserData(); 333 | 334 | Isolate *isolate = args.GetIsolate(); 335 | Persistent *errorCallback = &groupData->errorHandler; 336 | errorCallback->Reset(isolate, Local::Cast(args[1])); 337 | 338 | group->onError([isolate, errorCallback](void *user) { 339 | HandleScope hs(isolate); 340 | Local argv[] = {Local::New(isolate, *(Persistent *) user)}; 341 | node::MakeCallback(isolate, isolate->GetCurrentContext()->Global(), Local::New(isolate, *errorCallback), 1, argv); 342 | 343 | ((Persistent *) user)->Reset(); 344 | delete (Persistent *) user; 345 | }); 346 | } 347 | 348 | template 349 | void closeSocket(const FunctionCallbackInfo &args) { 350 | NativeString nativeString(args[2]); 351 | unwrapSocket(args[0].As())->close(args[1]->IntegerValue(), nativeString.getData(), nativeString.getLength()); 352 | } 353 | 354 | template 355 | void terminateSocket(const FunctionCallbackInfo &args) { 356 | unwrapSocket(args[0].As())->terminate(); 357 | } 358 | 359 | template 360 | void closeGroup(const FunctionCallbackInfo &args) { 361 | NativeString nativeString(args[2]); 362 | uWS::Group *group = (uWS::Group *) args[0].As()->Value(); 363 | group->close(args[1]->IntegerValue(), nativeString.getData(), nativeString.getLength()); 364 | } 365 | 366 | template 367 | void terminateGroup(const FunctionCallbackInfo &args) { 368 | ((uWS::Group *) args[0].As()->Value())->terminate(); 369 | } 370 | 371 | template 372 | void broadcast(const FunctionCallbackInfo &args) { 373 | uWS::Group *group = (uWS::Group *) args[0].As()->Value(); 374 | uWS::OpCode opCode = args[2]->BooleanValue() ? uWS::OpCode::BINARY : uWS::OpCode::TEXT; 375 | NativeString nativeString(args[1]); 376 | group->broadcast(nativeString.getData(), nativeString.getLength(), opCode); 377 | } 378 | 379 | template 380 | void prepareMessage(const FunctionCallbackInfo &args) { 381 | uWS::OpCode opCode = (uWS::OpCode) args[1]->IntegerValue(); 382 | NativeString nativeString(args[0]); 383 | args.GetReturnValue().Set(External::New(args.GetIsolate(), uWS::WebSocket::prepareMessage(nativeString.getData(), nativeString.getLength(), opCode, false))); 384 | } 385 | 386 | template 387 | void sendPrepared(const FunctionCallbackInfo &args) { 388 | unwrapSocket(args[0].As()) 389 | ->sendPrepared((typename uWS::WebSocket::PreparedMessage *) args[1].As()->Value()); 390 | } 391 | 392 | template 393 | void finalizeMessage(const FunctionCallbackInfo &args) { 394 | uWS::WebSocket::finalizeMessage((typename uWS::WebSocket::PreparedMessage *) args[0].As()->Value()); 395 | } 396 | 397 | void forEach(const FunctionCallbackInfo &args) { 398 | Isolate *isolate = args.GetIsolate(); 399 | uWS::Group *group = (uWS::Group *) args[0].As()->Value(); 400 | Local cb = Local::Cast(args[1]); 401 | group->forEach([isolate, &cb](uWS::WebSocket *webSocket) { 402 | Local argv[] = { 403 | getDataV8(webSocket, isolate) 404 | }; 405 | cb->Call(Null(isolate), 1, argv); 406 | }); 407 | } 408 | 409 | void getSize(const FunctionCallbackInfo &args) { 410 | uWS::Group *group = (uWS::Group *) args[0].As()->Value(); 411 | GroupData *groupData = (GroupData *) group->getUserData(); 412 | args.GetReturnValue().Set(Integer::New(args.GetIsolate(), groupData->size)); 413 | } 414 | 415 | void startAutoPing(const FunctionCallbackInfo &args) { 416 | uWS::Group *group = (uWS::Group *) args[0].As()->Value(); 417 | NativeString nativeString(args[2]); 418 | group->startAutoPing(args[1]->IntegerValue(), std::string(nativeString.getData(), nativeString.getLength())); 419 | } 420 | 421 | void setNoop(const FunctionCallbackInfo &args) { 422 | noop.Reset(args.GetIsolate(), Local::Cast(args[0])); 423 | } 424 | 425 | void listen(const FunctionCallbackInfo &args) { 426 | uWS::Group *group = (uWS::Group *) args[0].As()->Value(); 427 | hub.listen(args[1]->IntegerValue(), nullptr, 0, group); 428 | } 429 | 430 | template 431 | struct Namespace { 432 | Local object; 433 | Namespace (Isolate *isolate) { 434 | object = Object::New(isolate); 435 | NODE_SET_METHOD(object, "send", send); 436 | NODE_SET_METHOD(object, "close", closeSocket); 437 | NODE_SET_METHOD(object, "terminate", terminateSocket); 438 | NODE_SET_METHOD(object, "prepareMessage", prepareMessage); 439 | NODE_SET_METHOD(object, "sendPrepared", sendPrepared); 440 | NODE_SET_METHOD(object, "finalizeMessage", finalizeMessage); 441 | 442 | Local group = Object::New(isolate); 443 | NODE_SET_METHOD(group, "onConnection", onConnection); 444 | NODE_SET_METHOD(group, "onMessage", onMessage); 445 | NODE_SET_METHOD(group, "onDisconnection", onDisconnection); 446 | 447 | if (!isServer) { 448 | NODE_SET_METHOD(group, "onError", onError); 449 | } else { 450 | NODE_SET_METHOD(group, "forEach", forEach); 451 | NODE_SET_METHOD(group, "getSize", getSize); 452 | NODE_SET_METHOD(group, "startAutoPing", startAutoPing); 453 | NODE_SET_METHOD(group, "listen", listen); 454 | } 455 | 456 | NODE_SET_METHOD(group, "onPing", onPing); 457 | NODE_SET_METHOD(group, "onPong", onPong); 458 | NODE_SET_METHOD(group, "create", createGroup); 459 | NODE_SET_METHOD(group, "delete", deleteGroup); 460 | NODE_SET_METHOD(group, "close", closeGroup); 461 | NODE_SET_METHOD(group, "terminate", terminateGroup); 462 | NODE_SET_METHOD(group, "broadcast", broadcast); 463 | 464 | object->Set(String::NewFromUtf8(isolate, "group"), group); 465 | } 466 | }; 467 | -------------------------------------------------------------------------------- /nodejs/src/extension.cpp: -------------------------------------------------------------------------------- 1 | #include "uWS.h" 2 | #include "addon.h" 3 | #include "../env.h" 4 | #include "../env-inl.h" 5 | 6 | namespace node { 7 | 8 | void Main(Local exports, Local unused, Local context) { 9 | Environment* env = Environment::GetCurrent(context); 10 | Isolate *isolate = exports->GetIsolate(); 11 | 12 | exports->Set(String::NewFromUtf8(isolate, "server"), Namespace(isolate).object); 13 | exports->Set(String::NewFromUtf8(isolate, "client"), Namespace(isolate).object); 14 | 15 | env->SetMethod(exports, "setUserData", setUserData); 16 | env->SetMethod(exports, "getUserData", getUserData); 17 | env->SetMethod(exports, "clearUserData", clearUserData); 18 | env->SetMethod(exports, "getAddress", getAddress); 19 | 20 | env->SetMethod(exports, "transfer", transfer); 21 | env->SetMethod(exports, "upgrade", upgrade); 22 | env->SetMethod(exports, "connect", connect); 23 | env->SetMethod(exports, "setNoop", setNoop); 24 | registerCheck(isolate); 25 | } 26 | 27 | } 28 | 29 | NODE_MODULE_CONTEXT_AWARE_BUILTIN(uws_builtin, node::Main) 30 | -------------------------------------------------------------------------------- /nodejs/src/http.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | Persistent reqTemplate, resTemplate; 4 | Persistent httpPersistent; 5 | 6 | uWS::HttpRequest *currentReq = nullptr; 7 | 8 | struct HttpServer { 9 | 10 | struct Request { 11 | static void on(const FunctionCallbackInfo &args) { 12 | NativeString eventName(args[0]); 13 | if (std::string(eventName.getData(), eventName.getLength()) == "data") { 14 | args.Holder()->SetInternalField(1, args[1]); 15 | } else if (std::string(eventName.getData(), eventName.getLength()) == "end") { 16 | args.Holder()->SetInternalField(2, args[1]); 17 | } else { 18 | std::cout << "Warning: req.on(" << std::string(eventName.getData(), eventName.getLength()) << ") is not implemented!" << std::endl; 19 | } 20 | args.GetReturnValue().Set(args.Holder()); 21 | } 22 | 23 | static void headers(Local property, const PropertyCallbackInfo &args) { 24 | uWS::HttpRequest *req = currentReq; 25 | if (!req) { 26 | std::cerr << "Warning: req.headers usage past request handler is not supported!" << std::endl; 27 | } else { 28 | NativeString nativeString(property); 29 | uWS::Header header = req->getHeader(nativeString.getData(), nativeString.getLength()); 30 | if (header) { 31 | args.GetReturnValue().Set(String::NewFromOneByte(args.GetIsolate(), (uint8_t *) header.value, NewStringType::kNormal, header.valueLength).ToLocalChecked()); 32 | } 33 | } 34 | } 35 | 36 | static void url(Local property, const PropertyCallbackInfo &args) { 37 | args.GetReturnValue().Set(args.This()->GetInternalField(4)); 38 | } 39 | 40 | static void method(Local property, const PropertyCallbackInfo &args) { 41 | //std::cout << "method" << std::endl; 42 | long methodId = ((long) args.This()->GetAlignedPointerFromInternalField(3)) >> 1; 43 | switch (methodId) { 44 | case uWS::HttpMethod::METHOD_GET: 45 | args.GetReturnValue().Set(String::NewFromOneByte(args.GetIsolate(), (uint8_t *) "GET", NewStringType::kNormal, 3).ToLocalChecked()); 46 | break; 47 | case uWS::HttpMethod::METHOD_PUT: 48 | args.GetReturnValue().Set(String::NewFromOneByte(args.GetIsolate(), (uint8_t *) "PUT", NewStringType::kNormal, 3).ToLocalChecked()); 49 | break; 50 | case uWS::HttpMethod::METHOD_POST: 51 | args.GetReturnValue().Set(String::NewFromOneByte(args.GetIsolate(), (uint8_t *) "POST", NewStringType::kNormal, 4).ToLocalChecked()); 52 | break; 53 | case uWS::HttpMethod::METHOD_HEAD: 54 | args.GetReturnValue().Set(String::NewFromOneByte(args.GetIsolate(), (uint8_t *) "HEAD", NewStringType::kNormal, 4).ToLocalChecked()); 55 | break; 56 | case uWS::HttpMethod::METHOD_PATCH: 57 | args.GetReturnValue().Set(String::NewFromOneByte(args.GetIsolate(), (uint8_t *) "PATCH", NewStringType::kNormal, 5).ToLocalChecked()); 58 | break; 59 | case uWS::HttpMethod::METHOD_TRACE: 60 | args.GetReturnValue().Set(String::NewFromOneByte(args.GetIsolate(), (uint8_t *) "TRACE", NewStringType::kNormal, 5).ToLocalChecked()); 61 | break; 62 | case uWS::HttpMethod::METHOD_DELETE: 63 | args.GetReturnValue().Set(String::NewFromOneByte(args.GetIsolate(), (uint8_t *) "DELETE", NewStringType::kNormal, 6).ToLocalChecked()); 64 | break; 65 | case uWS::HttpMethod::METHOD_OPTIONS: 66 | args.GetReturnValue().Set(String::NewFromOneByte(args.GetIsolate(), (uint8_t *) "OPTIONS", NewStringType::kNormal, 7).ToLocalChecked()); 67 | break; 68 | case uWS::HttpMethod::METHOD_CONNECT: 69 | args.GetReturnValue().Set(String::NewFromOneByte(args.GetIsolate(), (uint8_t *) "CONNECT", NewStringType::kNormal, 7).ToLocalChecked()); 70 | break; 71 | } 72 | } 73 | 74 | // placeholders 75 | static void unpipe(const FunctionCallbackInfo &args) { 76 | //std::cout << "req.unpipe called" << std::endl; 77 | } 78 | 79 | static void resume(const FunctionCallbackInfo &args) { 80 | //std::cout << "req.resume called" << std::endl; 81 | } 82 | 83 | static void socket(const FunctionCallbackInfo &args) { 84 | // return new empty object 85 | args.GetReturnValue().Set(Object::New(args.GetIsolate())); 86 | } 87 | 88 | static Local getTemplateObject(Isolate *isolate) { 89 | Local reqTemplateLocal = FunctionTemplate::New(isolate); 90 | reqTemplateLocal->SetClassName(String::NewFromUtf8(isolate, "uws.Request")); 91 | reqTemplateLocal->InstanceTemplate()->SetInternalFieldCount(5); 92 | reqTemplateLocal->PrototypeTemplate()->SetAccessor(String::NewFromUtf8(isolate, "url"), Request::url); 93 | reqTemplateLocal->PrototypeTemplate()->SetAccessor(String::NewFromUtf8(isolate, "method"), Request::method); 94 | reqTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "on"), FunctionTemplate::New(isolate, Request::on)); 95 | reqTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "unpipe"), FunctionTemplate::New(isolate, Request::unpipe)); 96 | reqTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "resume"), FunctionTemplate::New(isolate, Request::resume)); 97 | reqTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "socket"), FunctionTemplate::New(isolate, Request::socket)); 98 | 99 | Local reqObjectLocal = reqTemplateLocal->GetFunction()->NewInstance(isolate->GetCurrentContext()).ToLocalChecked(); 100 | 101 | Local headersTemplate = ObjectTemplate::New(isolate); 102 | headersTemplate->SetNamedPropertyHandler(Request::headers); 103 | 104 | reqObjectLocal->Set(String::NewFromUtf8(isolate, "headers"), headersTemplate->NewInstance()); 105 | return reqObjectLocal; 106 | } 107 | }; 108 | 109 | struct Response { 110 | static void on(const FunctionCallbackInfo &args) { 111 | NativeString eventName(args[0]); 112 | if (std::string(eventName.getData(), eventName.getLength()) == "close") { 113 | args.Holder()->SetInternalField(1, args[1]); 114 | } else { 115 | std::cout << "Warning: res.on(" << std::string(eventName.getData(), eventName.getLength()) << ") is not implemented!" << std::endl; 116 | } 117 | args.GetReturnValue().Set(args.Holder()); 118 | } 119 | 120 | static void end(const FunctionCallbackInfo &args) { 121 | uWS::HttpResponse *res = (uWS::HttpResponse *) args.Holder()->GetAlignedPointerFromInternalField(0); 122 | if (res) { 123 | NativeString nativeString(args[0]); 124 | 125 | ((Persistent *) &res->userData)->Reset(); 126 | ((Persistent *) &res->userData)->~Persistent(); 127 | ((Persistent *) &res->extraUserData)->Reset(); 128 | ((Persistent *) &res->extraUserData)->~Persistent(); 129 | res->end(nativeString.getData(), nativeString.getLength()); 130 | } 131 | } 132 | 133 | // todo: this is slow 134 | static void writeHead(const FunctionCallbackInfo &args) { 135 | uWS::HttpResponse *res = (uWS::HttpResponse *) args.Holder()->GetAlignedPointerFromInternalField(0); 136 | if (res) { 137 | std::string head = "HTTP/1.1 " + std::to_string(args[0]->IntegerValue()) + " "; 138 | 139 | if (args.Length() > 1 && args[1]->IsString()) { 140 | NativeString statusMessage(args[1]); 141 | head.append(statusMessage.getData(), statusMessage.getLength()); 142 | } else { 143 | head += "OK"; 144 | } 145 | 146 | if (args[args.Length() - 1]->IsObject()) { 147 | Local headersObject = args[args.Length() - 1]->ToObject(); 148 | Local headers = headersObject->GetOwnPropertyNames(); 149 | for (int i = 0; i < headers->Length(); i++) { 150 | Local key = headers->Get(i); 151 | Local value = headersObject->Get(key); 152 | 153 | NativeString nativeKey(key); 154 | NativeString nativeValue(value); 155 | 156 | head += "\r\n"; 157 | head.append(nativeKey.getData(), nativeKey.getLength()); 158 | head += ": "; 159 | head.append(nativeValue.getData(), nativeValue.getLength()); 160 | } 161 | } 162 | 163 | head += "\r\n\r\n"; 164 | res->write(head.data(), head.length()); 165 | } 166 | } 167 | 168 | // todo: if not writeHead called before then should write implicit headers 169 | static void write(const FunctionCallbackInfo &args) { 170 | uWS::HttpResponse *res = (uWS::HttpResponse *) args.Holder()->GetAlignedPointerFromInternalField(0); 171 | 172 | if (res) { 173 | NativeString nativeString(args[0]); 174 | res->write(nativeString.getData(), nativeString.getLength()); 175 | } 176 | } 177 | 178 | static void setHeader(const FunctionCallbackInfo &args) { 179 | //std::cout << "res.setHeader called" << std::endl; 180 | } 181 | 182 | static void getHeader(const FunctionCallbackInfo &args) { 183 | //std::cout << "res.getHeader called" << std::endl; 184 | } 185 | 186 | static Local getTemplateObject(Isolate *isolate) { 187 | Local resTemplateLocal = FunctionTemplate::New(isolate); 188 | resTemplateLocal->SetClassName(String::NewFromUtf8(isolate, "uws.Response")); 189 | resTemplateLocal->InstanceTemplate()->SetInternalFieldCount(5); 190 | resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "end"), FunctionTemplate::New(isolate, Response::end)); 191 | resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "writeHead"), FunctionTemplate::New(isolate, Response::writeHead)); 192 | resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "write"), FunctionTemplate::New(isolate, Response::write)); 193 | resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "on"), FunctionTemplate::New(isolate, Response::on)); 194 | resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "setHeader"), FunctionTemplate::New(isolate, Response::setHeader)); 195 | resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "getHeader"), FunctionTemplate::New(isolate, Response::getHeader)); 196 | return resTemplateLocal->GetFunction()->NewInstance(isolate->GetCurrentContext()).ToLocalChecked(); 197 | } 198 | }; 199 | 200 | // todo: wrap everything up - most important function to get correct 201 | static void createServer(const FunctionCallbackInfo &args) { 202 | 203 | // todo: delete this on destructor 204 | uWS::Group *group = hub.createGroup(); 205 | group->setUserData(new GroupData); 206 | GroupData *groupData = (GroupData *) group->getUserData(); 207 | 208 | Isolate *isolate = args.GetIsolate(); 209 | Persistent *httpRequestCallback = &groupData->httpRequestHandler; 210 | httpRequestCallback->Reset(isolate, Local::Cast(args[0])); 211 | group->onHttpRequest([isolate, httpRequestCallback](uWS::HttpResponse *res, uWS::HttpRequest req, char *data, size_t length, size_t remainingBytes) { 212 | HandleScope hs(isolate); 213 | 214 | currentReq = &req; 215 | 216 | Local reqObject = Local::New(isolate, reqTemplate)->Clone(); 217 | reqObject->SetAlignedPointerInInternalField(0, &req); 218 | new (&res->extraUserData) Persistent(isolate, reqObject); 219 | 220 | Local resObject = Local::New(isolate, resTemplate)->Clone(); 221 | resObject->SetAlignedPointerInInternalField(0, res); 222 | new (&res->userData) Persistent(isolate, resObject); 223 | 224 | // store url & method (needed by Koa and Express) 225 | long methodId = req.getMethod() << 1; 226 | reqObject->SetAlignedPointerInInternalField(3, (void *) methodId); 227 | reqObject->SetInternalField(4, String::NewFromOneByte(isolate, (uint8_t *) req.getUrl().value, NewStringType::kNormal, req.getUrl().valueLength).ToLocalChecked()); 228 | 229 | Local argv[] = {reqObject, resObject}; 230 | Local::New(isolate, *httpRequestCallback)->Call(isolate->GetCurrentContext()->Global(), 2, argv); 231 | 232 | if (length) { 233 | Local dataCallback = reqObject->GetInternalField(1); 234 | if (!dataCallback->IsUndefined()) { 235 | Local argv[] = {ArrayBuffer::New(isolate, data, length)}; 236 | Local::Cast(dataCallback)->Call(isolate->GetCurrentContext()->Global(), 1, argv); 237 | } 238 | 239 | if (!remainingBytes) { 240 | Local endCallback = reqObject->GetInternalField(2); 241 | if (!endCallback->IsUndefined()) { 242 | Local::Cast(endCallback)->Call(isolate->GetCurrentContext()->Global(), 0, nullptr); 243 | } 244 | } 245 | } 246 | 247 | currentReq = nullptr; 248 | reqObject->SetAlignedPointerInInternalField(0, nullptr); 249 | }); 250 | 251 | group->onCancelledHttpRequest([isolate](uWS::HttpResponse *res) { 252 | HandleScope hs(isolate); 253 | 254 | // mark res as invalid 255 | Local resObject = Local::New(isolate, *(Persistent *) &res->userData); 256 | resObject->SetAlignedPointerInInternalField(0, nullptr); 257 | 258 | // mark req as invalid 259 | Local reqObject = Local::New(isolate, *(Persistent *) &res->extraUserData); 260 | reqObject->SetAlignedPointerInInternalField(0, nullptr); 261 | 262 | // emit res 'close' on aborted response 263 | Local closeCallback = resObject->GetInternalField(1); 264 | if (!closeCallback->IsUndefined()) { 265 | Local::Cast(closeCallback)->Call(isolate->GetCurrentContext()->Global(), 0, nullptr); 266 | } 267 | 268 | ((Persistent *) &res->userData)->Reset(); 269 | ((Persistent *) &res->userData)->~Persistent(); 270 | ((Persistent *) &res->extraUserData)->Reset(); 271 | ((Persistent *) &res->extraUserData)->~Persistent(); 272 | }); 273 | 274 | group->onHttpData([isolate](uWS::HttpResponse *res, char *data, size_t length, size_t remainingBytes) { 275 | Local reqObject = Local::New(isolate, *(Persistent *) res->extraUserData); 276 | 277 | Local dataCallback = reqObject->GetInternalField(1); 278 | if (!dataCallback->IsUndefined()) { 279 | Local argv[] = {ArrayBuffer::New(isolate, data, length)}; 280 | Local::Cast(dataCallback)->Call(isolate->GetCurrentContext()->Global(), 1, argv); 281 | } 282 | 283 | if (!remainingBytes) { 284 | Local endCallback = reqObject->GetInternalField(2); 285 | if (!endCallback->IsUndefined()) { 286 | Local::Cast(endCallback)->Call(isolate->GetCurrentContext()->Global(), 0, nullptr); 287 | } 288 | } 289 | }); 290 | 291 | Local newInstance; 292 | if (!args.IsConstructCall()) { 293 | args.GetReturnValue().Set(newInstance = Local::New(args.GetIsolate(), httpPersistent)->NewInstance(isolate->GetCurrentContext()).ToLocalChecked()); 294 | } else { 295 | args.GetReturnValue().Set(newInstance = args.This()); 296 | } 297 | 298 | newInstance->SetAlignedPointerInInternalField(0, group); 299 | } 300 | 301 | static void on(const FunctionCallbackInfo &args) { 302 | NativeString eventName(args[0]); 303 | std::cout << "Warning: server.on(" << std::string(eventName.getData(), eventName.getLength()) << ") is not implemented!" << std::endl; 304 | } 305 | 306 | static void listen(const FunctionCallbackInfo &args) { 307 | uWS::Group *group = (uWS::Group *) args.Holder()->GetAlignedPointerFromInternalField(0); 308 | std::cout << "listen: " << hub.listen(args[0]->IntegerValue(), nullptr, 0, group) << std::endl; 309 | 310 | if (args[args.Length() - 1]->IsFunction()) { 311 | Local::Cast(args[args.Length() - 1])->Call(args.GetIsolate()->GetCurrentContext()->Global(), 0, nullptr); 312 | } 313 | } 314 | 315 | // var app = getExpressApp(express) 316 | static void getExpressApp(const FunctionCallbackInfo &args) { 317 | Isolate *isolate = args.GetIsolate(); 318 | if (args[0]->IsFunction()) { 319 | Local express = Local::Cast(args[0]); 320 | Local context = args.GetIsolate()->GetCurrentContext(); 321 | express->Get(String::NewFromUtf8(isolate, "request"))->ToObject()->SetPrototype(context, Local::New(args.GetIsolate(), reqTemplate)->GetPrototype()); 322 | express->Get(String::NewFromUtf8(isolate, "response"))->ToObject()->SetPrototype(context, Local::New(args.GetIsolate(), resTemplate)->GetPrototype()); 323 | 324 | // also change app.listen? 325 | 326 | // change prototypes back? 327 | 328 | args.GetReturnValue().Set(express->NewInstance(context).ToLocalChecked()); 329 | } 330 | } 331 | 332 | static void getResponsePrototype(const FunctionCallbackInfo &args) { 333 | args.GetReturnValue().Set(Local::New(args.GetIsolate(), resTemplate)->GetPrototype()); 334 | } 335 | 336 | static void getRequestPrototype(const FunctionCallbackInfo &args) { 337 | args.GetReturnValue().Set(Local::New(args.GetIsolate(), reqTemplate)->GetPrototype()); 338 | } 339 | 340 | static Local getHttpServer(Isolate *isolate) { 341 | Local httpServer = FunctionTemplate::New(isolate, HttpServer::createServer); 342 | httpServer->InstanceTemplate()->SetInternalFieldCount(1); 343 | 344 | httpServer->Set(String::NewFromUtf8(isolate, "createServer"), FunctionTemplate::New(isolate, HttpServer::createServer)); 345 | httpServer->Set(String::NewFromUtf8(isolate, "getExpressApp"), FunctionTemplate::New(isolate, HttpServer::getExpressApp)); 346 | httpServer->Set(String::NewFromUtf8(isolate, "getResponsePrototype"), FunctionTemplate::New(isolate, HttpServer::getResponsePrototype)); 347 | httpServer->Set(String::NewFromUtf8(isolate, "getRequestPrototype"), FunctionTemplate::New(isolate, HttpServer::getRequestPrototype)); 348 | httpServer->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "listen"), FunctionTemplate::New(isolate, HttpServer::listen)); 349 | httpServer->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "on"), FunctionTemplate::New(isolate, HttpServer::on)); 350 | 351 | reqTemplate.Reset(isolate, Request::getTemplateObject(isolate)); 352 | resTemplate.Reset(isolate, Response::getTemplateObject(isolate)); 353 | 354 | Local httpServerLocal = httpServer->GetFunction(); 355 | httpPersistent.Reset(isolate, httpServerLocal); 356 | return httpServerLocal; 357 | } 358 | }; 359 | -------------------------------------------------------------------------------- /nodejs/src/uws.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const http = require('http'); 4 | const EventEmitter = require('events'); 5 | const EE_ERROR = 'Registering more than one listener to a WebSocket is not supported.'; 6 | const DEFAULT_PAYLOAD_LIMIT = 16777216; 7 | 8 | let _upgradeReq = null; 9 | 10 | function noop() {} 11 | 12 | function abortConnection(socket, code, name) { 13 | socket.end('HTTP/1.1 ' + code + ' ' + name + '\r\n\r\n'); 14 | } 15 | 16 | function emitConnection(ws) { 17 | this.emit('connection', ws, _upgradeReq); 18 | } 19 | 20 | function onServerMessage(message, webSocket) { 21 | webSocket.internalOnMessage(message); 22 | } 23 | 24 | const native = (() => { 25 | try { 26 | try { 27 | return process.binding('uws_builtin'); 28 | } catch (e) { 29 | return require(`./uws_${process.platform}_${process.versions.modules}`); 30 | } 31 | } catch (e) { 32 | const version = process.version.substring(1).split('.').map(function(n) { 33 | return parseInt(n); 34 | }); 35 | const lessThanSixFour = version[0] < 6 || (version[0] === 6 && version[1] < 4); 36 | 37 | if (process.platform === 'win32' && lessThanSixFour) { 38 | throw new Error('µWebSockets requires Node.js 6.4.0 or greater on Windows.'); 39 | } else { 40 | throw new Error('Compilation of µWebSockets has failed and there is no pre-compiled binary ' + 41 | 'available for your system. Please install a supported C++11 compiler and reinstall the module \'uws\'.'); 42 | } 43 | } 44 | })(); 45 | 46 | native.setNoop(noop); 47 | 48 | const clientGroup = native.client.group.create(0, DEFAULT_PAYLOAD_LIMIT); 49 | 50 | native.client.group.onConnection(clientGroup, (external) => { 51 | const webSocket = native.getUserData(external); 52 | webSocket.external = external; 53 | webSocket.internalOnOpen(); 54 | }); 55 | 56 | native.client.group.onMessage(clientGroup, (message, webSocket) => { 57 | webSocket.internalOnMessage(message); 58 | }); 59 | 60 | native.client.group.onDisconnection(clientGroup, (external, code, message, webSocket) => { 61 | webSocket.external = null; 62 | 63 | process.nextTick(() => { 64 | webSocket.internalOnClose(code, message); 65 | }); 66 | 67 | native.clearUserData(external); 68 | }); 69 | 70 | native.client.group.onPing(clientGroup, (message, webSocket) => { 71 | webSocket.onping(message); 72 | }); 73 | 74 | native.client.group.onPong(clientGroup, (message, webSocket) => { 75 | webSocket.onpong(message); 76 | }); 77 | 78 | native.client.group.onError(clientGroup, (webSocket) => { 79 | process.nextTick(() => { 80 | webSocket.internalOnError({ 81 | message: 'uWs client connection error', 82 | stack: 'uWs client connection error' 83 | }); 84 | }); 85 | }); 86 | 87 | class WebSocket { 88 | constructor(external) { 89 | this.external = external; 90 | this.internalOnMessage = noop; 91 | this.internalOnClose = noop; 92 | this.onping = noop; 93 | this.onpong = noop; 94 | } 95 | 96 | get upgradeReq() { 97 | return _upgradeReq; 98 | } 99 | 100 | set onmessage(f) { 101 | if (f) { 102 | this.internalOnMessage = (message) => { 103 | f({data: message}); 104 | }; 105 | } else { 106 | this.internalOnMessage = noop; 107 | } 108 | } 109 | 110 | set onopen(f) { 111 | if (f) { 112 | this.internalOnOpen = f; 113 | } else { 114 | this.internalOnOpen = noop; 115 | } 116 | } 117 | 118 | set onclose(f) { 119 | if (f) { 120 | this.internalOnClose = (code, message) => { 121 | f({code: code, reason: message}); 122 | }; 123 | } else { 124 | this.internalOnClose = noop; 125 | } 126 | } 127 | 128 | set onerror(f) { 129 | if (f && this instanceof WebSocketClient) { 130 | this.internalOnError = f; 131 | } else { 132 | this.internalOnError = noop; 133 | } 134 | } 135 | 136 | emit(eventName, arg1, arg2) { 137 | if (eventName === 'message') { 138 | this.internalOnMessage(arg1); 139 | } else if (eventName === 'close') { 140 | this.internalOnClose(arg1, arg2); 141 | } else if (eventName === 'ping') { 142 | this.onping(arg1); 143 | } else if (eventName === 'pong') { 144 | this.onpong(arg1); 145 | } 146 | return this; 147 | } 148 | 149 | on(eventName, f) { 150 | if (eventName === 'message') { 151 | if (this.internalOnMessage !== noop) { 152 | throw Error(EE_ERROR); 153 | } 154 | this.internalOnMessage = f; 155 | } else if (eventName === 'close') { 156 | if (this.internalOnClose !== noop) { 157 | throw Error(EE_ERROR); 158 | } 159 | this.internalOnClose = f; 160 | } else if (eventName === 'ping') { 161 | if (this.onping !== noop) { 162 | throw Error(EE_ERROR); 163 | } 164 | this.onping = f; 165 | } else if (eventName === 'pong') { 166 | if (this.onpong !== noop) { 167 | throw Error(EE_ERROR); 168 | } 169 | this.onpong = f; 170 | } else if (eventName === 'open') { 171 | if (this.internalOnOpen !== noop) { 172 | throw Error(EE_ERROR); 173 | } 174 | this.internalOnOpen = f; 175 | } else if (eventName === 'error' && this instanceof WebSocketClient) { 176 | if (this.internalOnError !== noop) { 177 | throw Error(EE_ERROR); 178 | } 179 | this.internalOnError = f; 180 | } 181 | return this; 182 | } 183 | 184 | once(eventName, f) { 185 | if (eventName === 'message') { 186 | if (this.internalOnMessage !== noop) { 187 | throw Error(EE_ERROR); 188 | } 189 | this.internalOnMessage = (message) => { 190 | this.internalOnMessage = noop; 191 | f(message); 192 | }; 193 | } else if (eventName === 'close') { 194 | if (this.internalOnClose !== noop) { 195 | throw Error(EE_ERROR); 196 | } 197 | this.internalOnClose = (code, message) => { 198 | this.internalOnClose = noop; 199 | f(code, message); 200 | }; 201 | } else if (eventName === 'ping') { 202 | if (this.onping !== noop) { 203 | throw Error(EE_ERROR); 204 | } 205 | this.onping = () => { 206 | this.onping = noop; 207 | f(); 208 | }; 209 | } else if (eventName === 'pong') { 210 | if (this.onpong !== noop) { 211 | throw Error(EE_ERROR); 212 | } 213 | this.onpong = () => { 214 | this.onpong = noop; 215 | f(); 216 | }; 217 | } 218 | return this; 219 | } 220 | 221 | removeAllListeners(eventName) { 222 | if (!eventName || eventName === 'message') { 223 | this.internalOnMessage = noop; 224 | } 225 | if (!eventName || eventName === 'close') { 226 | this.internalOnClose = noop; 227 | } 228 | if (!eventName || eventName === 'ping') { 229 | this.onping = noop; 230 | } 231 | if (!eventName || eventName === 'pong') { 232 | this.onpong = noop; 233 | } 234 | return this; 235 | } 236 | 237 | removeListener(eventName, cb) { 238 | if (eventName === 'message' && this.internalOnMessage === cb) { 239 | this.internalOnMessage = noop; 240 | } else if (eventName === 'close' && this.internalOnClose === cb) { 241 | this.internalOnClose = noop; 242 | } else if (eventName === 'ping' && this.onping === cb) { 243 | this.onping = noop; 244 | } else if (eventName === 'pong' && this.onpong === cb) { 245 | this.onpong = noop; 246 | } 247 | return this; 248 | } 249 | 250 | get OPEN() { 251 | return WebSocketClient.OPEN; 252 | } 253 | 254 | get CLOSED() { 255 | return WebSocketClient.CLOSED; 256 | } 257 | 258 | get readyState() { 259 | return this.external ? WebSocketClient.OPEN : WebSocketClient.CLOSED; 260 | } 261 | 262 | get _socket() { 263 | const address = this.external ? native.getAddress(this.external) : new Array(3); 264 | return { 265 | remotePort: address[0], 266 | remoteAddress: address[1], 267 | remoteFamily: address[2] 268 | }; 269 | } 270 | 271 | // from here down, functions are not common between client and server 272 | 273 | ping(message, options, dontFailWhenClosed) { 274 | if (this.external) { 275 | native.server.send(this.external, message, WebSocketClient.OPCODE_PING, false); 276 | } 277 | } 278 | 279 | terminate() { 280 | if (this.external) { 281 | native.server.terminate(this.external); 282 | this.external = null; 283 | } 284 | } 285 | 286 | send(message, options, cb, compress) { 287 | if (this.external) { 288 | if (typeof options === 'function') { 289 | cb = options; 290 | options = null; 291 | } 292 | 293 | const binary = options && typeof options.binary === 'boolean' ? options.binary : typeof message !== 'string'; 294 | 295 | native.server.send(this.external, message, binary ? WebSocketClient.OPCODE_BINARY : WebSocketClient.OPCODE_TEXT, cb ? (() => { 296 | process.nextTick(cb); 297 | }) : undefined, compress); 298 | } else if (cb) { 299 | cb(new Error('not opened')); 300 | } 301 | } 302 | 303 | close(code, data) { 304 | if (this.external) { 305 | native.server.close(this.external, code, data); 306 | this.external = null; 307 | } 308 | } 309 | } 310 | 311 | class WebSocketClient extends WebSocket { 312 | constructor(uri) { 313 | super(null); 314 | this.internalOnOpen = noop; 315 | this.internalOnError = noop; 316 | native.connect(clientGroup, uri, this); 317 | } 318 | 319 | ping(message, options, dontFailWhenClosed) { 320 | if (this.external) { 321 | native.client.send(this.external, message, WebSocketClient.OPCODE_PING, false); 322 | } 323 | } 324 | 325 | terminate() { 326 | if (this.external) { 327 | native.client.terminate(this.external); 328 | this.external = null; 329 | } 330 | } 331 | 332 | send(message, options, cb, compress) { 333 | if (this.external) { 334 | if (typeof options === 'function') { 335 | cb = options; 336 | options = null; 337 | } 338 | 339 | const binary = options && typeof options.binary === 'boolean' ? options.binary : typeof message !== 'string'; 340 | 341 | native.client.send(this.external, message, binary ? WebSocketClient.OPCODE_BINARY : WebSocketClient.OPCODE_TEXT, cb ? (() => { 342 | process.nextTick(cb); 343 | }) : undefined, compress); 344 | } else if (cb) { 345 | cb(new Error('not opened')); 346 | } 347 | } 348 | 349 | close(code, data) { 350 | if (this.external) { 351 | native.client.close(this.external, code, data); 352 | this.external = null; 353 | } 354 | } 355 | } 356 | 357 | class Server extends EventEmitter { 358 | constructor(options, callback) { 359 | super(); 360 | 361 | if (!options) { 362 | throw new TypeError('missing options'); 363 | } 364 | 365 | if (options.port === undefined && !options.server && !options.noServer) { 366 | throw new TypeError('invalid options'); 367 | } 368 | 369 | var nativeOptions = 0; 370 | if (options.perMessageDeflate !== undefined && options.perMessageDeflate !== false) { 371 | nativeOptions |= WebSocketClient.PERMESSAGE_DEFLATE; 372 | 373 | if (options.perMessageDeflate.serverNoContextTakeover === false) { 374 | nativeOptions |= WebSocketClient.SLIDING_DEFLATE_WINDOW; 375 | } 376 | } 377 | 378 | this.serverGroup = native.server.group.create(nativeOptions, options.maxPayload === undefined ? DEFAULT_PAYLOAD_LIMIT : options.maxPayload); 379 | 380 | // can these be made private? 381 | this._upgradeCallback = noop; 382 | this._upgradeListener = null; 383 | this._noDelay = options.noDelay === undefined ? true : options.noDelay; 384 | this._lastUpgradeListener = true; 385 | this._passedHttpServer = options.server; 386 | 387 | if (!options.noServer) { 388 | this.httpServer = options.server ? options.server : http.createServer((request, response) => { 389 | // todo: default HTTP response 390 | response.end(); 391 | }); 392 | 393 | if (options.path && (!options.path.length || options.path[0] !== '/')) { 394 | options.path = '/' + options.path; 395 | } 396 | 397 | this.httpServer.on('upgrade', this._upgradeListener = ((request, socket, head) => { 398 | if (!options.path || options.path == request.url.split('?')[0].split('#')[0]) { 399 | if (options.verifyClient) { 400 | const info = { 401 | origin: request.headers.origin, 402 | secure: request.connection.authorized !== undefined || request.connection.encrypted !== undefined, 403 | req: request 404 | }; 405 | 406 | if (options.verifyClient.length === 2) { 407 | options.verifyClient(info, (result, code, name) => { 408 | if (result) { 409 | this.handleUpgrade(request, socket, head, emitConnection); 410 | } else { 411 | abortConnection(socket, code, name); 412 | } 413 | }); 414 | } else { 415 | if (options.verifyClient(info)) { 416 | this.handleUpgrade(request, socket, head, emitConnection); 417 | } else { 418 | abortConnection(socket, 400, 'Client verification failed'); 419 | } 420 | } 421 | } else { 422 | this.handleUpgrade(request, socket, head, emitConnection); 423 | } 424 | } else { 425 | if (this._lastUpgradeListener) { 426 | abortConnection(socket, 400, 'URL not supported'); 427 | } 428 | } 429 | })); 430 | 431 | this.httpServer.on('newListener', (eventName, listener) => { 432 | if (eventName === 'upgrade') { 433 | this._lastUpgradeListener = false; 434 | } 435 | }); 436 | 437 | this.httpServer.on('error', (err) => { 438 | this.emit('error', err); 439 | }); 440 | } 441 | 442 | native.server.group.onDisconnection(this.serverGroup, (external, code, message, webSocket) => { 443 | webSocket.external = null; 444 | 445 | process.nextTick(() => { 446 | webSocket.internalOnClose(code, message); 447 | }); 448 | 449 | native.clearUserData(external); 450 | }); 451 | 452 | native.server.group.onMessage(this.serverGroup, onServerMessage); 453 | 454 | native.server.group.onPing(this.serverGroup, (message, webSocket) => { 455 | webSocket.onping(message); 456 | }); 457 | 458 | native.server.group.onPong(this.serverGroup, (message, webSocket) => { 459 | webSocket.onpong(message); 460 | }); 461 | 462 | native.server.group.onConnection(this.serverGroup, (external) => { 463 | const webSocket = new WebSocket(external); 464 | 465 | native.setUserData(external, webSocket); 466 | this._upgradeCallback(webSocket); 467 | _upgradeReq = null; 468 | }); 469 | 470 | if (options.port !== undefined) { 471 | if (options.host) { 472 | this.httpServer.listen(options.port, options.host, () => { 473 | this.emit('listening'); 474 | callback && callback(); 475 | }); 476 | } else { 477 | this.httpServer.listen(options.port, () => { 478 | this.emit('listening'); 479 | callback && callback(); 480 | }); 481 | } 482 | } 483 | } 484 | 485 | handleUpgrade(request, socket, upgradeHead, callback) { 486 | if (socket._isNative) { 487 | if (this.serverGroup) { 488 | _upgradeReq = request; 489 | this._upgradeCallback = callback ? callback : noop; 490 | native.upgrade(this.serverGroup, socket.external, secKey, request.headers['sec-websocket-extensions'], request.headers['sec-websocket-protocol']); 491 | } 492 | } else { 493 | const secKey = request.headers['sec-websocket-key']; 494 | const socketHandle = socket.ssl ? socket._parent._handle : socket._handle; 495 | const sslState = socket.ssl ? socket.ssl._external : null; 496 | if (socketHandle && secKey && secKey.length == 24) { 497 | socket.setNoDelay(this._noDelay); 498 | const ticket = native.transfer(socketHandle.fd === -1 ? socketHandle : socketHandle.fd, sslState); 499 | socket.on('close', (error) => { 500 | if (this.serverGroup) { 501 | _upgradeReq = request; 502 | this._upgradeCallback = callback ? callback : noop; 503 | native.upgrade(this.serverGroup, ticket, secKey, request.headers['sec-websocket-extensions'], request.headers['sec-websocket-protocol']); 504 | } 505 | }); 506 | } 507 | socket.destroy(); 508 | } 509 | } 510 | 511 | broadcast(message, options) { 512 | if (this.serverGroup) { 513 | native.server.group.broadcast(this.serverGroup, message, options && options.binary || false); 514 | } 515 | } 516 | 517 | startAutoPing(interval, userMessage) { 518 | if (this.serverGroup) { 519 | native.server.group.startAutoPing(this.serverGroup, interval, userMessage); 520 | } 521 | } 522 | 523 | close(cb) { 524 | if (this._upgradeListener && this.httpServer) { 525 | this.httpServer.removeListener('upgrade', this._upgradeListener); 526 | 527 | if (!this._passedHttpServer) { 528 | this.httpServer.close(); 529 | } 530 | } 531 | 532 | if (this.serverGroup) { 533 | native.server.group.close(this.serverGroup); 534 | this.serverGroup = null; 535 | } 536 | 537 | if (typeof cb === 'function') { 538 | // compatibility hack, 15 seconds timeout 539 | setTimeout(cb, 20000); 540 | } 541 | } 542 | 543 | get clients() { 544 | if (this.serverGroup) { 545 | return { 546 | length: native.server.group.getSize(this.serverGroup), 547 | forEach: ((cb) => {native.server.group.forEach(this.serverGroup, cb)}) 548 | }; 549 | } 550 | } 551 | } 552 | 553 | WebSocketClient.PERMESSAGE_DEFLATE = 1; 554 | WebSocketClient.SLIDING_DEFLATE_WINDOW = 16; 555 | //WebSocketClient.SERVER_NO_CONTEXT_TAKEOVER = 2; 556 | //WebSocketClient.CLIENT_NO_CONTEXT_TAKEOVER = 4; 557 | WebSocketClient.OPCODE_TEXT = 1; 558 | WebSocketClient.OPCODE_BINARY = 2; 559 | WebSocketClient.OPCODE_PING = 9; 560 | WebSocketClient.OPEN = 1; 561 | WebSocketClient.CLOSED = 0; 562 | WebSocketClient.Server = Server; 563 | WebSocketClient.http = native.httpServer; 564 | WebSocketClient.native = native; 565 | module.exports = WebSocketClient; 566 | -------------------------------------------------------------------------------- /nodejs/tests/autobahn.js: -------------------------------------------------------------------------------- 1 | const WebSocketServer = require('../dist/uws').Server; 2 | const non_ssl = new WebSocketServer({ port: 3000 }); 3 | const fs = require('fs'); 4 | const https = require('https'); 5 | 6 | var non_ssl_disconnections = 0; 7 | non_ssl.on('connection', function(ws) { 8 | ws.on('message', function(message) { 9 | ws.send(message); 10 | }); 11 | 12 | ws.on('close', function() { 13 | if (++non_ssl_disconnections == 519) { 14 | non_ssl.close(); 15 | } 16 | }); 17 | }); 18 | 19 | const options = { 20 | key: fs.readFileSync('../uWebSockets/misc/ssl/key.pem'), 21 | cert: fs.readFileSync('../uWebSockets/misc/ssl/cert.pem'), 22 | passphrase: '1234' 23 | }; 24 | 25 | const httpsServer = https.createServer(options, (req, res) => { 26 | req.socket.end(); 27 | }); 28 | 29 | const ssl = new WebSocketServer({ server: httpsServer }); 30 | 31 | var ssl_disconnections = 0; 32 | ssl.on('connection', function(ws) { 33 | ws.on('message', function(message) { 34 | ws.send(message); 35 | }); 36 | 37 | ws.on('close', function() { 38 | if (++ssl_disconnections == 519) { 39 | ssl.close(); 40 | } 41 | }); 42 | }); 43 | 44 | httpsServer.listen(3001); 45 | -------------------------------------------------------------------------------- /python/.gitignore: -------------------------------------------------------------------------------- 1 | build/* 2 | *.pyc 3 | uWebSockets 4 | dist/* 5 | uWebSockets.egg-info/* 6 | .vagrant/* 7 | debug.ld 8 | manylinux.map 9 | uWebSockets.map 10 | windows/*.dll 11 | -------------------------------------------------------------------------------- /python/Bindings.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #ifndef _NO_THREADS 5 | #include 6 | #endif //_NO_THREADS 7 | #include 8 | #include // NOTE: Must be stdint.h not cstdint 9 | 10 | // Fixes error with statically linked OpenSSL library 11 | #ifdef MSVC 12 | FILE _iob[] = {*stdin,*stdout,*stderr}; 13 | extern "C" FILE * __cdecl __iob_func(void) {return _iob;} 14 | #endif 15 | 16 | #include 17 | // Include main uWebsockets 18 | #include "uWS.h" 19 | 20 | 21 | 22 | 23 | 24 | using namespace std; 25 | 26 | #ifdef DEBUG_PYTHON_BINDINGS 27 | #define debug(...) printf(__VA_ARGS__) 28 | #else 29 | #define debug(...) 30 | #endif 31 | 32 | /** Common Exception class **/ 33 | #ifndef MSVC 34 | static PyObject * uWebSockets_error __attribute__ ((unused)); 35 | #else 36 | static PyObject * uWebSockets_error; 37 | #endif 38 | 39 | //TODO: Remove, testing bindings work 40 | static PyObject * uWebSockets_hello(PyObject * self, PyObject * args) { 41 | debug("Hello, world\n"); 42 | Py_RETURN_NONE; 43 | } 44 | 45 | /** 46 | * Websocket extension 47 | */ 48 | template 49 | class WebSocket 50 | { 51 | private: /** Don't define variables here it breaks Python, define at the bottom **/ 52 | WebSocket() { 53 | // CPython cannot bind to constructors 54 | throw new runtime_error("Constructor cannot be called"); 55 | } 56 | virtual ~WebSocket() { 57 | // CPython cannot bind to destructors 58 | throw new runtime_error("Destructor cannot be called"); 59 | } 60 | 61 | public: 62 | /** 63 | * Wrapper for python __init__ 64 | */ 65 | int __init__(char * uri) { 66 | debug("Called __init__\n"); 67 | this->hub = new uWS::Hub(); 68 | this->ws = NULL; 69 | this->td = NULL; 70 | this->_state = INVALID; 71 | this->close_immediately = false; 72 | hub->uWS::Group::onConnection([this](uWS::WebSocket *ws, uWS::HttpRequest req) { 73 | debug("Connected!\n"); 74 | if (this->close_immediately) { 75 | ws->close(); 76 | } else { 77 | this->ws = ws; 78 | this->_state = CONNECTED; 79 | this->on_open(); 80 | } 81 | }); 82 | 83 | hub->uWS::Group::onMessage([this](uWS::WebSocket *ws, char *message, size_t length, uWS::OpCode opCode) { 84 | debug("Got message %s %d\n", message, (int)length); 85 | if (this->close_immediately) { 86 | ws->close(); 87 | } 88 | else { 89 | this->on_message(message, length); 90 | } 91 | }); 92 | 93 | hub->uWS::Group::onDisconnection([this](uWS::WebSocket * ws, int code, char *message, size_t length) { 94 | debug("Closed %d %s\n", code, message ? message : "(null)"); 95 | if (this->_state != INVALID) { 96 | this->_state = DISCONNECTED; 97 | } 98 | if (!this->close_immediately) { 99 | this->on_close(code, message, length); 100 | } 101 | }); 102 | // Work around for MANYLINUX initialisation bug, explicitly initialise empty headers 103 | map extra_headers = map(); 104 | this->_state = CONNECTING; 105 | hub->connect(uri, nullptr, extra_headers); 106 | return 0; 107 | } 108 | 109 | /** 110 | * Wrapper for python destructor 111 | */ 112 | void __del__() { 113 | debug("Called __del__\n"); 114 | if (this->connected()) { 115 | this->close(); 116 | } 117 | delete this->hub; 118 | delete this->td; 119 | this->hub = NULL; 120 | this->td = NULL; 121 | this->ws = NULL; 122 | this->_state = INVALID; 123 | } 124 | private: 125 | PyObject * check_error(const char * name) { 126 | if (this->_state == INVALID) { 127 | PyErr_SetString(uWebSockets_error, ""); 128 | this->_state = EXCEPTION; 129 | this->close(); 130 | return NULL; 131 | } 132 | Py_RETURN_NONE; 133 | } 134 | public: 135 | /** 136 | * Message handler 137 | */ 138 | PyObject * on_message(char * message, size_t length) { 139 | debug("Got message %s %d\n", message, (int)length); 140 | PyGILState_STATE gstate = PyGILState_Ensure(); 141 | PyObject * result = PyObject_CallMethod((PyObject*)this, (char*)"on_message", (char*)"s#", message, length); 142 | if (result == NULL) { 143 | fprintf(stderr, "Error in on_message(%s,%d)\n", message, (int)length); 144 | PyErr_WriteUnraisable((PyObject*)this); 145 | this->close(); 146 | this->_state = INVALID; 147 | } 148 | PyGILState_Release(gstate); 149 | return result; 150 | } 151 | 152 | /** 153 | * Send a message 154 | */ 155 | PyObject * send(char * message, size_t length) { 156 | debug("Sending: \"%s\" %d\n", message, (int)length); 157 | if (!this->ws || this->valid() == Py_False) { 158 | debug("Not connected!\n"); 159 | PyErr_SetString(uWebSockets_error, "WebSocket not connected yet"); 160 | return NULL; 161 | } else if (this->connected() == Py_False) { 162 | PyErr_SetString(uWebSockets_error, "WebSocket has disconnected"); 163 | return NULL; 164 | } 165 | this->ws->send(message, length, uWS::OpCode::TEXT); 166 | return this->check_error("send"); 167 | } 168 | 169 | 170 | 171 | PyObject * run(bool background) { 172 | debug("Called run %d\n", background); 173 | #ifndef _NO_THREADS 174 | if (background) { 175 | this->td = new thread([this]() { 176 | this->hub->run(); 177 | }); 178 | } else 179 | #endif //_NO_THREADS 180 | { 181 | Py_BEGIN_ALLOW_THREADS 182 | this->hub->run(); 183 | Py_END_ALLOW_THREADS 184 | } 185 | return this->check_error("run"); 186 | } 187 | 188 | PyObject * on_open() { 189 | debug("GIL state %d\n", PyGILState_Check()); 190 | PyGILState_STATE gstate = PyGILState_Ensure(); 191 | debug("GIL state %d\n", PyGILState_Check()); 192 | PyObject * result = PyObject_CallMethod((PyObject*)this, (char*)"on_open", NULL); // NOTE: Ignore the -Wwrite-strings warning 193 | debug("GIL state %d\n", PyGILState_Check()); 194 | debug("Result is %p , %s\n", (void*)result, (result == Py_True) ? "True" : (result == Py_False) ? "False" : "???"); 195 | if (result == NULL) { 196 | fprintf(stderr, "Error in on_open()"); 197 | PyErr_WriteUnraisable((PyObject*)this); 198 | this->close(); 199 | this->_state = INVALID; 200 | } 201 | PyGILState_Release(gstate); 202 | return result; 203 | } 204 | 205 | PyObject * connected() { 206 | if (this->_state == INVALID) { 207 | return this->check_error("connected"); 208 | } 209 | if (this->_state == CONNECTED) { 210 | Py_RETURN_TRUE; 211 | } else { 212 | Py_RETURN_FALSE; 213 | } 214 | } 215 | 216 | PyObject * valid() { 217 | if (this->_state == INVALID) { 218 | return this->check_error("valid"); 219 | } 220 | if (this->_state == CONNECTED || this->_state == DISCONNECTED) { 221 | Py_RETURN_TRUE; 222 | } else { 223 | Py_RETURN_FALSE; 224 | } 225 | } 226 | 227 | PyObject * on_close(int code, char * message, int length) { 228 | if (this->close_immediately) { 229 | Py_RETURN_NONE; 230 | } 231 | PyGILState_STATE gstate = PyGILState_Ensure(); 232 | PyObject * result = PyObject_CallMethod((PyObject*)this, (char*)"on_close", (char*)"is#", code, message, length); // NOTE: Ignore the -Wwrite-strings warning 233 | if (result == NULL) { 234 | fprintf(stderr, "Error in on_close(%d, %s,%d)\n", code, message, length); 235 | PyErr_WriteUnraisable((PyObject*)this);; 236 | this->_state = INVALID; 237 | } 238 | PyGILState_Release(gstate); 239 | //this->__del__(); 240 | return result; 241 | } 242 | 243 | PyObject * close() { 244 | debug("Close requested\n"); 245 | PyGILState_STATE gstate = PyGILState_Ensure(); 246 | if (this->ws) { 247 | debug("Close socket\n"); 248 | uWS::WebSocket * w = this->ws; 249 | this->ws = NULL; 250 | w->close(); 251 | } else { 252 | this->close_immediately = true; 253 | } 254 | #ifndef _NO_THREADS 255 | if (this->td && this_thread::get_id() != this->td->get_id()) { 256 | debug("Join thread\n"); 257 | thread * t = td; 258 | this->td = NULL; 259 | t->join(); 260 | } 261 | #endif 262 | PyGILState_Release(gstate); 263 | return this->check_error("close"); 264 | } 265 | 266 | PyObject * force_close() { 267 | this->close_immediately = true; 268 | return this->close(); 269 | } 270 | 271 | PyObject_HEAD 272 | 273 | private: 274 | // The websocket 275 | uWS::WebSocket * ws; 276 | // The Hub 277 | uWS::Hub * hub; 278 | #ifndef _NO_THREADS 279 | thread * td; 280 | #else 281 | void * td; 282 | #endif 283 | enum { 284 | INVALID=0, 285 | CONNECTING=1, 286 | CONNECTED=2, 287 | DISCONNECTED=3, 288 | EXCEPTION=6, 289 | } _state; 290 | bool close_immediately; 291 | 292 | }; 293 | 294 | template 295 | static PyObject * WebSocket_new(PyTypeObject * type, PyObject * args, PyObject * kwargs) { 296 | debug("Construct new object\n"); 297 | WebSocket * self = (WebSocket*)(type->tp_alloc(type, 0)); 298 | return (PyObject*)(self); 299 | } 300 | 301 | template 302 | static void WebSocket_dealloc(WebSocket * self) { 303 | if (self != NULL) { 304 | self->__del__(); 305 | Py_TYPE(self)->tp_free((PyObject*)self); 306 | } 307 | } 308 | 309 | template 310 | static PyObject * WebSocket_run(PyObject * self, PyObject * args) { 311 | bool background; 312 | if (!PyArg_ParseTuple(args, "b", &background)) { 313 | return NULL; 314 | } 315 | return ((WebSocket*)(self))->run(background); 316 | } 317 | 318 | template 319 | static int WebSocket_init(WebSocket * self, PyObject * args, PyObject * kwargs) { 320 | debug("Initialise new object\n"); 321 | char * uri; 322 | int length; 323 | if (!PyArg_ParseTuple(args, "s#", &uri, &length)) { 324 | return 1; 325 | } 326 | debug("URI: %s, %d\n", uri, length); 327 | return self->__init__(uri); 328 | } 329 | 330 | template 331 | static PyObject * WebSocket_on_message(PyObject * self, PyObject * args) { 332 | char * message; 333 | int length; 334 | if (!PyArg_ParseTuple(args, "s#", &message, &length)) { 335 | return NULL; 336 | } 337 | return ((WebSocket*)(self))->on_message(message, length); 338 | } 339 | 340 | template 341 | static PyObject * WebSocket_send(PyObject * self, PyObject * args) { 342 | char * message; 343 | int length; 344 | debug("Sending...\n"); 345 | if (!PyArg_ParseTuple(args, "s#", &message, &length)) { 346 | return NULL; 347 | } 348 | debug("Args: %s %d\n", message, length); 349 | return ((WebSocket*)(self))->send(message, length); 350 | } 351 | 352 | template 353 | static PyObject * WebSocket_close(PyObject * self, PyObject * args) { 354 | return ((WebSocket*)(self))->close(); 355 | } 356 | 357 | template 358 | static PyObject * WebSocket_connected(PyObject * self, PyObject * args) { 359 | return ((WebSocket*)(self))->connected(); 360 | } 361 | 362 | template 363 | static PyObject * WebSocket_valid(PyObject * self, PyObject * args) { 364 | return ((WebSocket*)(self))->valid(); 365 | } 366 | 367 | template 368 | static PyObject * WebSocket_getattr(PyObject * self, PyObject * name) { 369 | #if (PYTHON_FLAVOUR == 3) 370 | char * cname = PyBytes_AsString(PyUnicode_AsASCIIString(name)); 371 | #else 372 | char * cname = PyString_AsString(name); 373 | #endif 374 | if (cname == NULL) { 375 | return NULL; 376 | } 377 | PyObject * result = PyObject_GenericGetAttr(self, name); 378 | if (result == NULL) { 379 | fprintf(stderr, "No such attribute \"%s\"\n", cname); 380 | WebSocket * w = (WebSocket*)(self); 381 | w->force_close(); 382 | } 383 | return result; 384 | } 385 | 386 | static PyMethodDef WebSocketClient_methods[] = { 387 | {"on_message", WebSocket_on_message, METH_VARARGS, (char*)"Callback for receiving a message"}, 388 | {"send", WebSocket_send, METH_VARARGS, (char*)"Send a message to connected peer"}, 389 | {"run", WebSocket_run, METH_VARARGS, (char*)"Start the event loop"}, 390 | {"close", WebSocket_close, METH_VARARGS, (char*)"Close the WebSocket"}, 391 | {"connected", WebSocket_connected, METH_VARARGS, (char*)"Is the WebSocket currently connected right now?"}, 392 | {"valid", WebSocket_valid, METH_VARARGS, (char*)"Is the WebSocket valid?"}, 393 | {NULL} 394 | }; 395 | 396 | 397 | 398 | /** 399 | * Python Type Object for the WebSocket class 400 | */ 401 | static PyTypeObject uWebSockets_WebSocketClientType = { 402 | PyVarObject_HEAD_INIT(NULL, 0) 403 | "uWebSockets.WebSocketClient", /* tp_name */ 404 | sizeof(WebSocket), /* tp_basicsize */ 405 | 0, /* tp_itemsize */ 406 | (destructor)WebSocket_dealloc, /* tp_dealloc */ 407 | 0, /* tp_print */ 408 | 0, /* tp_getattr */ 409 | 0, /* tp_setattr */ 410 | 0, /* tp_compare */ 411 | 0, /* tp_repr */ 412 | 0, /* tp_as_number */ 413 | 0, /* tp_as_sequence */ 414 | 0, /* tp_as_mapping */ 415 | 0, /* tp_hash */ 416 | 0, /* tp_call */ 417 | 0, /* tp_str */ 418 | WebSocket_getattr, /* tp_getattro */ 419 | 0, /* tp_setattro */ 420 | 0, /* tp_as_buffer */ 421 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ 422 | "A WebSocket Client", /* tp_doc */ 423 | 0, 424 | 0, 425 | 0, 426 | 0, 427 | 0, 428 | 0, 429 | WebSocketClient_methods, 430 | 0, 431 | 0, 432 | 0, 433 | 0, 434 | 0, 435 | 0, 436 | 0, 437 | (initproc)WebSocket_init, 438 | 0, 439 | WebSocket_new, 440 | }; 441 | 442 | 443 | /** 444 | * Public methods 445 | */ 446 | static PyMethodDef uWebSockets_methods[] = { 447 | {"hello", uWebSockets_hello, METH_VARARGS, "Prints 'Hello, World'"}, 448 | //{"WebSocketClient", , METH_VARARGS, "Create WebSocket client"}, 449 | {NULL, NULL, 0, NULL} 450 | }; 451 | 452 | 453 | 454 | #if (PYTHON_FLAVOUR == 3) 455 | /** 456 | * Module definition structure 457 | * (Py_InitModule is Python2 only) 458 | */ 459 | static struct PyModuleDef uWebSockets_module_def = { 460 | PyModuleDef_HEAD_INIT, 461 | "uWebSockets", // name 462 | "Python bindings for the uWebSockets library", // docstring 463 | -1, // Keep state in globals 464 | uWebSockets_methods //module methods 465 | }; 466 | #endif 467 | 468 | /** 469 | * Module initialisation function 470 | */ 471 | PyMODINIT_FUNC 472 | inituWebSockets(void) { 473 | debug("Called inituWebSockets\n"); 474 | if (!Py_IsInitialized()) { // If for some reason we are invoking the interpreter from here rather than the other way around... 475 | debug("Initialise"); 476 | Py_Initialize(); 477 | } 478 | PyObject * m = NULL; 479 | #if (PYTHON_FLAVOUR == 3) 480 | m = PyModule_Create(&uWebSockets_module_def); // Python3 way 481 | #else 482 | m = Py_InitModule("uWebSockets", uWebSockets_methods); // Python2 way 483 | #endif 484 | 485 | if (m == NULL) { 486 | #if (PYTHON_FLAVOUR == 3) 487 | Py_RETURN_NONE; 488 | #else 489 | return; 490 | #endif 491 | } 492 | 493 | uWebSockets_error = PyErr_NewException((char*)"uWebSockets.Error", NULL, NULL); 494 | Py_INCREF(uWebSockets_error); 495 | PyModule_AddObject(m, "Error", uWebSockets_error); 496 | if (PyType_Ready(&uWebSockets_WebSocketClientType) < 0) { 497 | fprintf(stderr, __FILE__":Failed to construct WebSocketClientType\n"); 498 | #if (PYTHON_FLAVOUR == 3) 499 | return m; 500 | #else 501 | return; 502 | #endif 503 | } 504 | Py_INCREF(&uWebSockets_WebSocketClientType); 505 | PyModule_AddObject(m, "WebSocketClient", (PyObject*)&uWebSockets_WebSocketClientType); 506 | 507 | PyEval_InitThreads(); 508 | #if (PYTHON_FLAVOUR == 3) 509 | return m; 510 | #endif 511 | } 512 | 513 | // Define both PyInit_uWebSockets and inituWebSockets for compatibility 514 | PyMODINIT_FUNC 515 | PyInit_uWebSockets(void) { 516 | debug("Called PyInit_uWebSockets\n"); 517 | #if (PYTHON_FLAVOUR == 3) 518 | return inituWebSockets(); 519 | #else 520 | inituWebSockets(); 521 | #endif 522 | } 523 | 524 | #ifdef MANYLINUX 525 | typedef void (*_exitfn)(void); 526 | static vector<_exitfn> _atexit = vector<_exitfn>(); 527 | 528 | void __wrap__fini(void) { 529 | //TODO: Remove this horrible hack 530 | for (_exitfn & fn : _atexit) { 531 | (*fn)(); 532 | } 533 | } 534 | 535 | extern "C" { 536 | void __wrap_atexit(void(*function)(void)) { 537 | _atexit.push_back(function); 538 | } 539 | } 540 | #endif 541 | -------------------------------------------------------------------------------- /python/Jenkinsfile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env groovy 2 | pipeline { 3 | agent any 4 | triggers { cron("@daily") } 5 | options { 6 | timeout(time: 1, unit: 'HOURS') 7 | //retry(4) //Doesn't actually work see https://issues.jenkins-ci.org/browse/JENKINS-46354 8 | } 9 | stages { 10 | stage('Start Vagrant') { 11 | steps { 12 | sh 'cd python && vagrant up' 13 | } 14 | } 15 | 16 | stage('Build') { 17 | steps { 18 | sh 'cd python && make vagrant/wheels' 19 | } 20 | } 21 | 22 | stage('Install') { 23 | steps { 24 | sh 'cd python && make vagrant/install' 25 | } 26 | } 27 | 28 | stage('Tests') { 29 | steps { 30 | sh 'cd python && make vagrant/test' 31 | } 32 | } 33 | 34 | stage('Uninstall') { 35 | steps { 36 | sh 'cd python && make vagrant/uninstall' 37 | } 38 | } 39 | } 40 | post { 41 | failure { 42 | sh 'echo Failed' 43 | sh '(cd python; make vagrant/uninstall; make vagrant/clean) || echo "Could not clean!"' 44 | } 45 | success { 46 | sh 'echo Success!' 47 | } 48 | always { 49 | step([$class: 'LogParserPublisher', parsingRulesPath: '/var/lib/jenkins/jenkins-rule-logparser', useProjectRule: false]) 50 | sh 'cd python && vagrant halt' 51 | } 52 | 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /python/MANIFEST.in: -------------------------------------------------------------------------------- 1 | include uWebSockets/src/*.h 2 | -------------------------------------------------------------------------------- /python/Makefile: -------------------------------------------------------------------------------- 1 | export CXX 2 | export CC 3 | 4 | ## Work out the platform for python wheels 5 | PLATFORM := $(shell uname -s) 6 | ifeq ($(filter Linux Windows Darwin,$(PLATFORM)),) 7 | PLATFORM := Windows 8 | endif 9 | PLATFORM := $(shell echo $(PLATFORM) | tr '[:upper:]' '[:lower:]') 10 | #PLATFORM :="$(PLATFORM)-$(shell arch)" 11 | all : wheels 12 | 13 | ifeq ($(PLATFORM),windows) 14 | wheels : setup.py 15 | cmd /c build-all-wheels.bat 16 | else 17 | SHELL := bash 18 | wheels : setup.py 19 | bash build-all-wheels.sh 20 | sdist : setup.py 21 | python2 setup.py sdist 22 | python3 setup.py sdist 23 | 24 | endif 25 | 26 | 27 | clean : 28 | rm -rf build 29 | rm -rf dist 30 | 31 | upload : 32 | find dist -type f -print | while IFS= read -r f; do \ 33 | twine upload $$f; \ 34 | done 35 | 36 | install : 37 | if (which pip2); then pip2 install uWebSockets --no-index -f dist; fi 38 | if (which pip3); then pip3 install uWebSockets --no-index -f dist; fi 39 | if [[ -d /opt/python/*/bin ]]; then \ 40 | for PYBIN in /opt/python/*/bin; do \ 41 | "$${PYBIN}/pip" install uWebSockets --no-index -f dist; \ 42 | done; \ 43 | fi 44 | 45 | uninstall : 46 | pip2 uninstall -y uWebSockets 47 | pip3 uninstall -y uWebSockets 48 | if [[ -d /opt/python/*/bin ]]; then \ 49 | for PYBIN in /opt/python/*/bin; do \ 50 | "$${PYBIN}/pip" uninstall -y uWebSockets --no-index -f dist; \ 51 | done; \ 52 | fi 53 | 54 | 55 | ## Wrappers for building with Vagrant/Docker 56 | VAGRANT_PROVIDER ?= docker 57 | VAGRANT_HOST ?= manylinux 58 | .vagrant : Vagrantfile $(if $(filter docker,$(VAGRANT_PROVIDER)), $(shell find docker -path "*/$(VAGRANT_HOST)/*" -name "Dockerfile" -print)) 59 | vagrant destroy -f $(VAGRANT_HOST) 60 | vagrant up $(VAGRANT_HOST) 61 | touch $@ 62 | 63 | vagrant/% : .vagrant 64 | (vagrant status $(VAGRANT_HOST) | grep "$(VAGRANT_HOST)" | grep "running") || vagrant up $(VAGRANT_HOST) 65 | vagrant ssh $(VAGRANT_HOST) -c 'cd /vagrant && make $(notdir $@)' 66 | 67 | all-vagrant : 68 | export VAGRANT_HOST=devel && make vagrant/wheels 69 | export VAGRANT_HOST=manylinux && make vagrant/wheels 70 | 71 | ifeq ($(MANYLINUX),yes) 72 | ldd-manylinux : wheels 73 | sudo /opt/python/cp27-cp27mu/bin/pip2 uninstall -y uWebSockets || true 74 | sudo /opt/python/cp27-cp27mu/bin/pip2 install --no-index -f dist/ uWebSockets 75 | ldd /opt/_internal/cpython-2.7.14-ucs4/lib/python2.7/site-packages/uWebSockets.so 76 | 77 | manylinux.map : /glibc-glibc-2.10/build/libc.map Makefile 78 | cat $(firstword $^) > $@ 79 | echo -e "UWS_0.14.6 {\n global:\n inituWebSockets;\n PyInit_uWebSockets;\n};" >> $@ 80 | 81 | setup.py : manylinux.map 82 | 83 | endif 84 | 85 | 86 | -------------------------------------------------------------------------------- /python/README.md: -------------------------------------------------------------------------------- 1 | # uWebSockets Python Bindings 2 | 3 | * Maintained by @szmoore on behalf of [Element Engineering Australia](https://github.com/elementengineering/uWebSockets-bindings) 4 | * This is a largely seperate project from uWebSockets and the *nodejs* bindings for uWebSockets. Refer to [uNetworking](https://github.com/uNetworking); all credit for uWebSockets and the nodejs bindings go to authors listed there. 5 | 6 | * ~~Original issue (since deleted)[#25](https://github.com/uNetworking/bindings/pull/25)~~ 7 | 8 | 9 | * These bindings are on [PyPi](https://pypi.python.org/pypi/uWebSockets) for Python 2.7 and Python 3.6 10 | * `pip2 install uWebSockets` or `pip3 install uWebSockets` 11 | * Chat is [here](https://gitter.im/uWebSockets-chat/Lobby) 12 | 13 | ## Important notice for Linux Users ## 14 | * If you think you found a bug in a binary wheel package on PyPi, please first try to reproduce it after downloading the `tar.gz` version of the package. 15 | This is essential because the `manylinux1` wheels are basically a giant hack and may behave differently. 16 | * While we are compatible with `manylinux1` in terms of the ABI versioning, we might not be compatible with ancient linux kernel versions that don't support `eventfd` 17 | * We statically link absolutely everything we can (even parts of the C standard library) and modify version symbols and linker scripts. Yep. 18 | 19 | ## Important notice for Windows Users ## 20 | 21 | * This is not easy to compile on windows. 22 | * We statically link some of the libraries because they are not easily available for windows. 23 | But it's not quite as bad as the hacks used for `manylinux1`. 24 | 25 | ## Usage: 26 | 27 | * See [test_client.py](tests/test_client.py) 28 | * The API mimics [`websocket-client`](https://github.com/websocket-client/websocket-client) as closely as possible (except we always exit on exceptions). 29 | 1. The object must be provided a URI at initialisation eg: `MyWebSocket("wss://echo.websocket.org")` 30 | 2. `on_open()` called when opened (if defined) 31 | 3. `on_message(message)` called on messages (if defined) 32 | 4. `on_close()` called on clean exit (if defined) 33 | 5. `send(message)` send message if possible 34 | 6. `close()` close socket, idempotent 35 | **Warning** Once the socket is closed, it can't be re-opened - you have to make a new one. 36 | 37 | * This is not optimized at all but it's already better than `websocket-client` due to the upstream `uWebSockets` being so good. 38 | 39 | 40 | ## Compiling from Source 41 | 42 | ### Linux x86_64 43 | 1. `git submodule update --init` 44 | 2. Copy or move the uWebSockets directory into this directory `cp -R ../uWebSockets ./` 45 | 3. Pick one of: 46 | 1. Install `docker` and `vagrant` **(preferred)** 47 | 2. Install `g++ gcc make git libssl-dev libuv1-dev python python-pip python3 python3-pip python3-all-dev python2.7-dev` (debian) 48 | 49 | 3. And then accordingly: 50 | 1. Docker: `make vagrant/all` 51 | * (or `vagrant ssh -c 'cd /vagrant; make wheels'`) 52 | 2. Native: `make wheels` 53 | 54 | ### Windoze 55 | * Install the dependencies listed [here](./windows/windoze.md) 56 | * Based on a guide from [@spacecowboy](http://cowboyprogrammer.org/building-python-wheels-for-windows/) with modifications for Windows 10 57 | * `cmd /c build-all-wheels.bat` 58 | 59 | ### OSX 60 | * Use [brew](https://brew.sh/) to install development libraries / gcc 61 | * `make wheels` 62 | 63 | ## Complaints/Support 64 | * This is a third party binding, which is seperate from the main uWebSockets project (and also the node binding) 65 | * See [#25](https://github.com/uNetworking/bindings/pull/25) 66 | * Tag issues with Python bindings to @szmoore 67 | * See the [section above](#Important) about `manylinux1` issues. 68 | 69 | #### The eternal struggle 70 | * Python2 will never disappear, so you have to support it forever 71 | * Python3 will never be stable, so you have to support it forever 72 | 73 | 74 | ``` 75 | Thus farther still upon the outermost 76 | Head of that seventh circle all alone 77 | I went, where sat the melancholy folk. 78 | ``` 79 | 80 | 81 | -------------------------------------------------------------------------------- /python/Vagrantfile: -------------------------------------------------------------------------------- 1 | # Generate UUIDs to hack around bug with docker container name and image tags (otherwise will get conflict on vagrant destroy) 2 | require 'securerandom' 3 | 4 | Vagrant.configure("2") do |config| 5 | config.vm.define "devel" do |d| 6 | d.vm.hostname = "devel" 7 | d.vm.provider "docker" do |p| 8 | p.build_dir = "docker/devel" 9 | p.remains_running = true 10 | p.has_ssh = true 11 | end 12 | end 13 | 14 | config.vm.define "manylinux" do |d| 15 | d.vm.hostname = "manylinux" 16 | d.vm.provider "docker" do |p| 17 | p.build_dir = "docker/manylinux" 18 | p.remains_running = true 19 | p.has_ssh = true 20 | p.create_args = ["--cap-add", "SYS_PTRACE"] 21 | end 22 | end 23 | 24 | config.vm.define "test" do |d| 25 | d.vm.hostname = "test" 26 | d.vm.provider "docker" do |p| 27 | p.build_dir = "docker/test" 28 | p.remains_running = true 29 | p.has_ssh = true 30 | p.create_args = ["--cap-add", "SYS_PTRACE"] 31 | end 32 | end 33 | 34 | end 35 | -------------------------------------------------------------------------------- /python/build-all-wheels.bat: -------------------------------------------------------------------------------- 1 | :: Based on https://gist.github.com/spacecowboy/23fcd4d40cfd1c1cd88a#file-build-all-wheels-bat, added Python 3.6 2 | :: Credit to @spacecowboy http://cowboyprogrammer.org/building-python-wheels-for-windows/ 3 | 4 | :: Required: Visual Studio 10.0 Express, Visual Studio 9 Express, 5 | :: Windows 7 SDK (.NET 4), Windows 7 SDK (.NET 3.5), Anaconda/Miniconda 6 | 7 | ::::::::::::::::::::::::::::::::::: 8 | :: User configurable stuff start :: 9 | ::::::::::::::::::::::::::::::::::: 10 | echo off 11 | :: These depends on where you installed Anaconda. 12 | :: Python2 or Python3 doesn't matter but you need both 32bit and 64bit versions. 13 | set ANACONDA_BASE=C:\ProgramData\Anaconda2 14 | set ANACONDA_BASE64=C:\ProgramData\Anaconda2-64 15 | 16 | :: Location of your package, can be a directory or a git repo. 17 | 18 | :: A directory 19 | set PKG_REPO=C:\Users\Sam.Moore\Documents\uWebSockets-bindings\python 20 | 21 | set WHEEL_DIR=%PKG_REPO%\dist 22 | 23 | :: A git repo 24 | :: set PKG_REPO=git+https://github.com/uNetworking/bindings.git 25 | 26 | ::::::::::::::::::::::::::::::::: 27 | :: User configurable stuff end :: 28 | ::::::::::::::::::::::::::::::::: 29 | 30 | :: Save original path so we can restore it 31 | set BASEPATH=%PATH% 32 | 33 | :: Set up your conda environments like this, do it for both 32bit and 64bit. 34 | :: navigate to the Anaconda\Scripts / Anaconda-64\Scripts directory to avoid setting any Paths 35 | :: conda create -n py3.6 python=3.6 numpy pip mingw 36 | :: conda create -n py3.4 python=3.4 numpy pip mingw 37 | :: conda create -n py3.3 python=3.3 numpy pip mingw 38 | :: conda create -n py2.7 python=2.7 numpy pip mingw 39 | 40 | :: These depend on what you named your environments above 41 | set ENV27=envs\py2.7 42 | set ENV33=envs\py3.3 43 | set ENV34=envs\py3.4 44 | set ENV36=envs\py3.6 45 | 46 | :: Tell Python to select correct SDK version 47 | set DISTUTILS_USE_SDK=1 48 | set MSSdk=1 49 | 50 | set ANACONDA_BASE=C:\ProgramData\Anaconda3 51 | set ANACONDA_BASE64=C:\ProgramData\Anaconda3-64 52 | 53 | set PATH=%BASEPATH% 54 | :: Python3 requires Visual Studio 2010 compiler present (Express version is fine) 55 | call "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.Cmd" /Release /x86 56 | call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86 57 | set CPATH=%PATH% 58 | :: Python3.6 32bit 59 | set PATH=%ANACONDA_BASE%\%ENV36%;%ANACONDA_BASE%\%ENV36%\Scripts;%CPATH% 60 | echo "Python 3.6 32bit" 61 | call :Build 62 | 63 | 64 | :: Set 64-bit environment 65 | 66 | call "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.Cmd" /Release /x64 67 | call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64 68 | :: 64-bit cl.exe is here 69 | set CPATH=C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\x86_amd64;%CPATH% 70 | :: Python3.6 64bit 71 | set PATH=%ANACONDA_BASE64%\%ENV36%;%ANACONDA_BASE64%\%ENV36%\Scripts;%CPATH%;%PATH% 72 | echo "Python 3.6 64bit" 73 | call :Build 74 | 75 | goto:END 76 | 77 | :Build 78 | set PATH=%PATH%;C:\Program Files (x86)\Windows Kits\8.1\bin\x86 79 | color 07 80 | python --version 81 | pip --version 82 | :: Display architecture for sanity purposes 83 | python -c "import ctypes; print(ctypes.sizeof(ctypes.c_voidp)*8)" 84 | color 07 85 | :: And sys.executable 86 | python -c "import sys; print(sys.executable)" 87 | color 07 88 | pip install wheel -q 89 | color 07 90 | pip wheel --no-deps %PKG_REPO% --wheel-dir %WHEEL_DIR% 91 | color 07 92 | python %PKG_REPO%/setup.py fix-wheel 93 | color 07 94 | EXIT /B 0 95 | 96 | :END 97 | :: pip messes with terminal colours 98 | color 07 99 | -------------------------------------------------------------------------------- /python/build-all-wheels.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -x 3 | set -v 4 | set -e 5 | 6 | # Install with extra pythons 7 | if [[ -d /opt/python/ ]]; then 8 | # Set LD PATH 9 | 10 | # Go through directories in order of most recetly touched; 11 | for PYROOT in $(ls -t /opt/python) ; do 12 | sudo touch "/opt/python/${PYROOT}" # Touch the directory, this means if it fails it will be built first next time 13 | PYBIN="/opt/python/${PYROOT}/bin" 14 | set -e 15 | if ! [[ -f "${PYBIN}/nosetests" ]]; then set -e; sudo "${PYBIN}/pip" install nose; fi 16 | 17 | rm -rf build 18 | "${PYBIN}/pip" wheel . --wheel-dir prefixed 19 | sudo "${PYBIN}/pip" uninstall -y uWebsockets || true 20 | sudo "${PYBIN}/pip" install --no-index -f prefixed/ uWebsockets 21 | # Test import 22 | "${PYBIN}/python" -c "import uWebSockets" 23 | # Run nosetests 24 | "${PYBIN}/python" tests/test_client.py 25 | mkdir -p dist/ 26 | mv prefixed/* dist/ 27 | set +e 28 | 29 | whl=$(ls dist -htal | grep ".whl" | awk '{print $NF}' | head -n 1) 30 | old=$LD_LIBRARY_PATH 31 | export LD_LIBRARY_PATH=/opt/openssl/lib:/usr/local/lib:$LD_LIBARY_PATH 32 | (cd dist && auditwheel -vv show "$whl") 33 | if ! (cd dist && auditwheel repair "$whl" --wheel-dir .); then 34 | exit 1 35 | fi 36 | export LD_LIBRARY_PATH=$old 37 | unset old 38 | 39 | set -e 40 | sudo "${PYBIN}/pip" uninstall -y uWebsockets || true 41 | sudo "${PYBIN}/pip" install --no-index -f dist/ uWebsockets 42 | # Test import 43 | "${PYBIN}/python" -c "import uWebSockets" 44 | # Run nosetests 45 | "${PYBIN}/python" tests/test_client.py 46 | 47 | set +e 48 | done 49 | fi 50 | 51 | # Install with default python if it exists 52 | if (which pip2); then rm -rf build; pip2 wheel . --wheel-dir dist; fi 53 | if (which pip3); then rm -rf build; pip3 wheel . --wheel-dir dist; fi 54 | 55 | -------------------------------------------------------------------------------- /python/docker/devel/Dockerfile: -------------------------------------------------------------------------------- 1 | # Docker image for Vagrant which allows vagrant ssh to work 2 | FROM debian:buster 3 | ADD sources.list /etc/apt/sources.list 4 | ADD docker-common.sh /docker-common.sh 5 | RUN bash docker-common.sh && rm -f docker-common.sh 6 | 7 | RUN apt-get -y install \ 8 | rsync \ 9 | g++ \ 10 | gcc \ 11 | make \ 12 | git \ 13 | cmake \ 14 | libssl-dev \ 15 | libuv1-dev \ 16 | python \ 17 | python-pip \ 18 | python3 \ 19 | python3-pip \ 20 | python3-all-dev \ 21 | python2.7-dev 22 | 23 | RUN pip3 install --upgrade pip && \ 24 | pip2 install --upgrade pip 25 | 26 | RUN pip3 install wheel && \ 27 | pip2 install wheel 28 | 29 | EXPOSE 22 30 | ENTRYPOINT ["/usr/sbin/sshd", "-D"] 31 | -------------------------------------------------------------------------------- /python/docker/devel/README.md: -------------------------------------------------------------------------------- 1 | Dockerfile matches @szmoore's build environment as closely as possible. 2 | 3 | Debian 10 (buster) with standard system packages and C libraries installed via apt-get, but pip has been upgraded 4 | and assume use of pip for all python related packaging (as pypi recommends). 5 | 6 | -------------------------------------------------------------------------------- /python/docker/devel/docker-common.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -v 4 | set -x 5 | 6 | # Running this script at the start of a Dockerfile will allow vagrant ssh to correctly work with that machine 7 | # Should work for apt (debian) or yum (centos) based distributions 8 | # We use this because vagrant ssh is a more convenient workflow than `docker attach` 9 | 10 | function generic { 11 | 12 | groupadd -g 1000 vagrant && \ 13 | useradd --create-home -s /bin/bash -u 1000 -g 1000 vagrant && \ 14 | (echo 'vagrant:vagrant' | chpasswd) && \ 15 | if [[ -d /etc/sudoers.d ]]; then SUDOERS=/etc/sudoers.d/vagrant; rm -f "$SUDOERS"; else SUDOERS=/etc/sudoers; fi && \ 16 | (echo 'vagrant ALL = NOPASSWD: ALL' >> "$SUDOERS" && chmod 440 "$SUDOERS" && chown root:root "$SUDOERS") && \ 17 | (mkdir -p /home/vagrant/.ssh && chmod 700 /home/vagrant/.ssh) && \ 18 | (mkdir -p /vagrant && chown -R vagrant:vagrant /vagrant) && \ 19 | (echo ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzIw+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoPkcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NOTd0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcWyLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQ== vagrant insecure public key > /home/vagrant/.ssh/authorized_keys && chmod 600 /home/vagrant/.ssh/authorized_keys) && \ 20 | chmod 600 /home/vagrant/.ssh/authorized_keys && \ 21 | chown -R vagrant:vagrant /home/vagrant/.ssh && \ 22 | mkdir -p /run/sshd && \ 23 | sed -i -e 's/Defaults.*requiretty/#&/' /etc/sudoers && \ 24 | sed -i -e 's/#\?\(UsePAM \).*/\1 no/' /etc/ssh/sshd_config && \ 25 | sed -i -e 's/#\?\(UseDNS \).*/\1 no/' /etc/ssh/sshd_config && \ 26 | sed -i -e 's/#\?\(GSSAPIAuthentication \).*/\1 no/' /etc/ssh/sshd_config && \ 27 | sed -i -e 's/#\?\(PermitRootLogin \).*/\1 without-password/' /etc/ssh/sshd_config && \ 28 | (if ! [[ -f /etc/ssh/ssh_host_rsa_key ]]; then \ 29 | ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key; \ 30 | ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key; \ 31 | fi) 32 | return $? 33 | } 34 | 35 | if ( which apt-get ); then 36 | apt-get -y update && apt-get -y install sudo && apt-get -y install openssh-server && generic 37 | exit $? 38 | fi 39 | 40 | if ( which yum ); then 41 | yum -y update && yum -y install sudo && yum -y install openssh-server openssh-clients && generic 42 | exit $? 43 | fi 44 | -------------------------------------------------------------------------------- /python/docker/devel/sources.list: -------------------------------------------------------------------------------- 1 | deb http://http.debian.net/debian buster main contrib non-free 2 | deb http://security.debian.org/ buster/updates main contrib non-free 3 | deb-src http://security.debian.org/ buster/updates main contrib non-free -------------------------------------------------------------------------------- /python/docker/docker-common.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -v 4 | set -x 5 | 6 | # Running this script at the start of a Dockerfile will allow vagrant ssh to correctly work with that machine 7 | # Should work for apt (debian) or yum (centos) based distributions 8 | # We use this because vagrant ssh is a more convenient workflow than `docker attach` 9 | 10 | function generic { 11 | 12 | groupadd -g 1000 vagrant && \ 13 | useradd --create-home -s /bin/bash -u 1000 -g 1000 vagrant && \ 14 | (echo 'vagrant:vagrant' | chpasswd) && \ 15 | if [[ -d /etc/sudoers.d ]]; then SUDOERS=/etc/sudoers.d/vagrant; rm -f "$SUDOERS"; else SUDOERS=/etc/sudoers; fi && \ 16 | (echo 'vagrant ALL = NOPASSWD: ALL' >> "$SUDOERS" && chmod 440 "$SUDOERS" && chown root:root "$SUDOERS") && \ 17 | (mkdir -p /home/vagrant/.ssh && chmod 700 /home/vagrant/.ssh) && \ 18 | (mkdir -p /vagrant && chown -R vagrant:vagrant /vagrant) && \ 19 | (echo ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzIw+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoPkcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NOTd0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcWyLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQ== vagrant insecure public key > /home/vagrant/.ssh/authorized_keys && chmod 600 /home/vagrant/.ssh/authorized_keys) && \ 20 | chmod 600 /home/vagrant/.ssh/authorized_keys && \ 21 | chown -R vagrant:vagrant /home/vagrant/.ssh && \ 22 | mkdir -p /run/sshd && \ 23 | sed -i -e 's/Defaults.*requiretty/#&/' /etc/sudoers && \ 24 | sed -i -e 's/#\?\(UsePAM \).*/\1 no/' /etc/ssh/sshd_config && \ 25 | sed -i -e 's/#\?\(UseDNS \).*/\1 no/' /etc/ssh/sshd_config && \ 26 | sed -i -e 's/#\?\(GSSAPIAuthentication \).*/\1 no/' /etc/ssh/sshd_config && \ 27 | sed -i -e 's/#\?\(PermitRootLogin \).*/\1 without-password/' /etc/ssh/sshd_config && \ 28 | (if ! [[ -f /etc/ssh/ssh_host_rsa_key ]]; then \ 29 | ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key; \ 30 | ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key; \ 31 | fi) 32 | return $? 33 | } 34 | 35 | if ( which apt-get ); then 36 | apt-get -y update && apt-get -y install sudo && apt-get -y install openssh-server && generic 37 | exit $? 38 | fi 39 | 40 | if ( which yum ); then 41 | yum -y update && yum -y install sudo && yum -y install openssh-server openssh-clients && generic 42 | exit $? 43 | fi 44 | -------------------------------------------------------------------------------- /python/docker/manylinux/Dockerfile: -------------------------------------------------------------------------------- 1 | # Get python builds from manylinux project 2 | FROM quay.io/pypa/manylinux1_x86_64:latest 3 | 4 | # Run common docker 5 | ADD docker-common.sh /docker-common.sh 6 | RUN bash docker-common.sh && rm -f docker-common.sh 7 | 8 | # manylinux is Centos/5 which does not work out of the box 9 | 10 | # Install development libraries 11 | RUN yum -y install \ 12 | which \ 13 | glibc-devel \ 14 | libstdc++-devel \ 15 | mlocate \ 16 | unzip \ 17 | zip \ 18 | gcc \ 19 | gcc-c++ \ 20 | zlib-devel 21 | 22 | # Get glibc-2.10 23 | RUN curl https://codeload.github.com/bminor/glibc/tar.gz/glibc-2.10 -o glibc.tar.gz && \ 24 | tar -xvf glibc.tar.gz && \ 25 | (rm -rf /opt/rh/devtoolset-2/ && yum remove -y devtoolset-2-*) || true 26 | 27 | # Compile glibc and extract object files 28 | RUN cd glibc-glibc-2.10/ && mkdir -p build && cd build && \ 29 | ../configure --prefix=/opt/glibc2.10 --enable-shared && \ 30 | make -j && \ 31 | make -j install && \ 32 | cp libc_pic.a /opt/glibc2.10/lib/ 33 | 34 | # Compile and install libuv 35 | RUN curl https://codeload.github.com/libuv/libuv/tar.gz/v1.10.2 -o libuv.tar.gz && \ 36 | yum -y install libtool && \ 37 | tar -xvf libuv.tar.gz && cd libuv-1.10.2 && \ 38 | sh autogen.sh && \ 39 | ./configure && \ 40 | make -j && \ 41 | make -j install 42 | 43 | # Compile and install newer Perl in order to compile openssl 44 | RUN curl -O http://www.cpan.org/src/perl-5.12.3.tar.gz && \ 45 | tar -xvf perl-5.12.3.tar.gz && \ 46 | cd perl-5.12.3 && \ 47 | ./Configure -des -Dprefix=/opt/perl5.12 && \ 48 | (make || true) && \ 49 | (make install || true) 50 | 51 | # Compile and install newest openssl 52 | RUN curl https://codeload.github.com/openssl/openssl/tar.gz/OpenSSL_1_1_1-pre2 -o openssl.tar.gz && \ 53 | tar -xvf openssl.tar.gz && \ 54 | cd openssl-OpenSSL_1_1_1-pre2/ && \ 55 | export PATH=/opt/perl5.12/bin/:$PATH && \ 56 | ./config --prefix=/opt/openssl --openssldir=/opt/openssl/usr/local/ssl && \ 57 | make -j && \ 58 | make -j install 59 | 60 | # Upgrade gcc and g++ but patch ld 61 | RUN curl https://people.centos.org/tru/devtools-2/devtools-2.repo -o /etc/yum.repos.d/devtools-2.repo && \ 62 | yum install -y devtoolset-2-gcc devtoolset-2-binutils devtoolset-2-gcc-c++ && \ 63 | mv /opt/rh/devtoolset-2/root/usr/libexec/gcc/x86_64-CentOS-linux/4.8.2/ld /opt/rh/devtoolset-2/root/usr/libexec/gcc/x86_64-CentOS-linux/4.8.2/ld.old 64 | 65 | ADD ld-patch.sh /opt/rh/devtoolset-2/root/usr/libexec/gcc/x86_64-CentOS-linux/4.8.2/ld 66 | 67 | RUN echo 'export MANYLINUX=yes' >> /etc/bashrc && \ 68 | echo 'export CC=/opt/rh/devtoolset-2/root/usr/bin/gcc' >> /etc/bashrc && \ 69 | echo 'export CXX=/opt/rh/devtoolset-2/root/usr/bin/g++' >> /etc/bashrc 70 | 71 | EXPOSE 22 72 | ENTRYPOINT ["/usr/sbin/sshd", "-D"] 73 | -------------------------------------------------------------------------------- /python/docker/manylinux/README.md: -------------------------------------------------------------------------------- 1 | Dockerfile based on PyPi manylinux https://github.com/pypa/manylinux 2 | 3 | manylinux1 is the PEP for portable linux python wheels. 4 | 5 | *Unfortunately* it is currently based on a Centos/5 build environment. 6 | It is likely that sooner or later, manylinux2 will come out, but until then, a number of hacks are required. 7 | 8 | This took a while to work out. 9 | 10 | Here's a brief description of issues with work arounds: 11 | 12 | 1. `openssl-devel` provides ancient openssl which results in undefined symbols 13 | * We download a newer openssl source, BUT: this requires Perl 5.10.0 to configure... 14 | * We download Perl 5.12 source and compile it first, then we can use that perl to... 15 | * Compile openssl from source, so we can link dynamically. This gives us the symbols and `auditwheel` will work out the rest. 16 | * (Apparently PyPi does this too on various `manylinux` wheels but they keep it a secret) 17 | 18 | 2. `libuv-devel` does not exist 19 | * We download and compile from source (1.1.0) , this surprisingly Just Works 20 | 21 | 3. `g++` does not support `--std=c++11` 22 | * Save some time and fix 4. first (using the existing Centos/5 toolchain), then come back to this. 23 | * Install `devtools-2` which gives us a newer g++ and gcc in `/opt` 24 | * Fool the devtools compilers by replacing their `ld` executable (!) 25 | * The devtools compilers pass an option (`--build-info`) which the system default doesn't understand, so 26 | we actually replace their ld with a wrapper script (!) which seds out (!!) the invalid argument (!!!) 27 | then calls the system default ld (!!!!) 28 | 29 | 4. Centos/5 glibc doesn't contain `eventfd` but nothing newer is supported by `auditwheel` 30 | * We are restricted to GLIB 2.5 or earlier 31 | * But nobody says we can't statically link with a newer glibc... 32 | * After reviewing commit history (and trying some versions), glibc 2.10 seems the safest 33 | * Compile glibc 2.10 with the original (system default) gcc 34 | 35 | 5. Various Linker Hacks 36 | * At this point we have three libc's on the system so understandably things get confusing 37 | * (setup.py)[../../setup.py] uses environment variable `MANYLINUX` to set a bunch of hacks. 38 | * (The linker wrapper script)[./ld-patch.sh] does more hacks 39 | 1. The devtools-2 compiler tries to use its own crtbegin/crtend/libc/libgcc so replace those with the system defaults 40 | If this is not done, the library loads properly, but `auditwheel` detects external references to `GLIBC_PRIVATE` 41 | 2. Statically link to the devtools-2 version of libstd++ 42 | 4. We need PIC glibc2.10 to statically link; fortunately this is an intermediate step so is left over in the build directory 43 | 5. PIC glibc2.10 leaves out a symbol which is in soinit.so, this is left in the build directory so pull it in 44 | 6. glibc2.10 causes multiple definitions from crti.o, so use the `-z muldefs` flag to discard repeated definitions (!!!!) 45 | 7. Due to our hack in 1. (or possibly 6 breaking something in crtend/crtn) we now get a segmentation fault on library _fini 46 | So, in `Bindings.cpp` we have a `MANYLINUX` define (set from (setup.py)[../../setup.py]) and we override the default `_fini` with it. 47 | * This `__wrap_fini` does absolutely nothing and no cleanup. 48 | * This is probably bad and is probably going to cause kernel memory leaks or some bizarre bugs 49 | 8. Statically link libssl, lz, luv, etcetera. 50 | Debatedly we shouldn't do this but in the spirit of `manylinux` "will work on any linux" we want it to run on linux without installing a bunch of development libraries. 51 | Especially since I just pulled the newest available libssl due to security concerns with older versions 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /python/docker/manylinux/docker-common.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -v 4 | set -x 5 | 6 | # Running this script at the start of a Dockerfile will allow vagrant ssh to correctly work with that machine 7 | # Should work for apt (debian) or yum (centos) based distributions 8 | # We use this because vagrant ssh is a more convenient workflow than `docker attach` 9 | 10 | function generic { 11 | 12 | groupadd -g 1000 vagrant && \ 13 | useradd --create-home -s /bin/bash -u 1000 -g 1000 vagrant && \ 14 | (echo 'vagrant:vagrant' | chpasswd) && \ 15 | if [[ -d /etc/sudoers.d ]]; then SUDOERS=/etc/sudoers.d/vagrant; rm -f "$SUDOERS"; else SUDOERS=/etc/sudoers; fi && \ 16 | (echo 'vagrant ALL = NOPASSWD: ALL' >> "$SUDOERS" && chmod 440 "$SUDOERS" && chown root:root "$SUDOERS") && \ 17 | (mkdir -p /home/vagrant/.ssh && chmod 700 /home/vagrant/.ssh) && \ 18 | (mkdir -p /vagrant && chown -R vagrant:vagrant /vagrant) && \ 19 | (echo ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzIw+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoPkcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NOTd0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcWyLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQ== vagrant insecure public key > /home/vagrant/.ssh/authorized_keys && chmod 600 /home/vagrant/.ssh/authorized_keys) && \ 20 | chmod 600 /home/vagrant/.ssh/authorized_keys && \ 21 | chown -R vagrant:vagrant /home/vagrant/.ssh && \ 22 | mkdir -p /run/sshd && \ 23 | sed -i -e 's/Defaults.*requiretty/#&/' /etc/sudoers && \ 24 | sed -i -e 's/#\?\(UsePAM \).*/\1 no/' /etc/ssh/sshd_config && \ 25 | sed -i -e 's/#\?\(UseDNS \).*/\1 no/' /etc/ssh/sshd_config && \ 26 | sed -i -e 's/#\?\(GSSAPIAuthentication \).*/\1 no/' /etc/ssh/sshd_config && \ 27 | sed -i -e 's/#\?\(PermitRootLogin \).*/\1 without-password/' /etc/ssh/sshd_config && \ 28 | (if ! [[ -f /etc/ssh/ssh_host_rsa_key ]]; then \ 29 | ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key; \ 30 | ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key; \ 31 | fi) 32 | return $? 33 | } 34 | 35 | if ( which apt-get ); then 36 | apt-get -y update && apt-get -y install sudo && apt-get -y install openssh-server && generic 37 | exit $? 38 | fi 39 | 40 | if ( which yum ); then 41 | yum -y update && yum -y install sudo && yum -y install openssh-server openssh-clients && generic 42 | exit $? 43 | fi 44 | -------------------------------------------------------------------------------- /python/docker/manylinux/ld-patch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | set -o pipefail 4 | args=$(echo $@ | sed -e 's/--build-id//g') 5 | #for f in crtbeginS.o crtendS.o crtbeginT.o; do 6 | # HACK_PATH="/opt/rh/devtoolset-2/root/usr/lib/gcc/x86_64-CentOS-linux/4.8.2/$f" 7 | # ORIG_PATH="/usr/lib/gcc/x86_64-redhat-linux/4.1.1/$f" 8 | # args=$(echo $args | sed -e "s%${HACK_PATH}%${ORIG_PATH}%g") 9 | #done 10 | #args=$(echo $args | sed -e "s%-L/opt/rh/devtoolset-2/root/usr/lib/gcc/x86_64-CentOS-linux/4.8.2\S*%%g") 11 | 12 | args="/usr/lib64/crti.o $args" 13 | args="/usr/lib/gcc/x86_64-redhat-linux/4.1.1/crtbeginS.o $args" 14 | args="$args /usr/lib/gcc/x86_64-redhat-linux/4.1.1/crtendS.o" 15 | args="$args /usr/lib64/crtn.o" 16 | args="$args --start-group -lc -lm -lpthread -lgcc_s -lc -lstdc++ --end-group" 17 | 18 | echo -e "\n\nRun linker:\t$args\n\n" 2>&1 | tee /vagrant/debug.ld 19 | ld $args --verbose 2>&1 | tee -a /vagrant/debug.ld 20 | -------------------------------------------------------------------------------- /python/docker/manylinux/link-options: -------------------------------------------------------------------------------- 1 | -nostartfiles 2 | -Bstatic 3 | -lc 4 | -lstdc++ 5 | -Bdynamic 6 | -lgcc 7 | -lc 8 | -Bstatic 9 | -lz 10 | -luv 11 | -lssl 12 | -lcrypto 13 | -z initfirst 14 | /glibc-glibc-2.10/build/elf/soinit.os 15 | /glibc-glibc-2.10/build/libc_pic.a 16 | --default-symver 17 | --version-script=/vagrant/manylinux.map 18 | -Bdynamic -------------------------------------------------------------------------------- /python/docker/test/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM centos:latest 2 | 3 | RUN yum -y install which 4 | 5 | # Run common docker 6 | ADD docker-common.sh /docker-common.sh 7 | RUN bash docker-common.sh && rm -f docker-common.sh 8 | 9 | RUN yum -y install epel-release 10 | RUN yum -y install python-pip 11 | 12 | EXPOSE 22 13 | ENTRYPOINT ["/usr/sbin/sshd", "-D"] 14 | -------------------------------------------------------------------------------- /python/docker/test/docker-common.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -v 4 | set -x 5 | 6 | # Running this script at the start of a Dockerfile will allow vagrant ssh to correctly work with that machine 7 | # Should work for apt (debian) or yum (centos) based distributions 8 | # We use this because vagrant ssh is a more convenient workflow than `docker attach` 9 | 10 | function generic { 11 | 12 | groupadd -g 1000 vagrant && \ 13 | useradd --create-home -s /bin/bash -u 1000 -g 1000 vagrant && \ 14 | (echo 'vagrant:vagrant' | chpasswd) && \ 15 | if [[ -d /etc/sudoers.d ]]; then SUDOERS=/etc/sudoers.d/vagrant; rm -f "$SUDOERS"; else SUDOERS=/etc/sudoers; fi && \ 16 | (echo 'vagrant ALL = NOPASSWD: ALL' >> "$SUDOERS" && chmod 440 "$SUDOERS" && chown root:root "$SUDOERS") && \ 17 | (mkdir -p /home/vagrant/.ssh && chmod 700 /home/vagrant/.ssh) && \ 18 | (mkdir -p /vagrant && chown -R vagrant:vagrant /vagrant) && \ 19 | (echo ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzIw+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoPkcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NOTd0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcWyLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQ== vagrant insecure public key > /home/vagrant/.ssh/authorized_keys && chmod 600 /home/vagrant/.ssh/authorized_keys) && \ 20 | chmod 600 /home/vagrant/.ssh/authorized_keys && \ 21 | chown -R vagrant:vagrant /home/vagrant/.ssh && \ 22 | mkdir -p /run/sshd && \ 23 | sed -i -e 's/Defaults.*requiretty/#&/' /etc/sudoers && \ 24 | sed -i -e 's/#\?\(UsePAM \).*/\1 no/' /etc/ssh/sshd_config && \ 25 | sed -i -e 's/#\?\(UseDNS \).*/\1 no/' /etc/ssh/sshd_config && \ 26 | sed -i -e 's/#\?\(GSSAPIAuthentication \).*/\1 no/' /etc/ssh/sshd_config && \ 27 | sed -i -e 's/#\?\(PermitRootLogin \).*/\1 without-password/' /etc/ssh/sshd_config && \ 28 | (if ! [[ -f /etc/ssh/ssh_host_rsa_key ]]; then \ 29 | ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key; \ 30 | ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key; \ 31 | fi) 32 | return $? 33 | } 34 | 35 | if ( which apt-get ); then 36 | apt-get -y update && apt-get -y install sudo && apt-get -y install openssh-server && generic 37 | exit $? 38 | fi 39 | 40 | if ( which yum ); then 41 | yum -y update && yum -y install sudo && yum -y install openssh-server openssh-clients && generic 42 | exit $? 43 | fi 44 | -------------------------------------------------------------------------------- /python/manylinux.map: -------------------------------------------------------------------------------- 1 | GLIBC_2.2.5 { 2 | global: 3 | __sigaction; 4 | _Exit; 5 | _IO_2_1_stdin_; _IO_2_1_stdout_; _IO_2_1_stderr_; 6 | _IO_adjust_column; _IO_clearerr; _IO_default_doallocate; 7 | _IO_adjust_wcolumn; _IO_free_wbackup_area; _IO_init_wmarker; 8 | _IO_default_finish; _IO_default_pbackfail; _IO_default_uflow; 9 | _IO_default_xsgetn; _IO_default_xsputn; _IO_do_write; 10 | _IO_do_write; _IO_file_attach; _IO_file_close_it; _IO_file_finish; 11 | _IO_doallocbuf; _IO_fclose; _IO_fdopen; _IO_feof; _IO_ferror; 12 | _IO_fclose; _IO_fopen; _IO_fdopen; _IO_popen; __asprintf; 13 | _IO_fflush; _IO_fgetc; _IO_fgetpos; _IO_fgets; _IO_file_attach; 14 | _IO_fgetpos; _IO_fgetpos64; _IO_fsetpos; _IO_fsetpos64; 15 | _IO_file_close; _IO_file_close_it; _IO_file_doallocate; 16 | _IO_file_fopen; _IO_file_init; _IO_file_jumps; _IO_file_open; 17 | _IO_file_fopen; _IO_file_init; _IO_file_overflow; _IO_file_seekoff; 18 | _IO_file_overflow; _IO_file_read; _IO_file_seek; _IO_file_seekoff; 19 | _IO_file_setbuf; _IO_file_stat; _IO_file_sync; _IO_file_underflow; 20 | _IO_file_setbuf; _IO_file_sync; _IO_file_underflow; 21 | _IO_file_write; _IO_file_xsputn; _IO_fileno; _IO_flockfile; 22 | _IO_file_write; _IO_file_xsputn; _IO_proc_open; _IO_proc_close; 23 | _IO_flush_all; _IO_flush_all_linebuffered; _IO_fopen; _IO_fprintf; 24 | _IO_fputs; _IO_fread; _IO_free_backup_area; _IO_freopen; 25 | _IO_fscanf; _IO_fseek; _IO_fsetpos; _IO_ftell; _IO_ftrylockfile; 26 | _IO_funlockfile; _IO_fwrite; _IO_getc; _IO_getline; _IO_gets; 27 | _IO_getc; _IO_peekc_unlocked; _IO_putc; _IO_feof; _IO_ferror; 28 | _IO_getline_info; 29 | _IO_init; _IO_init_marker; _IO_link_in; _IO_marker_delta; 30 | _IO_iter_begin; _IO_iter_end; _IO_iter_next; _IO_iter_file; 31 | _IO_least_wmarker; _IO_seekwmark; _IO_sputbackwc; _IO_sungetwc; 32 | _IO_list_all; _IO_stderr_; _IO_stdin_; _IO_stdout_; 33 | _IO_list_lock; _IO_list_unlock; _IO_list_resetlock; 34 | _IO_marker_difference; _IO_padn; _IO_pclose; _IO_peekc_locked; 35 | _IO_perror; _IO_popen; _IO_printf; _IO_proc_close; _IO_proc_open; 36 | _IO_putc; _IO_puts; _IO_remove_marker; _IO_rewind; _IO_scanf; 37 | _IO_seekmark; _IO_seekoff; _IO_seekpos; _IO_setb; _IO_setbuf; 38 | _IO_setbuffer; _IO_setlinebuf; _IO_setvbuf; _IO_sgetn; 39 | _IO_sprintf; _IO_sputbackc; _IO_sscanf; _IO_str_init_readonly; 40 | _IO_str_init_static; _IO_str_overflow; _IO_str_pbackfail; 41 | _IO_str_seekoff; _IO_str_underflow; _IO_sungetc; 42 | _IO_switch_to_get_mode; _IO_un_link; _IO_ungetc; 43 | _IO_switch_to_main_wget_area; _IO_switch_to_wbackup_area; 44 | _IO_switch_to_wget_mode; _IO_unsave_wmarkers; _IO_wdefault_doallocate; 45 | _IO_unsave_markers; _IO_vfprintf; _IO_vfscanf; _IO_vsprintf; 46 | _IO_wdefault_finish; _IO_wdefault_pbackfail; _IO_wdefault_setbuf; 47 | _IO_wdefault_uflow; _IO_wdefault_xsgetn; _IO_wdefault_xsputn; 48 | _IO_wdo_write; _IO_wfile_jumps; _IO_wfile_overflow; _IO_wfile_seekoff; 49 | _IO_wdoallocbuf; _IO_wmarker_delta; _IO_wsetb; __woverflow; __wuflow; 50 | _IO_wfile_setbuf; _IO_wfile_sync; _IO_wfile_underflow; _IO_wfile_xsputn; 51 | ___brk_addr; __curbrk; __progname; __progname_full; 52 | __adjtimex; 53 | __argz_count; __argz_stringify; __argz_next; 54 | __assert; 55 | __assert_fail; __assert_perror_fail; 56 | __backtrace; __backtrace_symbols; __backtrace_symbols_fd; 57 | __bsd_getpgrp; __setpgid; __getpgid; 58 | __bzero; __strtok_r; 59 | __clone; 60 | __cmsg_nxthdr; 61 | __connect; __send; 62 | __ctype32_tolower; __ctype32_toupper; 63 | __ctype_b; __ctype32_b; __ctype_tolower; __ctype_toupper; 64 | __ctype_get_mb_cur_max; 65 | __cxa_atexit; __cxa_finalize; 66 | __cyg_profile_func_enter; __cyg_profile_func_exit; 67 | __dcgettext; 68 | __dgettext; 69 | __dup2; __pipe; 70 | __endmntent; __getmntent_r; __setmntent; __statfs; __sysctl; 71 | __environ; _environ; 72 | __errno_location; 73 | __fbufsize; __freading; __fwriting; __freadable; __fwritable; __flbf; 74 | __ffs; 75 | __fpu_control; 76 | __fpurge; __fpending; __fsetlocking; _flushlbf; 77 | __getdelim; 78 | __gmtime_r; __gettimeofday; 79 | __h_errno_location; 80 | __isalnum_l; __isalpha_l; __isascii_l; __isblank_l; __iscntrl_l; 81 | __isdigit_l; __isgraph_l; __islower_l; __isprint_l; __ispunct_l; 82 | __isinf; __isinff; __isinfl; 83 | __isnan; __isnanf; __isnanl; __finite; __finitef; __finitel; 84 | __isspace_l; __isupper_l; __iswalnum_l; __iswalpha_l; __iswblank_l; 85 | __iswcntrl_l; __iswctype_l; __iswdigit_l; __iswgraph_l; __iswlower_l; 86 | __iswctype; 87 | __iswprint_l; __iswpunct_l; __iswspace_l; __iswupper_l; __iswxdigit_l; 88 | __isxdigit_l; __strcasecmp_l; __strcoll_l; __strfmon_l; __strncasecmp_l; 89 | __ivaliduser; __check_rhosts_file; __rcmd_errstr; 90 | __key_decryptsession_pk_LOCAL; __key_encryptsession_pk_LOCAL; 91 | __key_gendes_LOCAL; 92 | __libc_calloc; __libc_free; __libc_mallinfo; __libc_malloc; 93 | __libc_current_sigrtmin; __libc_current_sigrtmax; __libc_allocate_rtsig; 94 | __libc_freeres; 95 | __libc_init_first; __libc_start_main; 96 | __libc_mallopt; __libc_memalign; __libc_pvalloc; __libc_realloc; 97 | __libc_sa_len; 98 | __libc_valloc; 99 | __lseek; __open; __read; 100 | __malloc_initialize_hook; __free_hook; __malloc_hook; __realloc_hook; 101 | __malloc_initialized; __default_morecore; __morecore; 102 | __memalign_hook; __after_morecore_hook; 103 | __mempcpy_small; __stpcpy_small; __strcspn_c1; __strcspn_c2; __strcspn_c3; 104 | __monstartup; _mcleanup; __profile_frequency; 105 | __newlocale; __duplocale; __freelocale; 106 | __nl_langinfo_l; 107 | __nss_database_lookup; __nss_configure_lookup; 108 | __nss_hostname_digits_dots; 109 | __nss_passwd_lookup; __nss_group_lookup; __nss_hosts_lookup; __nss_next; 110 | __open64; 111 | __pread64; __pwrite64; 112 | __printf_fp; __vfscanf; 113 | __rawmemchr; __strcasestr; 114 | __res_randomid; 115 | __res_state; __res_init; __res_nclose; __res_ninit; _res_hconf; 116 | __rpc_thread_svc_fdset; __rpc_thread_createerr; 117 | __rpc_thread_svc_pollfd; __rpc_thread_svc_max_pollfd; 118 | __sbrk; __getpagesize; 119 | __sched_get_priority_max; __sched_get_priority_min; 120 | __sched_getparam; __sched_getscheduler; __sched_setscheduler; 121 | __sched_yield; __fork; __getpid; __wait; 122 | __secure_getenv; 123 | __select; 124 | __sigaddset; __sigdelset; __sigismember; __sysv_signal; 125 | __signbit; __signbitf; __signbitl; 126 | __sigpause; 127 | __sigsuspend; 128 | __stpncpy; __stpcpy; __strdup; __mempcpy; __strcasecmp; __strerror_r; 129 | __strcpy_small; __strspn_c1; __strspn_c2; __strspn_c3; __strpbrk_c2; 130 | __strndup; 131 | __strpbrk_c3; __strsep_1c; __strsep_2c; __strsep_3c; __strsep_g; 132 | __strto*_internal; 133 | __strtod_l; __strtof_l; __strtol_l; __strtold_l; __strtoll_l; __strtoul_l; 134 | __strtok_r_1c; 135 | __strtoull_l; __strxfrm_l; __toascii_l; __tolower_l; __toupper_l; 136 | __sysconf; 137 | __timezone; __daylight; __tzname; 138 | __towctrans; 139 | __towctrans_l; __towlower_l; __towupper_l; __wcscasecmp_l; __wcscoll_l; 140 | __uflow; __underflow; __overflow; 141 | __vfork; 142 | __vsscanf; __vsnprintf; 143 | __waitpid; 144 | __wcsncasecmp_l; __wcstod_l; __wcstof_l; __wcstol_l; __wcstold_l; 145 | __wcsto*_internal; __mbrlen; __mbrtowc; 146 | __wcstoll_l; __wcstoul_l; __wcstoull_l; __wcsxfrm_l; __wctype_l; 147 | __wctrans_l; 148 | __wunderflow; 149 | __xpg_basename; 150 | __xpg_sigpause; 151 | __xstat64; __fxstat64; __lxstat64; __poll; 152 | __xstat; __fxstat; __lxstat; __xmknod; __write; __close; __fcntl; 153 | _argp_unlock_xxx; 154 | _authenticate; 155 | _dl_mcount_wrapper; _dl_mcount_wrapper_check; 156 | _exit; 157 | _libc_intl_domainname; 158 | _longjmp; __sigsetjmp; _setjmp; 159 | _mcount; 160 | _nl_msg_cat_cntr; _nl_default_dirname; _nl_domain_bindings; 161 | _null_auth; 162 | _obstack; 163 | _obstack_allocated_p; _obstack_begin; _obstack_begin_1; 164 | _obstack_free; _obstack_memory_used; _obstack_newchunk; 165 | _res; 166 | _rpc_dtablesize; _seterr_reply; 167 | _sys_errlist; _sys_nerr; _sys_siglist; 168 | _sys_errlist; sys_errlist; _sys_nerr; sys_nerr; 169 | _sys_errlist; sys_errlist; _sys_nerr; sys_nerr; 170 | _sys_errlist; sys_errlist; _sys_nerr; sys_nerr; 171 | _sys_siglist; sys_siglist; sys_sigabbrev; 172 | _tolower; _toupper; 173 | a64l; abort; abs; atexit; atof; atoi; atol; atoll; 174 | accept; 175 | access; 176 | acct; addmntent; advance; 177 | addseverity; 178 | adjtime; adjtimex; asctime; asctime_r; 179 | alarm; 180 | alphasort64; 181 | alphasort; 182 | arch_prctl; __arch_prctl; 183 | argp_err_exit_status; argp_program_bug_address; argp_program_version; 184 | argp_error; argp_failure; argp_help; argp_parse; argp_state_help; 185 | argp_program_version_hook; 186 | argp_usage; 187 | argz_add; argz_add_sep; argz_append; argz_count; argz_create; 188 | argz_create_sep; argz_delete; argz_extract; argz_insert; argz_next; 189 | argz_replace; argz_stringify; 190 | asprintf; 191 | authdes_create; authdes_getucred; authdes_pk_create; 192 | authnone_create; authunix_create; authunix_create_default; 193 | backtrace; backtrace_symbols; backtrace_symbols_fd; 194 | basename; bcmp; bcopy; bzero; 195 | bdflush; 196 | bind; 197 | bind_textdomain_codeset; 198 | bindresvport; 199 | bindtextdomain; 200 | brk; 201 | bsd_signal; 202 | bsearch; 203 | btowc; 204 | calloc; cfree; 205 | callrpc; 206 | canonicalize_file_name; clearenv; 207 | capget; capset; 208 | catclose; catgets; catopen; 209 | cbc_crypt; clntunix_create; 210 | cfgetispeed; cfgetospeed; cfmakeraw; cfsetispeed; cfsetospeed; cfsetspeed; 211 | chdir; chmod; chown; close; creat; 212 | chflags; chroot; closelog; 213 | chown; 214 | clearerr; clearerr_unlocked; 215 | clnt_broadcast; clnt_create; clnt_pcreateerror; clnt_perrno; 216 | clnt_perror; clnt_spcreateerror; clnt_sperrno; clnt_sperror; 217 | clntraw_create; clnttcp_create; clntudp_bufcreate; clntudp_create; 218 | clock; ctime; ctime_r; 219 | clone; create_module; 220 | closedir; 221 | confstr; 222 | connect; 223 | copysign; copysignf; copysignl; 224 | creat64; 225 | ctermid; cuserid; 226 | daemon; dirname; 227 | daylight; timezone; tzname; 228 | dcgettext; dgettext; gettext; 229 | dcngettext; dngettext; 230 | delete_module; 231 | des_setparity; 232 | difftime; dysize; 233 | dirfd; 234 | div; drand48; drand48_r; 235 | dl_iterate_phdr; 236 | dprintf; 237 | dup; dup2; 238 | ecb_crypt; 239 | ecvt; ecvt_r; endfsent; endmntent; endttyent; endusershell; 240 | endaliasent; endhostent; endnetent; endnetgrent; endprotoent; endrpcent; 241 | endgrent; 242 | endpwent; 243 | endservent; 244 | endspent; 245 | endutent; 246 | endutxent; 247 | environ; optarg; opterr; optind; optopt; 248 | envz_add; envz_entry; envz_get; envz_merge; envz_remove; 249 | envz_strip; 250 | erand48; erand48_r; exit; 251 | err; error; error_at_line; errx; 252 | error_message_count; error_one_per_line; error_print_progname; 253 | ether_aton; ether_aton_r; ether_hostton; ether_line; ether_ntoa; 254 | ether_ntoa_r; ether_ntohost; 255 | euidaccess; 256 | execl; execle; execlp; execv; execve; execvp; fexecve; 257 | fattach; fdetach; 258 | fchdir; fchmod; fchown; fcntl; flock; fstatfs; fts_children; fts_close; 259 | fchflags; fcvt; fcvt_r; fdatasync; fsync; ftruncate; 260 | fclose; fcloseall; fdopen; feof; feof_locked; feof_unlocked; ferror; 261 | ferror_locked; ferror_unlocked; fflush; fflush_locked; fflush_unlocked; 262 | ffs; 263 | ffsl; ffsll; 264 | fgetc; fgetpos; fgets; fileno; fileno_locked; fileno_unlocked; 265 | fgetgrent; fgetgrent_r; 266 | fgetpos64; fopen64; freopen64; fseeko; fseeko64; fsetpos64; ftello; 267 | fgetpos; fgetpos64; fgetwc; fgetwc_unlocked; fgetws; fgetws_unlocked; 268 | fgetpwent; fgetpwent_r; 269 | fgets_unlocked; fputs_unlocked; fgetc_unlocked; 270 | fgetspent; fgetspent_r; 271 | finite; finitef; finitel; frexp; frexpf; frexpl; 272 | flockfile; fprintf; fscanf; ftrylockfile; funlockfile; 273 | fmtmsg; 274 | fnmatch; 275 | fnmatch; fork; fpathconf; freeaddrinfo; 276 | fopen; fopencookie; fputc; fputc_locked; fputc_unlocked; fputs; 277 | fputwc; fputwc_unlocked; fputws; fputws_unlocked; fsetpos; fsetpos64; 278 | fread; freopen; fseek; fsetpos; ftell; fwrite; 279 | free; 280 | fstatfs64; fstatvfs; fstatvfs64; ftw64; 281 | ftello64; fopen; fclose; fdopen; fread_unlocked; fwrite_unlocked; 282 | ftime; 283 | ftok; 284 | ftruncate64; 285 | fts_open; fts_read; fts_set; ftw; 286 | fwide; fwprintf; fwscanf; fopencookie; fmemopen; 287 | gai_strerror; getnameinfo; glob64; globfree64; 288 | gcvt; get_avphys_pages; get_nprocs; get_nprocs_conf; get_phys_pages; 289 | get_current_dir_name; getcwd; getwd; 290 | get_kernel_syms; getresgid; getresuid; 291 | get_myaddress; getpublickey; getsecretkey; 292 | getaddrinfo; getdtablesize; getegid; geteuid; getgid; getopt; getopt_long; 293 | getaliasbyname; getaliasbyname_r; getaliasent; getaliasent_r; 294 | getaliasbyname_r; getaliasent_r; gethostbyaddr_r; gethostbyname2_r; 295 | getc; getc_locked; getc_unlocked; getchar; getchar_unlocked; getdelim; 296 | getcontext; 297 | getdate; getdate_r; 298 | getdate_err; 299 | getdirentries64; 300 | getdirentries; 301 | getdomainname; gethostbyaddr; gethostbyaddr_r; gethostbyname; 302 | getenv; getsubopt; 303 | getfsent; getfsfile; getfsspec; gethostid; gethostname; getmntent; 304 | getgrent; getgrent_r; getgrgid; getgrgid_r; getgrnam; getgrnam_r; 305 | getgrent_r; getgrgid_r; getgrnam_r; 306 | getgrouplist; 307 | getgroups; 308 | gethostbyname2; gethostbyname2_r; gethostbyname_r; gethostent; 309 | gethostbyname_r; gethostent_r; getnetbyaddr_r; getnetbyname_r; 310 | gethostent_r; getnetbyaddr; getnetbyaddr_r; getnetbyname; 311 | getitimer; gettimeofday; gmtime; gmtime_r; 312 | getline; getw; 313 | getloadavg; 314 | getlogin; getlogin_r; getutent; getutent_r; getutid; getutid_r; getutline; 315 | getmntent_r; getpagesize; getpass; getttyent; getttynam; getusershell; 316 | getmsg; getpmsg; 317 | getnetbyname_r; getnetent; getnetent_r; getnetgrent; getnetgrent_r; 318 | getnetent_r; getnetgrent_r; getprotobyname_r; getprotobynumber_r; 319 | getnetname; 320 | getopt_long_only; getpgid; getpgrp; getpid; getppid; getsid; getuid; glob; 321 | getpeername; getsockname; getsockopt; 322 | getpriority; getrlimit; getrusage; 323 | getprotobyname; getprotobyname_r; getprotobynumber; 324 | getprotobynumber_r; getprotoent; getprotoent_r; getrpcbyname; 325 | getprotoent_r; getrpcbyname_r; getrpcbynumber_r; getrpcent_r; 326 | getpt; getutxent; getutxid; getutxline; grantpt; 327 | getpw; getpwent; getpwent_r; getpwnam; getpwnam_r; getpwuid; getpwuid_r; 328 | getpwent_r; getpwuid_r; getpwnam_r; 329 | getrlimit64; 330 | getrpcbyname_r; getrpcbynumber; getrpcbynumber_r; getrpcent; getrpcent_r; 331 | getrpcport; getservbyname; getservbyname_r; getservbyport; 332 | gets; 333 | getservbyname_r; 334 | getservbyport_r; getservent; getservent_r; 335 | getspent; getspent_r; getspnam; getspnam_r; 336 | getspent_r; getspnam_r; 337 | getutline_r; 338 | getutmpx; getutmp; 339 | getwc; getwc_unlocked; getwchar; getwchar_unlocked; 340 | glob_pattern_p; globfree; group_member; 341 | gnu_get_libc_release; gnu_get_libc_version; 342 | gsignal; 343 | gtty; 344 | h_errlist; h_nerr; 345 | hasmntopt; hcreate; hcreate_r; hdestroy; hdestroy_r; hsearch; hsearch_r; 346 | herror; hstrerror; 347 | host2netname; 348 | htonl; htons; 349 | iconv_open; iconv; iconv_close; 350 | if_freenameindex; if_indextoname; if_nameindex; if_nametoindex; 351 | imaxabs; imaxdiv; 352 | in6addr_any; in6addr_loopback; 353 | index; 354 | inet_addr; inet_aton; inet_lnaof; inet_makeaddr; inet_netof; inet_network; 355 | inet_nsap_addr; inet_nsap_ntoa; inet_ntoa; inet_ntop; inet_pton; innetgr; 356 | init_module; 357 | initgroups; 358 | initstate; initstate_r; 359 | insque; ioctl; 360 | ioperm; iopl; 361 | iruserok; 362 | iruserok_af; 363 | isalnum; isalpha; isascii; isblank; iscntrl; isdigit; isgraph; islower; 364 | isastream; 365 | isatty; 366 | isfdtype; 367 | isinf; isinff; isinfl; isnan; isnanf; isnanl; ldexp; ldexpf; ldexpl; 368 | isprint; ispunct; isspace; isupper; isxdigit; 369 | iswalnum; iswalpha; iswcntrl; iswctype; iswdigit; iswgraph; iswlower; 370 | iswblank; 371 | iswprint; iswpunct; iswspace; iswupper; iswxdigit; 372 | jrand48; jrand48_r; lfind; lsearch; 373 | key_decryptsession; key_decryptsession_pk; key_encryptsession; 374 | key_encryptsession_pk; key_gendes; key_get_conv; key_secretkey_is_set; 375 | key_setnet; key_setsecret; 376 | kill; killpg; 377 | klogctl; 378 | l64a; labs; lcong48; lcong48_r; ldiv; llabs; lldiv; lrand48; lrand48_r; 379 | lchown; link; lockf; lseek; 380 | lckpwdf; 381 | listen; 382 | llseek; 383 | loc1; loc2; locs; 384 | localeconv; 385 | localeconv; 386 | localtime; localtime_r; 387 | lockf64; lseek64; 388 | longjmp; 389 | madvise; mkstemp; mktemp; mlock; mlockall; mmap; mount; mprotect; msync; 390 | makecontext; 391 | mallinfo; malloc; malloc_get_state; malloc_set_state; malloc_stats; 392 | malloc_trim; malloc_usable_size; mallopt; memalign; mprobe; mtrace; 393 | mallwatch; obstack_alloc_failed_handler; obstack_exit_failure; 394 | mblen; mbrlen; mbrtowc; mbsinit; mbsnrtowcs; mbsrtowcs; mbstowcs; 395 | mbtowc; mcheck; mcount; mrand48; mrand48_r; 396 | mcheck_check_all; mcheck_pedantic; 397 | memccpy; memchr; memcmp; memcpy; memfrob; memmem; memmove; memset; 398 | mempcpy; 399 | memrchr; 400 | mincore; mkdtemp; mkstemp64; 401 | mkdir; mkfifo; 402 | mktime; 403 | mmap64; 404 | modf; modff; modfl; 405 | modify_ldt; 406 | moncontrol; 407 | monstartup; 408 | mremap; 409 | msgctl; msgget; msgrcv; msgsnd; 410 | munlock; munlockall; munmap; 411 | muntrace; 412 | nanosleep; 413 | netname2host; netname2user; 414 | nfsservctl; 415 | nftw; nftw64; 416 | ngettext; 417 | nice; 418 | nl_langinfo; 419 | nrand48; nrand48_r; 420 | ntohl; ntohs; 421 | ntp_adjtime; ntp_gettime; 422 | obstack_free; 423 | on_exit; 424 | open64; 425 | open; 426 | open_memstream; open_obstack_stream; obstack_printf; obstack_vprintf; 427 | opendir; 428 | openlog; 429 | parse_printf_format; perror; printf; putw; 430 | passwd2des; 431 | pathconf; pause; pselect; 432 | pclose; popen; 433 | pclose; popen; putc; putc_locked; putc_unlocked; putchar; 434 | personality; prctl; 435 | pipe; poll; 436 | pivot_root; 437 | pmap_getmaps; pmap_getport; pmap_rmtcall; pmap_set; pmap_unset; 438 | posix_fadvise; posix_fadvise64; posix_fallocate; posix_fallocate64; 439 | posix_madvise; 440 | posix_memalign; 441 | posix_openpt; 442 | posix_spawn; posix_spawnp; posix_spawnattr_getschedpolicy; 443 | posix_spawn_file_actions_addclose; posix_spawn_file_actions_addopen; 444 | posix_spawn_file_actions_adddup2; 445 | posix_spawn_file_actions_init; posix_spawn_file_actions_destroy; 446 | posix_spawnattr_getflags; posix_spawnattr_setflags; 447 | posix_spawnattr_getpgroup; posix_spawnattr_setpgroup; 448 | posix_spawnattr_getsigdefault; posix_spawnattr_setsigdefault; 449 | posix_spawnattr_init; posix_spawnattr_destroy; 450 | posix_spawnattr_setschedparam; 451 | posix_spawnattr_setschedpolicy; posix_spawnattr_getschedparam; 452 | posix_spawnattr_setsigmask; posix_spawnattr_getsigmask; 453 | pread; pread64; pwrite; pwrite64; 454 | printf_size; printf_size_info; 455 | profil; profil_counter; 456 | program_invocation_name; program_invocation_short_name; 457 | psignal; 458 | pthread_attr_destroy; pthread_attr_init; 459 | pthread_attr_getdetachstate; pthread_attr_setdetachstate; 460 | pthread_attr_getinheritsched; pthread_attr_setinheritsched; 461 | pthread_attr_getschedparam; pthread_attr_setschedparam; 462 | pthread_attr_getschedpolicy; pthread_attr_setschedpolicy; 463 | pthread_attr_getscope; pthread_attr_setscope; 464 | pthread_attr_init; 465 | pthread_attr_init; 466 | pthread_cond_broadcast; pthread_cond_destroy; 467 | pthread_cond_init; pthread_cond_signal; pthread_cond_wait; 468 | pthread_cond_timedwait; 469 | pthread_condattr_destroy; pthread_condattr_init; 470 | pthread_equal; pthread_exit; 471 | pthread_getschedparam; pthread_setschedparam; 472 | pthread_mutex_destroy; pthread_mutex_init; 473 | pthread_mutex_lock; pthread_mutex_unlock; 474 | pthread_self; 475 | pthread_setcancelstate; pthread_setcanceltype; 476 | ptrace; 477 | ptsname; ptsname_r; pututxline; 478 | putchar_unlocked; puts; 479 | putenv; 480 | putgrent; 481 | putmsg; putpmsg; 482 | putpwent; setpwent; 483 | putspent; 484 | pututline; 485 | putwc; putwc_unlocked; putwchar; putwchar_unlocked; 486 | pvalloc; 487 | qecvt; qecvt_r; qfcvt; qfcvt_r; qgcvt; 488 | qsort; 489 | query_module; quotactl; 490 | raise; 491 | rand; rand_r; random; random_r; realpath; rpmatch; 492 | rawmemchr; 493 | rcmd; rexec; rresvport; ruserok; ruserpass; 494 | rcmd_af; rexec_af; rresvport_af; ruserok_af; 495 | re_comp; re_compile_fastmap; re_compile_pattern; re_exec; re_match; 496 | re_match_2; re_search; re_search_2; re_set_registers; re_set_syntax; 497 | re_max_failures; re_syntax_options; 498 | read; readlink; rmdir; 499 | readdir64; readdir64_r; 500 | readdir; readdir_r; rewinddir; 501 | readv; reboot; remque; revoke; 502 | realloc; 503 | recv; recvfrom; recvmsg; 504 | regcomp; regerror; regexec; regfree; 505 | register_printf_function; remove; rename; 506 | registerrpc; 507 | res_init; 508 | rewind; 509 | rexecoptions; 510 | rindex; 511 | rpc_createerr; svc_fdset; svcauthdes_stats; 512 | rtime; 513 | sbrk; select; setdomainname; setfsent; sethostent; sethostid; sethostname; 514 | scalbln; scalblnf; scalblnl; 515 | scalbn; scalbnf; scalbnl; 516 | scandir64; 517 | scandir; seekdir; 518 | scanf; snprintf; sprintf; sscanf; 519 | sched_get_priority_max; sched_get_priority_min; sched_getparam; 520 | sched_getscheduler; sched_rr_get_interval; sched_setparam; 521 | sched_setscheduler; sched_yield; setegid; seteuid; setgid; setlogin; 522 | seed48; seed48_r; setcontext; setenv; setstate; setstate_r; srand; srand48; 523 | semctl; semget; semop; shmat; shmctl; shmdt; shmget; 524 | semctl; shmctl; msgctl; 525 | send; sendmsg; sendto; setsockopt; shutdown; socket; socketpair; 526 | sendfile; 527 | setaliasent; setnetent; setnetgrent; setprotoent; setrpcent; setservent; 528 | setbuf; setbuffer; setlinebuf; setvbuf; 529 | setfsgid; setfsuid; 530 | setgrent; setgroups; 531 | setitimer; settimeofday; stime; strftime; strptime; 532 | setjmp; 533 | setlocale; 534 | setlogmask; setmntent; setregid; setreuid; setttyent; setusershell; sstk; 535 | setpgid; setpgrp; setsid; setuid; sleep; sysconf; 536 | setpriority; setrlimit; 537 | setresgid; setresuid; swapoff; swapon; sysctl; 538 | setrlimit64; 539 | setspent; 540 | setutent; 541 | setutxent; 542 | sgetspent; sgetspent_r; 543 | sigaction; sigaddset; sigaltstack; sigandset; sigblock; sigdelset; 544 | sigemptyset; sigfillset; siggetmask; siginterrupt; sigisemptyset; 545 | sighold; sigrelse; sigignore; sigset; sysv_signal; 546 | sigismember; siglongjmp; signal; sigorset; sigpause; sigpending; 547 | sigprocmask; sigreturn; sigsetmask; sigstack; sigsuspend; sigvec; 548 | sigqueue; sigtimedwait; sigwaitinfo; 549 | sigwait; ssignal; 550 | sockatmark; 551 | sprofil; 552 | srand48_r; srandom; srandom_r; step; strfmon; strtod; strtof; strtol; 553 | statfs64; statvfs; statvfs64; 554 | statfs; symlink; 555 | stderr; stdin; stdout; 556 | stpcpy; stpncpy; strcasecmp; strcat; strchr; strcmp; strcoll; strcpy; 557 | strcasestr; strverscmp; 558 | strchrnul; __strverscmp; 559 | strcspn; strdup; strerror; strerror_r; strfry; strlen; strncasecmp; 560 | strncat; strncmp; strncpy; strndup; strnlen; strpbrk; strrchr; strsep; 561 | strsignal; strspn; strstr; strtok; strtok_r; strxfrm; swab; 562 | strtoimax; strtoumax; swapcontext; 563 | strtold; strtoll; strtoq; strtoul; strtoull; strtouq; system; 564 | stty; sync; syscall; syslog; 565 | svc_exit; svc_getreq; svc_getreqset; svc_register; svc_run; 566 | svc_getreq_common; svc_getreq_poll; svc_max_pollfd; svc_pollfd; 567 | svc_sendreply; svc_unregister; svcerr_auth; svcerr_decode; 568 | svcerr_noproc; svcerr_noprog; svcerr_progvers; svcerr_systemerr; 569 | svcerr_weakauth; svcfd_create; svcraw_create; svctcp_create; 570 | svcudp_bufcreate; svcudp_create; svcudp_enablecache; 571 | svcunix_create; svcunixfd_create; 572 | swprintf; swscanf; 573 | sys_errlist; sys_nerr; sys_sigabbrev; sys_siglist; 574 | sysinfo; 575 | tcdrain; tcflow; tcflush; tcgetattr; tcgetpgrp; tcsendbreak; tcsetattr; 576 | tcgetsid; 577 | tcsetpgrp; 578 | tdelete; tfind; truncate; tsearch; ttyslot; twalk; 579 | tdestroy; truncate64; 580 | telldir; 581 | tempnam; tmpfile; tmpnam; tmpnam_r; 582 | textdomain; 583 | time; timegm; timelocal; tzset; 584 | times; 585 | tmpfile; tmpfile64; 586 | toascii; tolower; toupper; 587 | towctrans; towlower; towupper; 588 | tr_break; 589 | ttyname; ttyname_r; 590 | ualarm; usleep; ustat; utimes; 591 | ulckpwdf; 592 | ulimit; 593 | umask; unlink; utime; 594 | umount2; 595 | umount; uselib; 596 | uname; 597 | ungetc; 598 | ungetwc; 599 | unlockpt; updwtmpx; utmpxname; 600 | unsetenv; 601 | updwtmp; utmpname; 602 | user2netname; 603 | valloc; 604 | vasprintf; vdprintf; vscanf; vsnprintf; vsprintf; vsscanf; 605 | verr; verrx; vhangup; vsyslog; vwarn; vwarnx; 606 | versionsort; versionsort64; 607 | vfork; 608 | vfprintf; vfscanf; vprintf; 609 | vfwprintf; vswprintf; vwprintf; vfwscanf; vswscanf; vwscanf; 610 | vlimit; vtimes; 611 | wait; wait3; wait4; waitpid; 612 | waitid; wordexp; wordfree; 613 | warn; warnx; 614 | wcpcpy; wcpncpy; wcrtomb; wcscat; wcschr; wcscmp; wcscoll; 615 | wcscasecmp; wcsncasecmp; wcsnlen; wcstoll; 616 | wcschrnul; wmempcpy; 617 | wcscpy; wcscspn; wcsdup; wcslen; wcsncat; wcsncmp; 618 | wcsftime; 619 | wcsncpy; wcsnrtombs; wcspbrk; wcsrchr; wcsrtombs; wcsspn; wcsstr; 620 | wcstod; wcstof; wcstok; wcstol; wcstold; wcstoq; wcstoul; 621 | wcstoimax; wcstoumax; wcstoull; wcswcs; wmemrtombs; wmemrtowcs; 622 | wcstombs; wctomb; 623 | wcstouq; wcswidth; wcsxfrm; wctob; 624 | wctrans; wctype; wcwidth; 625 | wmemchr; wmemcmp; wmemcpy; wmemmove; wmemset; 626 | wprintf; wscanf; 627 | write; 628 | writev; 629 | xdecrypt; xdr_authdes_cred; xdr_authdes_verf; 630 | xdr_accepted_reply; xdr_array; xdr_authunix_parms; xdr_bool; xdr_bytes; 631 | xdr_callhdr; xdr_callmsg; xdr_char; xdr_cryptkeyarg; xdr_cryptkeyarg2; 632 | xdr_cryptkeyres; xdr_des_block; xdr_double; xdr_enum; xdr_float; 633 | xdr_free; xdr_int; xdr_key_netstarg; xdr_key_netstres; xdr_keybuf; 634 | xdr_getcredres; xdr_int16_t; xdr_int32_t; xdr_int8_t; 635 | xdr_hyper; xdr_u_hyper; xdr_longlong_t; xdr_u_longlong_t; 636 | xdr_int64_t; xdr_uint64_t; 637 | xdr_keystatus; xdr_long; xdr_netobj; xdr_opaque; xdr_opaque_auth; 638 | xdr_netnamestr; xdr_sizeof; 639 | xdr_pmap; xdr_pmaplist; xdr_pointer; xdr_reference; xdr_rejected_reply; 640 | xdr_replymsg; xdr_rmtcall_args; xdr_rmtcallres; xdr_short; xdr_string; 641 | xdr_u_char; xdr_u_int; xdr_u_long; xdr_u_short; xdr_union; xdr_vector; 642 | xdr_uint16_t; xdr_uint32_t; xdr_uint8_t; xdr_unixcred; 643 | xdr_void; xdr_wrapstring; xdrmem_create; xdrrec_create; 644 | xdrrec_endofrecord; xdrrec_eof; xdrrec_skiprecord; xdrstdio_create; 645 | xencrypt; xprt_register; xprt_unregister; 646 | local: 647 | *; 648 | }; 649 | GLIBC_2.2.6 { 650 | global: 651 | __nanosleep; 652 | } GLIBC_2.2.5; 653 | GLIBC_2.3 { 654 | global: 655 | __ctype_b_loc; __ctype_tolower_loc; __ctype_toupper_loc; 656 | __strftime_l; __wcsftime_l; 657 | __uselocale; 658 | _sys_errlist; sys_errlist; _sys_nerr; sys_nerr; 659 | fgetxattr; flistxattr; fremovexattr; fsetxattr; 660 | freeifaddrs; 661 | futimes; 662 | getifaddrs; 663 | getxattr; 664 | isalnum_l; isalpha_l; isascii_l; isblank_l; iscntrl_l; 665 | isctype; __isctype; 666 | isdigit_l; isgraph_l; islower_l; isprint_l; ispunct_l; 667 | isspace_l; isupper_l; iswalnum_l; iswalpha_l; iswblank_l; 668 | iswcntrl_l; iswctype_l; iswdigit_l; iswgraph_l; iswlower_l; 669 | iswprint_l; iswpunct_l; iswspace_l; iswupper_l; iswxdigit_l; 670 | isxdigit_l; strcasecmp_l; strcoll_l; strfmon_l; strncasecmp_l; 671 | lgetxattr; llistxattr; lremovexattr; lsetxattr; 672 | listxattr; 673 | lutimes; 674 | newlocale; duplocale; freelocale; uselocale; 675 | readahead; 676 | realpath; 677 | removexattr; 678 | sendfile64; 679 | setxattr; 680 | strftime_l; 681 | strtod_l; strtof_l; strtol_l; strtold_l; strtoul_l; 682 | strxfrm_l; toascii_l; tolower_l; toupper_l; 683 | towctrans_l; towlower_l; towupper_l; wcscasecmp_l; wcscoll_l; 684 | wcsftime_l; 685 | wcsncasecmp_l; wcstod_l; wcstof_l; wcstol_l; wcstold_l; 686 | wcstoll_l; wcstoul_l; wcstoull_l; wcsxfrm_l; wctype_l; 687 | wctrans_l; nl_langinfo_l; 688 | } GLIBC_2.2.6; 689 | GLIBC_2.3.2 { 690 | global: 691 | __register_atfork; 692 | epoll_create; epoll_ctl; epoll_wait; 693 | getresuid; getresgid; setresuid; setresgid; 694 | lchmod; 695 | pthread_cond_broadcast; pthread_cond_timedwait; 696 | pthread_cond_init; pthread_cond_destroy; 697 | pthread_cond_wait; pthread_cond_signal; 698 | strptime_l; 699 | } GLIBC_2.3; 700 | GLIBC_2.3.3 { 701 | global: 702 | gnu_dev_major; gnu_dev_minor; gnu_dev_makedev; 703 | inet6_option_alloc; inet6_option_next; inet6_option_find; 704 | inet6_option_space; inet6_option_init; inet6_option_append; 705 | nftw; nftw64; 706 | remap_file_pages; 707 | sched_getaffinity; sched_setaffinity; 708 | semtimedop; 709 | strtoll_l; strtoull_l; 710 | } GLIBC_2.3.2; 711 | GLIBC_2.3.4 { 712 | global: 713 | __chk_fail; 714 | __gets_chk; 715 | __memcpy_chk; __memmove_chk; __mempcpy_chk; __memset_chk; __stpcpy_chk; 716 | __printf_chk; __fprintf_chk; __vprintf_chk; __vfprintf_chk; 717 | __sprintf_chk; __vsprintf_chk; __snprintf_chk; __vsnprintf_chk; 718 | __strcat_chk; __strcpy_chk; __strncat_chk; __strncpy_chk; 719 | __xpg_strerror_r; 720 | getipv4sourcefilter; setipv4sourcefilter; 721 | getsourcefilter; setsourcefilter; 722 | regexec; 723 | sched_getaffinity; sched_setaffinity; 724 | xdr_quad_t; xdr_u_quad_t; 725 | } GLIBC_2.3.3; 726 | GLIBC_2.4 { 727 | global: 728 | __confstr_chk; __getgroups_chk; __ttyname_r_chk; __getlogin_r_chk; 729 | __fgets_chk; __fgets_unlocked_chk; 730 | __fxstatat; __fxstatat64; 731 | __gethostname_chk; __getdomainname_chk; __wcrtomb_chk; __mbsnrtowcs_chk; 732 | __read_chk; __pread_chk; __pread64_chk; 733 | __readlink_chk; __getcwd_chk; __getwd_chk; 734 | __realpath_chk; __ptsname_r_chk; __wctomb_chk; 735 | __recv_chk; __recvfrom_chk; 736 | __stack_chk_fail; 737 | __stpncpy_chk; 738 | __swprintf_chk; __vswprintf_chk; __wprintf_chk; __fwprintf_chk; 739 | __syslog_chk; __vsyslog_chk; 740 | __vwprintf_chk; __vfwprintf_chk; __fgetws_chk; __fgetws_unlocked_chk; 741 | __wcscpy_chk; __wmemcpy_chk; __wmemmove_chk; __wmempcpy_chk; __wcpcpy_chk; 742 | __wcsncpy_chk; __wcscat_chk; __wcsncat_chk; __wmemset_chk; __wcpncpy_chk; 743 | __wcsnrtombs_chk; __mbsrtowcs_chk; __wcsrtombs_chk; __mbstowcs_chk; 744 | __wcstombs_chk; 745 | _sys_errlist; sys_errlist; _sys_nerr; sys_nerr; 746 | eaccess; 747 | faccessat; 748 | fchmodat; 749 | fchownat; 750 | fdopendir; 751 | futimesat; 752 | inotify_init; inotify_add_watch; inotify_rm_watch; 753 | linkat; 754 | mkdirat; mkfifoat; __xmknodat; 755 | open_wmemstream; 756 | openat; openat64; 757 | ppoll; 758 | readlinkat; 759 | renameat; 760 | symlinkat; 761 | unlinkat; 762 | unshare; 763 | } GLIBC_2.3.4; 764 | GLIBC_2.5 { 765 | global: 766 | __readlinkat_chk; 767 | inet6_opt_init; inet6_opt_append; inet6_opt_finish; inet6_opt_set_val; 768 | inet6_opt_next; inet6_opt_find; inet6_opt_get_val; 769 | inet6_rth_segments; inet6_rth_getaddr; 770 | inet6_rth_space; inet6_rth_init; inet6_rth_add; inet6_rth_reverse; 771 | splice; tee; vmsplice; 772 | } GLIBC_2.4; 773 | GLIBC_2.6 { 774 | global: 775 | __sched_cpucount; 776 | epoll_pwait; sync_file_range; sched_getcpu; 777 | strerror_l; 778 | utimensat; futimens; 779 | } GLIBC_2.5; 780 | GLIBC_2.7 { 781 | global: 782 | __fread_chk; __fread_unlocked_chk; 783 | __isoc99_scanf; __isoc99_vscanf; __isoc99_fscanf; __isoc99_vfscanf; 784 | __isoc99_sscanf; __isoc99_vsscanf; 785 | __isoc99_swscanf; __isoc99_vswscanf; 786 | __isoc99_wscanf; __isoc99_vwscanf; __isoc99_fwscanf; __isoc99_vfwscanf; 787 | __open_2; __open64_2; __openat_2; __openat64_2; 788 | __sched_cpualloc; __sched_cpufree; 789 | eventfd; eventfd_read; eventfd_write; signalfd; 790 | mkostemp; mkostemp64; 791 | } GLIBC_2.6; 792 | GLIBC_2.8 { 793 | global: 794 | __asprintf_chk; __vasprintf_chk; __dprintf_chk; __vdprintf_chk; 795 | __obstack_printf_chk; __obstack_vprintf_chk; 796 | qsort_r; 797 | timerfd_create; timerfd_settime; timerfd_gettime; 798 | } GLIBC_2.7; 799 | GLIBC_2.9 { 800 | local: 801 | dup3; pipe2; 802 | epoll_create1; inotify_init1; 803 | } GLIBC_2.8; 804 | GLIBC_2.10 { 805 | local: 806 | __posix_getopt; 807 | accept4; 808 | endsgent; 809 | fallocate; fallocate64; 810 | fgetsgent; fgetsgent_r; 811 | getsgent; getsgent_r; getsgnam; getsgnam_r; getsgent_r; getsgnam_r; 812 | malloc_info; 813 | preadv; preadv64; pwritev; pwritev64; 814 | psiginfo; 815 | putsgent; 816 | quick_exit; __cxa_at_quick_exit; 817 | register_printf_modifier; register_printf_type; register_printf_specifier; 818 | setsgent; 819 | sgetsgent; sgetsgent_r; 820 | } GLIBC_2.9; 821 | GLIBC_PRIVATE { 822 | global: 823 | __collate_element_hash; __collate_element_strings; 824 | __collate_symbol_classes; __collate_symbol_hash; __collate_symbol_strings; 825 | __fortify_fail; 826 | __gai_sigqueue; 827 | __gconv_get_alias_db; __gconv_get_modules_db; __gconv_get_cache; 828 | __internal_endnetgrent; __internal_getnetgrent_r; 829 | __internal_setnetgrent; 830 | __libc_allocate_rtsig_private; 831 | __libc_clntudp_bufcreate; 832 | __libc_current_sigrtmin_private; __libc_current_sigrtmax_private; 833 | __libc_dl_error_tsd; 834 | __libc_dlopen_mode; __libc_dlsym; __libc_dlclose; 835 | __libc_fatal; 836 | __libc_fork; __libc_pwrite; 837 | __libc_longjmp; __libc_siglongjmp; 838 | __libc_malloc_pthread_startup; 839 | __libc_msgrcv; __libc_msgsnd; 840 | __libc_pthread_init; 841 | __libc_system; 842 | __libc_thread_freeres; 843 | __nss_disable_nscd; __nss_lookup_function; _nss_files_parse_sgent; 844 | __nss_passwd_lookup2; __nss_group_lookup2; __nss_hosts_lookup2; 845 | __nss_services_lookup2; __nss_next2; 846 | __open_catalog; 847 | __res_maybe_init; __res_iclose; 848 | __syscall_rt_sigqueueinfo; 849 | __vdso_clock_gettime; 850 | _dl_addr; 851 | _dl_open_hook; 852 | _dl_sym; _dl_vsym; 853 | _itoa_lower_digits; 854 | _nss_files_parse_grent; _nss_files_parse_pwent; _nss_files_parse_spent; 855 | errno; 856 | h_errno; __resp; 857 | } GLIBC_2.10; 858 | 859 | UWS_0.14.6 { 860 | global: 861 | inituWebSockets; 862 | PyInit_uWebSockets; 863 | __wrap_atexit; 864 | }; 865 | -------------------------------------------------------------------------------- /python/setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | import shutil 3 | import sys 4 | import platform 5 | import ctypes 6 | arch = ctypes.sizeof(ctypes.c_voidp)*8 7 | 8 | 9 | #from distutils.core import setup, Extension 10 | from setuptools import setup, Extension 11 | 12 | upstream_dir = os.path.join(os.path.dirname(__file__),"uWebSockets", "src") 13 | if not os.path.exists(upstream_dir): 14 | shutil.copytree(os.path.join(os.path.dirname(__file__), "..", "uWebSockets"), os.path.join(os.path.dirname(__file__), "uWebSockets")) 15 | 16 | upstream_src = [os.path.join(upstream_dir, f) for f in os.listdir(upstream_dir) if f.split(".")[-1] in ("cpp", "cxx", "c")] 17 | upstream_headers = [os.path.join(upstream_dir, f) for f in os.listdir(upstream_dir) if f.split(".")[-1] in ("hpp", "hxx", "h")] 18 | 19 | extra_objects = [] 20 | platform_link_args = [] 21 | platform_include_dirs = [] 22 | platform_cflags = [] 23 | platform_libraries = ["ssl", "crypto", "z", "uv"] 24 | platform_defines = [] 25 | platform_package_data = {"uWebSockets":[]} 26 | 27 | if platform.system().lower() == "linux": 28 | platform_defines = [("UWS_THREADSAFE", 1)] # FIXME: Does not work on Windoze 29 | else: 30 | platform_defines = [] 31 | 32 | 33 | 34 | if platform.system().lower() == "windows": 35 | platform_libraries = [] 36 | platform_include_dirs += [os.path.join(os.path.dirname(__file__),"windows")] 37 | platform_include_dirs += [os.path.join("C:\\","Program Files (x86)", "libuv", "include")] 38 | 39 | platform_include_dirs += [os.path.join("C:\\", "zlib")] 40 | 41 | platform_libraries += ["legacy_stdio_definitions", "legacy_stdio_wide_specifiers"] 42 | platform_libraries += ["crypt32", "User32", "GDI32", "Advapi32"] 43 | platform_link_args += ["/LIBPATH:"+os.path.join(os.path.dirname(sys.executable),"..","..","..","libs")] 44 | platform_libraries += ["python%d%d" % (sys.version_info[0], sys.version_info[1])] 45 | platform_libraries += ["python%d" % (sys.version_info[0],)] 46 | 47 | 48 | platform_libraries += ["zlibstat"] 49 | 50 | platform_package_data["uWebSockets"] += ["libuv.dll"] 51 | platform_libraries += ["libuv"] 52 | 53 | 54 | platform_link_args += ["/NODEFAULTLIB:libc"] 55 | if arch == 32: 56 | platform_include_dirs += [os.path.join("C:\\","OpenSSL-Win32","include")] 57 | platform_link_args += ["/LIBPATH:"+os.path.join("C:\\","OpenSSL-Win32","lib", "VC", "static")] 58 | platform_link_args += ["/LIBPATH:"+os.path.join("C:\\","zlib", "static32")] 59 | platform_link_args += ["/LIBPATH:"+os.path.join("C:\\","Program Files (x86)", "libuv")] 60 | platform_libraries += ["libssl32MT", "libcrypto32MT"] 61 | _external_dlls = [os.path.join("C:\\", "Program Files (x86)","libuv", "libuv.dll")] 62 | 63 | elif arch == 64: 64 | platform_include_dirs += [os.path.join("C:\\","OpenSSL-Win64","include")] 65 | platform_link_args += ["/LIBPATH:"+os.path.join("C:\\","OpenSSL-Win64","lib", "VC", "static")] 66 | platform_link_args += ["/LIBPATH:"+os.path.join("C:\\","zlib", "static_x64")] 67 | platform_link_args += ["/LIBPATH:"+os.path.join("C:\\","Program Files", "libuv")] 68 | platform_libraries += ["libssl64MT", "libcrypto64MT"] 69 | _external_dlls = [os.path.join("C:\\", "Program Files","libuv", "libuv.dll")] 70 | 71 | 72 | else: 73 | raise Exception("Unknown architecture %s" % repr(arch)) 74 | 75 | platform_defines = [("MSVC",1), ("_WIN32", 1), ("ZLIB_WINAPI",1)] 76 | if sys.version_info[0] == 2: 77 | platform_defines += [("_NO_THREADS",1)] 78 | else: 79 | """ 80 | We have to manually set these includes 81 | """ 82 | platform_include_dirs += [os.path.join("C:\\","Program Files (x86)","Microsoft Visual Studio 14.0", "VC", "INCLUDE")] 83 | platform_include_dirs += [os.path.join("C:\\","Program Files (x86)","Microsoft Visual Studio 14.0", "VC", "ATLMFC", "INCLUDE")] 84 | platform_include_dirs += [os.path.join("C:\\","Program Files (x86)","Windows Kits", "10", "INCLUDE", "10.0.10240.0", "ucrt")] 85 | platform_cflags += ["--std=c++0x"] 86 | 87 | if os.environ.get("MANYLINUX",None) is not None: 88 | platform_libraries = [] 89 | # To satisfy manylinux1 tag, we need to jump through a lot of hoops; see docker/manylinux 90 | platform_link_args = [ 91 | # Don't link with standard library, the script in docker/manylinux/ld-patch.sh will add the correct flags for that. 92 | "-nostdlib", 93 | "-Wl,--add-needed", 94 | "-Wl,--demangle", 95 | "-Wl,-Bstatic", 96 | "-lz", 97 | "-luv", 98 | "-L/opt/openssl/lib/", 99 | "-lssl", 100 | "-lcrypto", 101 | 102 | 103 | "/glibc-glibc-2.10/build/elf/soinit.os", 104 | "-Wl,-z,muldefs", 105 | "-Wl,--gc-sections", 106 | "-Wl,-fini=__wrap_fini", 107 | "-Wl,--wrap=atexit", 108 | "-Wl,-z,initfirst", 109 | "/glibc-glibc-2.10/build/libc_pic.a", 110 | "-Wl,--no-gc-sections", 111 | 112 | "-Wl,--default-symver", 113 | "-Wl,--version-script=/vagrant/manylinux.map", 114 | "-Wl,-Map=/vagrant/uWebSockets.map", 115 | "-Wl,--cref", 116 | 117 | "-Wl,-Bdynamic", 118 | 119 | "/opt/rh/devtoolset-2/root/usr/lib/gcc/x86_64-CentOS-linux/4.8.2/libgcc_eh.a", 120 | "/opt/rh/devtoolset-2/root/usr/lib/gcc/x86_64-CentOS-linux/4.8.2/libstdc++.a", 121 | 122 | ] 123 | platform_include_dirs = ["/opt/glibc2.10/include", "/opt/openssl/include/"] 124 | platform_cflags = ["-fPIC", "-g", "-Og"] 125 | platform_defines += [("MANYLINUX",1)] # ("DEBUG_PYTHON_BINDINGS", 1)] 126 | 127 | 128 | uWebSockets = Extension("uWebSockets", 129 | sources=["Bindings.cpp"] + upstream_src, 130 | include_dirs=[upstream_dir] + platform_include_dirs, 131 | libraries=platform_libraries, 132 | #define_macros=[("UWS_THREADSAFE", 1), ("PYTHON_FLAVOUR",sys.version_info[0])], ## FIXME: UWS_THREADSAFE unsupported on Windows and OSX 133 | define_macros=[("PYTHON_FLAVOUR", sys.version_info[0]), ("__STDC_LIMIT_MACROS",1)] + platform_defines, 134 | extra_compile_args=["-std=c++11"]+platform_cflags, # FIXME: Won't work on older compilers 135 | extra_link_args=platform_link_args, 136 | extra_objects = extra_objects 137 | ) 138 | 139 | version="0.14.8a1" 140 | 141 | """ 142 | Windoze Hack - Add dlls 143 | """ 144 | if platform.system().lower() == "windows" and "fix-wheel" in sys.argv: 145 | whl = os.path.join(os.path.dirname(__file__), "dist", "uWebSockets-%s-cp%d%d-cp%d%dm-win%s.whl" % (version, sys.version_info[0],sys.version_info[1],sys.version_info[0],sys.version_info[1],"32" if arch==32 else "_amd64")) 146 | print("wheel in %s" % repr(whl)) 147 | assert(os.path.exists(whl)) 148 | import zipfile 149 | with zipfile.ZipFile(whl,"a") as z: 150 | for dll in _external_dlls: 151 | print("Add %s" % dll) 152 | z.write(dll, os.path.basename(dll)) 153 | z.printdir() 154 | z.testzip() 155 | z.close() 156 | sys.exit(0) 157 | 158 | setup(name="uWebSockets", 159 | version=version, 160 | description="Python Bindings for the uWebSockets library", 161 | url="https://github.com/uNetworking/uWebSockets-bindings/", 162 | author="Sam Moore", 163 | author_email="smoore@elementengineering.com.au", 164 | license="MIT", 165 | classifiers=[ 166 | "Development Status :: 3 - Alpha", 167 | "Intended Audience :: Developers", 168 | "Topic :: Software Development", 169 | "License :: OSI Approved :: MIT License", 170 | 171 | "Programming Language :: Python :: 2", 172 | "Programming Language :: Python :: 2.7", 173 | "Programming Language :: Python :: 3", 174 | "Programming Language :: Python :: 3.6" 175 | ], 176 | keywords="websockets development", 177 | ext_modules =[uWebSockets], 178 | test_suite='nose.collector', 179 | tests_require=['nose'], 180 | include_package_data=True, 181 | package_data=platform_package_data 182 | ) 183 | 184 | -------------------------------------------------------------------------------- /python/tests/test_client.py: -------------------------------------------------------------------------------- 1 | import uWebSockets 2 | 3 | import threading 4 | import time 5 | import sys 6 | import uuid 7 | import json 8 | 9 | """ 10 | A Test Client which sends random messages to wss://echo.websocket.org and verifies the replies 11 | """ 12 | class TestClient(uWebSockets.WebSocketClient): 13 | 14 | def __init__(self, *args, **kwargs): 15 | """ 16 | Implement pre-connection initialisation here 17 | """ 18 | super(TestClient, self).__init__(*args, **kwargs) 19 | self.expected = None 20 | self.sent_received = {} 21 | 22 | def on_message(self, message): 23 | """ 24 | Handle messages here. Message is a string. 25 | If we get an exception, the websocket will disconnect automatically. 26 | """ 27 | print("Recv %s" % repr(message)) 28 | assert(message == self.expected) 29 | assert(message in self.sent_received) 30 | assert(self.sent_received[message] == False) 31 | self.sent_received[message] = True 32 | self.expected = str(uuid.uuid4().hex).upper()[0:6] 33 | self.send(self.expected) 34 | 35 | def test(self): 36 | print("What") 37 | 38 | def send(self, message): 39 | """ 40 | Overridable method to send messages 41 | """ 42 | print("Send %s" % repr(message)) 43 | self.sent_received[message] = False 44 | return super(TestClient, self).send(message) 45 | 46 | def on_open(self): 47 | """ 48 | Implement post-connection initialisation here 49 | """ 50 | print("Open %s" % repr(self)) 51 | self.expected = str(uuid.uuid4().hex).upper()[0:6] 52 | self.send(self.expected) 53 | 54 | def on_close(self, code, message): 55 | print("Closed %s %s" % (repr(code), repr(message))) 56 | 57 | 58 | def close(self): 59 | """ 60 | Overridable method for closing 61 | """ 62 | print("Overrode close here") 63 | return super(TestClient, self).close() 64 | 65 | num_messages = 10 66 | timeout = 20 67 | 68 | ws = TestClient("wss://echo.websocket.org") # Initialise with URI 69 | ws.run(True) # Argument is True to run in a seperate (C++ not python) thread, False to run within current thread. 70 | start_time = time.time() 71 | time.sleep(3) 72 | 73 | # ws.valid() becomes True after first ever connection and remains True forever 74 | # ws.connected() is actually connection state. 75 | # We need to check both so we don't break out of the loop before we even connected. 76 | while (not ws.valid() or ws.connected()) \ 77 | and (num_messages is None or len(ws.sent_received) < num_messages) \ 78 | and (timeout is None or time.time() - start_time < timeout): 79 | """ 80 | Do other application tasks here. 81 | """ 82 | time.sleep(1) 83 | 84 | print(json.dumps(ws.sent_received, indent=4)) 85 | ws.close() 86 | assert(len(ws.sent_received) >= num_messages) # Check test passed 87 | ## Required on Windoze 88 | sys.exit(0) 89 | -------------------------------------------------------------------------------- /python/windows/windoze.md: -------------------------------------------------------------------------------- 1 | ## Sources for Windows 7 2 | 3 | * Current as of 2018-05-04 4 | * Maintained by @szmoore 5 | * From the future? Try [webarchive](https://archive.org/) but it probably won't have any of these. 6 | * We require C++11 (or at least C++0x) support, which causes issues with Python 2.7, but you might be able to get it to work 7 | * To compile we require the Anaconda fork of Python, but the compiled wheel will still work with default PyPi provided Python (of the correct version and architecture) on a windows system. 8 | * We use Anaconda because it supplies stable development libraries for python that actually *work* with visual studio 9 | * **WARNING** Do *not* update `conda` because it will break. `4.4.10` is the working version. 10 | * If you see a blank screen press Y and Enter. It appears to be a stdio bug on windows. 11 | 12 | 13 | 14 | 15 | ### Python2.7 16 | 17 | * **This is not tested because I gave up, but it will probably work if you compile with:** 18 | * `-DNO_THREADS` 19 | * [Anaconda2 32bit](https://repo.continuum.io/archive/Anaconda2-5.1.0-Windows-x86.exe) 20 | * `cd C:\ProgramData\Anaconda\Scripts && conda create -n py2.7 python=2.7 numpy pip mingw` 21 | * [Anaconda2 64bit](https://repo.continuum.io/archive/Anaconda2-5.1.0-Windows-x86_64.exe) 22 | * `cd C:\ProgramData\Anaconda-64\Scripts && conda create -n py2.7 python=2.7 numpy pip mingw` 23 | 24 | * [.NET 3.5](https://www.microsoft.com/en-au/download/details.aspx?id=21)(Good luck) 25 | * [Windows 7 SDK](https://download.microsoft.com/download/7/A/B/7ABD2203-C472-4036-8BA0-E505528CCCB7/winsdk_web.exe) 26 | * [Visual C++ 2008](http://download.microsoft.com/download/A/5/4/A54BADB6-9C3F-478D-8657-93B3FC9FE62D/vcsetup.exe) 27 | 28 | ###Python3.X 29 | 30 | * [Anaconda3 32bit](https://repo.continuum.io/archive/Anaconda3-5.1.0-Windows-x86.exe) 31 | * `cd C:\ProgramData\Anaconda3\Scripts && conda create -n py3.6 python=3.6 numpy pip mingw` 32 | * [Anaconda3 64bit](https://repo.continuum.io/archive/Anaconda3-5.1.0-Windows-x86_64.exe) 33 | * `cd C:\ProgramData\Anaconda3-64\Scripts && conda create -n py3.6 python=3.6 numpy pip mingw` 34 | * [.NET 4.0](https://download.microsoft.com/download/1/B/E/1BE39E79-7E39-46A3-96FF-047F95396215/dotNetFx40_Full_setup.exe) 35 | * On Windows 10 you can skip this, as .NET 4.7 is already installed 36 | * [Visual C++ 2015](https://my.visualstudio.com/downloads?q=visual%20studio%20community%202015) 37 | * Note you must include C++ language support in the installer setup menu because it's not installed by default 38 | * If you use `-DNOTHREADS` as with Python2.7 you can probably use 2010, which is what Python3.X is *meant* to be compiled with. 39 | * [Visual C++ 2010](http://download.microsoft.com/download/1/D/9/1D9A6C0E-FC89-43EE-9658-B9F0E3A76983/vc_web.exe) 40 | * [Windows 7 SDK](https://download.microsoft.com/download/A/6/A/A6AC035D-DA3F-4F0C-ADA4-37C8E5D34E3D/winsdk_web.exe) 41 | 42 | 43 | #### WINDOZE TEN 44 | 45 | * You need Visual Studio 2015 because 2017 removes command line tools. 46 | * You can probably use VS 2017 and Windows 10 SDK but since they removed command line tools it's pretty shit to do from a batch script that can be put under source control... 47 | 48 | * To actually install the Windows 7 SDK and get 64 bit compilers to work, you need to edit registry values before installing it due to a bug, this is described [here]( https://stackoverflow.com/questions/32091593/cannot-install-windows-sdk-7-1-on-windows-10) but for completeness: 49 | 50 | * regdit the keys `HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\NET Framework Setup\NDP\v4\Client\Version` 51 | and `HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\NET Framework Setup\NDP\v4\Full\Version` 52 | to read `4.0.30319` then install. Then edit the keys back to whatever they were before `4.7.02556` 53 | 54 | * You may enouncter a bug with `rc.exe` not existing [see here](https://stackoverflow.com/questions/14372706/visual-studio-cant-build-due-to-rc-exe) 55 | * Install the Windows 8.1 Kit (not called SDK anymore?) 56 | * Add `C:\Program Files (x86)\Windows Kits\8.1\bin\x86` to path. 57 | 58 | 59 | ### OpenSSL 60 | * These now `404`, send me a letter and $200 if you want my saved copies... 61 | * Install them in `C:\OpenSSL-WinXX` (`32` and `64` respectively). 62 | * [32 bit](http://slproweb.com/download/Win32OpenSSL-1_1_0g.exe) 63 | * [64 bit](http://slproweb.com/download/Win64OpenSSL-1_1_0g.exe) 64 | 65 | ### zlib 66 | * [Windows version](https://sourceforge.net/projects/gnuwin32/files/zlib/1.2.3/zlib-1.2.3-lib.zip/download?use_mirror=jaist&download=) - Extract all headers **and** the *static* libraries to `C:\zlib` 67 | 68 | ### libuv 69 | * [32 bit](https://dist.libuv.org/dist/v1.9.1/libuv-x86-v1.9.1.build10.exe) in `C:\Program Files (x86)\libuv` 70 | * [64 bit](https://dist.libuv.org/dist/v1.9.1/libuv-x64-v1.9.1.build10.exe) in `C:\Program Files\libuv` 71 | --------------------------------------------------------------------------------