The connection class manages the TCP connection to the Jabber server
Allow TLS negotiation? Defaults to true
How many seconds to wait for <stream:features/> before proceeding
Keep-alive interval in seconds, defaults to 60 (see private method keepalive_loop for implementation details)
Optional CA-Path for TLS-handshake
Optional callback for verification of SSL peer
whether to use the old and deprecated SSL protocol Defaults to false
Create a new connection to the given host and port
# File lib/xmpp4r/connection.rb, line 41 def initialize super() @host = nil @port = nil @allow_tls = defined? OpenSSL @tls = false @ssl_capath = nil @ssl_verifycb = nil @features_timeout = 10 @keepalive_interval = 60 @use_ssl = false end
# File lib/xmpp4r/connection.rb, line 96 def accept_features begin Timeout::timeout(@features_timeout) { Jabber::debuglog("FEATURES: waiting...") @features_sem.wait Jabber::debuglog("FEATURES: waiting finished") } rescue Timeout::Error Jabber::debuglog("FEATURES: timed out when waiting, stream peer seems not XMPP compliant") end if @allow_tls and not is_tls? and @stream_features['starttls'] == 'urn:ietf:params:xml:ns:xmpp-tls' begin starttls rescue Jabber::debuglog("STARTTLS:\nFailure: #{$!}") end end end
Closing connection: first kill keepaliveThread (but only if it's not me), then call Jabber::Stream#close!
# File lib/xmpp4r/connection.rb, line 90 def close! @keepaliveThread.kill if @keepaliveThread and @keepaliveThread.alive? and @keepaliveThread != Thread.current super @keepaliveThread.kill if @keepaliveThread and @keepaliveThread.alive? end
Connect to the Jabber server through a TCP Socket, start the Jabber parser, invoke to #accept_features to wait for TLS, start the keep-alive thread
# File lib/xmpp4r/connection.rb, line 59 def connect(host, port) @host = host @port = port # Reset is_tls?, so that it works when reconnecting @tls = false Jabber::debuglog("CONNECTING:\n#{@host}:#{@port}") @socket = TCPSocket.new(@host, @port) # We want to use the old and deprecated SSL protocol (usually on port 5223) if @use_ssl ssl = OpenSSL::SSL::SSLSocket.new(@socket) ssl.connect # start SSL session ssl.sync_close = true Jabber::debuglog("SSL connection established.") @socket = ssl end start accept_features @keepaliveThread = Thread.new do Thread.current.abort_on_exception = true keepalive_loop end end
Have we gone to TLS mode?
or [false]
# File lib/xmpp4r/connection.rb, line 182 def is_tls? @tls end
Start the parser on the previously connected socket
# File lib/xmpp4r/connection.rb, line 118 def start super(@socket) end
Do a <starttls/> (will be automatically done by connect if stream peer supports this)
# File lib/xmpp4r/connection.rb, line 125 def starttls stls = REXML::Element.new('starttls') stls.add_namespace('urn:ietf:params:xml:ns:xmpp-tls') reply = nil send(stls) { |r| reply = r true } if reply.name != 'proceed' raise ServerError.new(reply.first_element('error')) end # Don't be interrupted stop begin error = nil # Context/user set-able stuff ctx = OpenSSL::SSL::SSLContext.new if @ssl_capath ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER ctx.ca_path = @ssl_capath else ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE end ctx.verify_callback = @ssl_verifycb # SSL connection establishing sslsocket = OpenSSL::SSL::SSLSocket.new(@socket, ctx) sslsocket.sync_close = true Jabber::debuglog("TLSv1: OpenSSL handshake in progress") sslsocket.connect # Make REXML believe it's a real socket class << sslsocket def kind_of?(o) o == IO ? true : super end end # We're done and will use it @tls = true @socket = sslsocket rescue error = $! ensure Jabber::debuglog("TLSv1: restarting parser") start accept_features raise error if error end end