class ProxyMachine class ClientConnection < EventMachine::Connection def self.start(host, port) $server = EM.start_server(host, port, self) $logger.info "Listening on #{host}:#{port}" $logger.info "Send QUIT to quit after waiting for all connections to finish." $logger.info "Send TERM or INT to quit after waiting for up to 10 seconds for connections to finish." end def post_init $logger.info "Accepted #{peer}" @buffer = [] @tries = 0 ProxyMachine.incr end def peer @peer ||= begin port, ip = Socket.unpack_sockaddr_in(get_peername) "#{ip}:#{port}" end end def receive_data(data) if !@server_side @buffer << data ensure_server_side_connection end rescue => e close_connection $logger.info "#{e.class} - #{e.message}" end def ensure_server_side_connection @timer.cancel if @timer unless @server_side commands = ProxyMachine.router.call(@buffer.join) $logger.info "#{peer} #{commands.inspect}" close_connection unless commands.instance_of?(Hash) if remote = commands[:remote] m, host, port = *remote.match(/^(.+):(.+)$/) klass = commands[:callback] ? CallbackServerConnection : ServerConnection if try_server_connect(host, port.to_i, klass) @server_side.callback = commands[:callback] if commands[:callback] if data = commands[:data] @buffer = [data] end if reply = commands[:reply] send_data(reply) end send_and_clear_buffer end elsif close = commands[:close] if close == true close_connection else send_data(close) close_connection_after_writing end elsif commands[:noop] # do nothing else close_connection end end end def try_server_connect(host, port, klass) @server_side = klass.request(host, port, self) proxy_incoming_to(@server_side, 10240) $logger.info "Successful connection to #{host}:#{port}." true rescue => e if @tries < 10 @tries += 1 $logger.info "Failed on server connect attempt #{@tries}. Trying again..." @timer.cancel if @timer @timer = EventMachine::Timer.new(0.1) do self.ensure_server_side_connection end else $logger.info "Failed after ten connection attempts." end false end def send_and_clear_buffer if !@buffer.empty? @buffer.each do |x| @server_side.send_data(x) end @buffer = [] end end def unbind @server_side.close_connection_after_writing if @server_side ProxyMachine.decr end # Proxy connection has been lost def proxy_target_unbound @server_side = nil end end end