aboutsummaryrefslogtreecommitdiff
path: root/third_party/websockify/other/websockify.rb
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/websockify/other/websockify.rb')
-rwxr-xr-xthird_party/websockify/other/websockify.rb171
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