diff options
Diffstat (limited to 'third_party/websockify/other/websockify.rb')
-rwxr-xr-x | third_party/websockify/other/websockify.rb | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/third_party/websockify/other/websockify.rb b/third_party/websockify/other/websockify.rb new file mode 100755 index 00000000..bdc61f16 --- /dev/null +++ b/third_party/websockify/other/websockify.rb @@ -0,0 +1,171 @@ +#!/usr/bin/env ruby + +# A WebSocket to TCP socket proxy +# Copyright 2011 Joel Martin +# Licensed under LGPL version 3 (see docs/LICENSE.LGPL-3) + +require 'socket' +$: << "other" +$: << "../other" +require 'websocket' +require 'optparse' + +# Proxy traffic to and from a WebSockets client to a normal TCP +# socket server target. All traffic to/from the client is base64 +# encoded/decoded to allow binary data to be sent/received to/from +# the target. +class WebSocketProxy < WebSocketServer + + @@Traffic_legend = " +Traffic Legend: + } - Client receive + }. - Client receive partial + { - Target receive + + > - Target send + >. - Target send partial + < - Client send + <. - Client send partial +" + + + def initialize(opts) + vmsg "in WebSocketProxy.initialize" + + super(opts) + + @target_host = opts["target_host"] + @target_port = opts["target_port"] + end + + # Echo back whatever is received + def new_client(client) + + msg "connecting to: %s:%s" % [@target_host, @target_port] + tsock = TCPSocket.open(@target_host, @target_port) + + if @verbose then puts @@Traffic_legend end + + begin + do_proxy(client, tsock) + rescue + tsock.shutdown(Socket::SHUT_RDWR) + tsock.close + raise + end + end + + # Proxy client WebSocket to normal target socket. + def do_proxy(client, target) + cqueue = [] + c_pend = 0 + tqueue = [] + rlist = [client, target] + + loop do + wlist = [] + + if tqueue.length > 0 + wlist << target + end + if cqueue.length > 0 || c_pend > 0 + wlist << client + end + + ins, outs, excepts = IO.select(rlist, wlist, nil, 0.001) + if excepts && excepts.length > 0 + raise Exception, "Socket exception" + end + + # Send queued client data to the target + if outs && outs.include?(target) + dat = tqueue.shift + sent = target.send(dat, 0) + if sent == dat.length + traffic ">" + else + tqueue.unshift(dat[sent...dat.length]) + traffic ".>" + end + end + + # Receive target data and queue for the client + if ins && ins.include?(target) + buf = target.recv(@@Buffer_size) + if buf.length == 0: + raise EClose, "Target closed" + end + + cqueue << buf + traffic "{" + end + + # Encode and send queued data to the client + if outs && outs.include?(client) + c_pend = send_frames(cqueue) + cqueue = [] + end + + # Receive client data, decode it, and send it back + if ins && ins.include?(client) + frames, closed = recv_frames + tqueue += frames + + if closed + send_close + raise EClose, closed + end + end + + end # loop + end +end + +# Parse parameters +opts = {} +parser = OptionParser.new do |o| + o.on('--verbose', '-v') { |b| opts['verbose'] = b } + o.parse! +end + +if ARGV.length < 2: + puts "Too few arguments" + exit 2 +end + +# Parse host:port and convert ports to numbers +if ARGV[0].count(":") > 0 + opts['listen_host'], _, opts['listen_port'] = ARGV[0].rpartition(':') +else + opts['listen_host'], opts['listen_port'] = nil, ARGV[0] +end + +begin + opts['listen_port'] = opts['listen_port'].to_i +rescue + puts "Error parsing listen port" + exit 2 +end + +if ARGV[1].count(":") > 0 + opts['target_host'], _, opts['target_port'] = ARGV[1].rpartition(':') +else + puts "Error parsing target" + exit 2 +end + +begin + opts['target_port'] = opts['target_port'].to_i +rescue + puts "Error parsing target port" + exit 2 +end + +puts "Starting server on #{opts['listen_host']}:#{opts['listen_port']}" +server = WebSocketProxy.new(opts) +server.start(100) +server.join + +puts "Server has been terminated" + +# vim: sw=2 |