require "xmlrpc/client"
require "rex"

module Msf
module RPC

# Loosely based on the XMLRPC::ClientS class
# Reimplemented for Metasploit

class Client < ::XMLRPC::Client

	attr_accessor :sock, :token

	# Use a TCP socket to do RPC
	def initialize(info={})

		@buff = ""
		self.sock = Rex::Socket::Tcp.create(
			'PeerHost' => info[:host],
			'PeerPort' => info[:port],
			'SSL'      => info[:ssl]
		)
	end

	# This override hooks into the RPCXML library
	def do_rpc(request,async)

		self.sock.put(request + "\x00")
		
		begin
			while(not @buff.index("\x00"))
				if ::IO.select([self.sock], nil, nil, 30)
					resp = self.sock.sysread(32768)
					@buff << resp if resp
				end
			end
		rescue ::Exception => e
			self.sock.close rescue nil
			raise EOFError, "XMLRPC connection closed"
		end

		mesg,left = @buff.split("\x00", 2)
		@buff = left.to_s
		mesg
	end

	def login(user,pass)
		res = self.call("auth.login", user, pass)
		if(not (res and res['result'] == "success"))
			raise RuntimeError, "authentication failed"
		end
		self.token = res['token']
		true
	end

	# Prepend the authentication token as the first parameter
	# of every call except auth.login. Requires the
	def call(meth, *args)
		if(meth != "auth.login")
			if(not self.token)
				raise RuntimeError, "client not authenticated"
			end
			args.unshift(self.token)
		end
		super(meth, *args)
	end

	def close
		self.sock.close
	end

end
end
end

