class Net::SSH::Authentication::Pageant::Socket

This is the pseudo-socket implementation that mimics the interface of a socket, translating each request into a Windows messaging call to the pageant daemon. This allows pageant support to be implemented simply by replacing the socket factory used by the Agent class.

Public Class Methods

new() click to toggle source

Create a new instance that communicates with the running pageant instance. If no such instance is running, this will cause an error.

# File lib/net/ssh/authentication/pageant.rb, line 109
def initialize
  @win = Win.FindWindow("Pageant", "Pageant")

  if @win == 0
    raise Net::SSH::Exception,
      "pageant process not running"
  end

  @res = nil
  @pos = 0
end
open(location=nil) click to toggle source

The factory method for creating a new Socket instance. The location parameter is ignored, and is only needed for compatibility with the general Socket interface.

# File lib/net/ssh/authentication/pageant.rb, line 103
def self.open(location=nil)
  new
end

Public Instance Methods

close() click to toggle source

Conceptually close the socket. This doesn’t really do anthing significant, but merely complies with the Socket interface.

# File lib/net/ssh/authentication/pageant.rb, line 174
def close
  @res = nil
  @pos = 0
end
closed?() click to toggle source

Conceptually asks if the socket is closed. As with close, this doesn’t really do anything significant, but merely complies with the Socket interface.

# File lib/net/ssh/authentication/pageant.rb, line 182
def closed?
  @res.nil? && @pos.zero?
end
read(n = nil) click to toggle source

Reads n bytes from the cached result of the last query. If n is nil, returns all remaining data from the last query.

# File lib/net/ssh/authentication/pageant.rb, line 188
def read(n = nil)
  return nil unless @res
  if n.nil?
    start, @pos = @pos, @res.size
    return @res[start..-1]
  else
    start, @pos = @pos, @pos + n
    return @res[start, n]
  end
end
send(data, *args) click to toggle source

Forwards the data to send_query, ignoring any arguments after the first. Returns 0.

# File lib/net/ssh/authentication/pageant.rb, line 123
def send(data, *args)
  @res = send_query(data)
  @pos = 0
end
send_query(query) click to toggle source

Packages the given query string and sends it to the pageant process via the Windows messaging subsystem. The result is cached, to be returned piece-wise when read is called.

# File lib/net/ssh/authentication/pageant.rb, line 131
def send_query(query)
  res = nil
  filemap = 0
  ptr = nil
  id = DL::PtrData.malloc(DL.sizeof("L"))

  mapname = "PageantRequest%08x\0000" % Win.getCurrentThreadId()
  filemap = Win.createFileMapping(Win::INVALID_HANDLE_VALUE, 
                                  Win::NULL,
                                  Win::PAGE_READWRITE, 0, 
                                  AGENT_MAX_MSGLEN, mapname)
  if filemap == 0
    raise Net::SSH::Exception,
      "Creation of file mapping failed"
  end

  ptr = Win.mapViewOfFile(filemap, Win::FILE_MAP_WRITE, 0, 0, 
                          AGENT_MAX_MSGLEN)

  if ptr.nil? || ptr.null?
    raise Net::SSH::Exception, "Mapping of file failed"
  end

  ptr[0] = query

  cds = [AGENT_COPYDATA_ID, mapname.size + 1, mapname].
    pack("LLp").to_ptr
  succ = Win.sendMessageTimeout(@win, Win::WM_COPYDATA, Win::NULL,
                                cds, Win::SMTO_NORMAL, 5000, id)

  if succ > 0
    retlen = 4 + ptr.to_s(4).unpack("N")[0]
    res = ptr.to_s(retlen)
  end        

  return res
ensure
  Win.unmapViewOfFile(ptr) unless ptr.nil? || ptr.null?
  Win.closeHandle(filemap) if filemap != 0
end