class Jabber::Bytestreams::SOCKS5Bytestreams

SOCKS5 Bytestreams (JEP-0065) implementation

Don't use directly, use SOCKS5BytestreamsInitiator and SOCKS5BytestreamsTarget

Attributes

connect_timeout[RW]

SOCKS connection timeout (for trying multiple streamhosts)

default: nil, use the OS' default timeout

streamhost_used[R]
StreamHost

the SOCKS connection is using

Public Class Methods

new(stream, session_id, initiator_jid, target_jid) click to toggle source
# File lib/xmpp4r/bytestreams/helper/socks5bytestreams/base.rb, line 30
def initialize(stream, session_id, initiator_jid, target_jid)
  @stream = stream
  @session_id = session_id
  @initiator_jid = (initiator_jid.kind_of?(String) ? JID.new(initiator_jid) : initiator_jid)
  @target_jid = (target_jid.kind_of?(String) ? JID.new(target_jid) : target_jid)
  @socks = nil
  @connect_timeout = nil
  @streamhost_used = nil
  @streamhost_cbs = CallbackList.new
end
query_streamhost(stream, streamhost, my_jid=nil) click to toggle source

Query a JID for its stream-host information

Jabber::Bytestreams::SOCKS5BytestreamsInitiator#add_streamhost can do this for you. Use this method if you plan to do multiple transfers, so you can cache the result.

stream
Stream

to operate on

streamhost
JID

of the proxy

my_jid
JID

Optional sender JID for Component operation

# File lib/xmpp4r/bytestreams/helper/socks5bytestreams/base.rb, line 95
def self.query_streamhost(stream, streamhost, my_jid=nil)
  res = nil

  iq = Iq.new(:get, streamhost)
  iq.from = my_jid
  iq.add(IqQueryBytestreams.new)
  stream.send_with_id(iq) { |reply|
    reply.query.each_element { |e|
      if e.kind_of?(StreamHost)
        e.jid = reply.from  # Help misconfigured proxys
        res = e
      end
    }
  }

  if res and res.jid and res.host and res.port
    res
  else
    nil
  end
end

Public Instance Methods

add_streamhost_callback(priority = 0, ref = nil, &block) click to toggle source

Add a callback that will be called when there is action regarding SOCKS stream-hosts

Usage of this callback is optional and serves informational purposes only.

block takes three arguments:

  • The StreamHost instance that is currently being tried

  • State information (is either :connecting, :authenticating, :success or :failure)

  • The exception value for the state :failure, else nil

# File lib/xmpp4r/bytestreams/helper/socks5bytestreams/base.rb, line 51
def add_streamhost_callback(priority = 0, ref = nil, &block)
  @streamhost_cbs.add(priority, ref, block)
end
close() click to toggle source

Close the stream-host connection

# File lib/xmpp4r/bytestreams/helper/socks5bytestreams/base.rb, line 82
def close
  @socks.close
end
flush() click to toggle source

Flush the SOCKS5 socket

# File lib/xmpp4r/bytestreams/helper/socks5bytestreams/base.rb, line 65
def flush
  @socks.flush
end
read(length=nil) click to toggle source

Receive from the stream-host

length
Fixnum

Amount of bytes (Will be passed to TCPSocket#read for the underlying SOCKS5 connection)

result
String

(or [nil] if finished)

# File lib/xmpp4r/bytestreams/helper/socks5bytestreams/base.rb, line 59
def read(length=nil)
  @socks.read(length)
end
write(buf) click to toggle source

Send to the stream-host

buf
String

Data

result
Fixnum

Amount of bytes sent

# File lib/xmpp4r/bytestreams/helper/socks5bytestreams/base.rb, line 73
def write(buf)
  @socks.write(buf)
  # FIXME: On FreeBSD this throws Errno::EPERM after it has already written a few
  # kilobytes, and when there are multiple sockets. ktrace told, that this originates
  # from the syscall, not ruby.
end

Private Instance Methods

connect_socks(streamhost) click to toggle source

Try a streamhost

result
SOCKS5Socket
# File lib/xmpp4r/bytestreams/helper/socks5bytestreams/base.rb, line 132
def connect_socks(streamhost)
  Timeout::timeout(@connect_timeout, Errno::ETIMEDOUT) {
    Jabber::debuglog("SOCKS5 Bytestreams: connecting to proxy #{streamhost.jid} (#{streamhost.host}:#{streamhost.port})")
    @streamhost_cbs.process(streamhost, :connecting, nil)
    socks = SOCKS5Socket.new(streamhost.host, streamhost.port)

    Jabber::debuglog("SOCKS5 Bytestreams: connected, authenticating")
    @streamhost_cbs.process(streamhost, :authenticating, nil)
    socks.auth

    socks.connect_domain(stream_address, 0)

    Jabber::debuglog("SOCKS5 Bytestreams: connected")
    @streamhost_cbs.process(streamhost, :success, nil)

    socks
  }
end
stream_address() click to toggle source

The address the stream-host expects from us. According to JEP-0096 this is the SHA1 hash of the concatenation of session_id, initiator_jid and target_jid.

result
String

SHA1 hash

# File lib/xmpp4r/bytestreams/helper/socks5bytestreams/base.rb, line 125
def stream_address
  Digest::SHA1.hexdigest("#{@session_id}#{@initiator_jid}#{@target_jid}")
end