| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| */ |
| |
| /** |
| * ws2tcp.js is a simple node.js library that proxies from a WebSocket to a TCP |
| * Socket or vice versa. It has minimal dependencies - the standard node.js net |
| * library and the ws WebSocket library (npm install ws). |
| * <p> |
| * Two fuctions are exported, ws2tcp proxies from a WebSocket to a TCP Socket and |
| * tcp2ws proxies from a TCP Socket to a WebSocket. |
| * @Author Fraser Adams |
| * @file |
| */ |
| |
| var WebSocket = require('ws'); |
| var net = require('net'); |
| |
| /** |
| * This function is shared by ws2tcp and tcp2ws and takes care of cleaning up |
| * and closing the WebSocket and Socket when things close down or error. |
| * @param sock the TCP Socket instance we're registering cleanup handlers for. |
| * @param ws the WebSocket instance we're registering cleanup handlers for. |
| */ |
| var registerCleanupCallbacks = function(sock, ws) { |
| var cleanup = function(sock, ws) { |
| sock.removeAllListeners('close'); |
| sock.end(); |
| ws.removeAllListeners('close'); |
| ws.close(); |
| }; |
| |
| sock.on('close', function() { |
| cleanup(sock, ws); |
| }); |
| |
| sock.on('error', function (e) { |
| console.log("socket error: " + e.code); |
| cleanup(sock, ws); |
| }); |
| |
| ws.on('close', function() { |
| cleanup(sock, ws); |
| }); |
| |
| ws.on('error', function (e) { |
| console.log("websocket error: " + e.code); |
| cleanup(sock, ws); |
| }); |
| }; |
| |
| /** |
| * This function establishes a proxy that listens on a specified TCP Socket port |
| * and proxies data to a WebSocket on the target host listening on the specified |
| * target port. |
| * @param lport the listen port. |
| * @param thost the target host. |
| * @param tport the target port. |
| * @param subProtocols a string containing a comma separated list of WebSocket sub-protocols. |
| */ |
| var tcp2ws = function(lport, thost, tport, subProtocols) { |
| var opts = null; |
| if (subProtocols) { |
| // The regex trims the string (removes spaces at the beginning and end, |
| // then splits the string by <any space>,<any space> into an Array. |
| subProtocols = subProtocols.replace(/^ +| +$/g,"").split(/ *, */); |
| opts = {'protocol': subProtocols.toString()}; |
| } |
| |
| var server = net.createServer(function(sock) { |
| var url = 'ws://' + thost + ':' + tport; |
| var ws = new WebSocket(url, opts); |
| var ready = false; |
| var buffer = []; |
| |
| registerCleanupCallbacks(sock, ws); |
| |
| sock.on('data', function(data) { |
| if (ready) { |
| ws.send(data); |
| } else { |
| buffer.push(data); |
| } |
| }); |
| |
| ws.on('open', function () { |
| if (buffer.length > 0) { |
| ws.send(Buffer.concat(buffer)); |
| } |
| ready = true; |
| buffer = null; |
| }); |
| |
| ws.on('message', function(m) { |
| sock.write(m); |
| }); |
| }); |
| server.listen(lport); |
| }; |
| |
| /** |
| * This function establishes a proxy that listens on a specified WebSocket port |
| * and proxies data to a TCP Socket on the target host listening on the specified |
| * target port. |
| * @param lport the listen port. |
| * @param thost the target host. |
| * @param tport the target port. |
| */ |
| var ws2tcp = function(lport, thost, tport) { |
| var server = new WebSocket.Server({port: lport}); |
| server.on('connection', function(ws) { |
| var sock = net.connect(tport, thost); |
| var ready = false; |
| var buffer = []; |
| |
| registerCleanupCallbacks(sock, ws); |
| |
| ws.on('message', function(m) { |
| if (ready) { |
| sock.write(m); |
| } else { |
| buffer.push(m); |
| } |
| }); |
| |
| sock.on('connect', function() { |
| if (buffer.length > 0) { |
| sock.write(Buffer.concat(buffer)); |
| } |
| ready = true; |
| buffer = null; |
| }); |
| |
| sock.on('data', function(data) { |
| try { |
| ws.send(data); |
| } catch (e) { |
| console.log("error sending: " + e); |
| } |
| }); |
| }); |
| server.on('error', function(e) { |
| console.log("websocket server error: " + e.code); |
| }); |
| }; |
| |
| // Export the two proxy functions. |
| module.exports.ws2tcp = ws2tcp; |
| module.exports.tcp2ws = tcp2ws; |
| |