Class | Jabber::Connection |
In: |
lib/xmpp4r/connection.rb
|
Parent: | Stream |
The connection class manages the TCP connection to the Jabber server
allow_tls | [RW] | Allow TLS negotiation? Defaults to true |
features_timeout | [RW] | How many seconds to wait for <stream:features/> before proceeding |
host | [R] | |
keepalive_interval | [RW] | Keep-alive interval in seconds, defaults to 60 (see private method keepalive_loop for implementation details) |
port | [R] | |
ssl_capath | [RW] | Optional CA-Path for TLS-handshake |
ssl_verifycb | [RW] | Optional callback for verification of SSL peer |
use_ssl | [RW] | 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 41: def initialize 42: super() 43: @host = nil 44: @port = nil 45: @allow_tls = defined? OpenSSL 46: @tls = false 47: @ssl_capath = nil 48: @ssl_verifycb = nil 49: @features_timeout = 10 50: @keepalive_interval = 60 51: @use_ssl = false 52: end
# File lib/xmpp4r/connection.rb, line 96 96: def accept_features 97: begin 98: Timeout::timeout(@features_timeout) { 99: Jabber::debuglog("FEATURES: waiting...") 100: @features_sem.wait 101: Jabber::debuglog("FEATURES: waiting finished") 102: } 103: rescue Timeout::Error 104: Jabber::debuglog("FEATURES: timed out when waiting, stream peer seems not XMPP compliant") 105: end 106: 107: if @allow_tls and not is_tls? and @stream_features['starttls'] == 'urn:ietf:params:xml:ns:xmpp-tls' 108: begin 109: starttls 110: rescue 111: Jabber::debuglog("STARTTLS:\nFailure: #{$!}") 112: end 113: end 114: end
Closing connection: first kill keepaliveThread (but only if it‘s not me), then call Stream#close!
# File lib/xmpp4r/connection.rb, line 90 90: def close! 91: @keepaliveThread.kill if @keepaliveThread and @keepaliveThread.alive? and @keepaliveThread != Thread.current 92: super 93: @keepaliveThread.kill if @keepaliveThread and @keepaliveThread.alive? 94: 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 59: def connect(host, port) 60: @host = host 61: @port = port 62: # Reset is_tls?, so that it works when reconnecting 63: @tls = false 64: 65: Jabber::debuglog("CONNECTING:\n#{@host}:#{@port}") 66: @socket = TCPSocket.new(@host, @port) 67: 68: # We want to use the old and deprecated SSL protocol (usually on port 5223) 69: if @use_ssl 70: ssl = OpenSSL::SSL::SSLSocket.new(@socket) 71: ssl.connect # start SSL session 72: ssl.sync_close = true 73: Jabber::debuglog("SSL connection established.") 74: @socket = ssl 75: end 76: 77: start 78: 79: accept_features 80: 81: @keepaliveThread = Thread.new do 82: Thread.current.abort_on_exception = true 83: keepalive_loop 84: end 85: end
Have we gone to TLS mode?
result: | [true] or [false] |
# File lib/xmpp4r/connection.rb, line 182 182: def is_tls? 183: @tls 184: end
Start the parser on the previously connected socket
# File lib/xmpp4r/connection.rb, line 118 118: def start 119: super(@socket) 120: end
Do a <starttls/> (will be automatically done by connect if stream peer supports this)
# File lib/xmpp4r/connection.rb, line 125 125: def starttls 126: stls = REXML::Element.new('starttls') 127: stls.add_namespace('urn:ietf:params:xml:ns:xmpp-tls') 128: 129: reply = nil 130: send(stls) { |r| 131: reply = r 132: true 133: } 134: if reply.name != 'proceed' 135: raise ServerError.new(reply.first_element('error')) 136: end 137: # Don't be interrupted 138: stop 139: 140: begin 141: error = nil 142: 143: # Context/user set-able stuff 144: ctx = OpenSSL::SSL::SSLContext.new 145: if @ssl_capath 146: ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER 147: ctx.ca_path = @ssl_capath 148: else 149: ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE 150: end 151: ctx.verify_callback = @ssl_verifycb 152: 153: # SSL connection establishing 154: sslsocket = OpenSSL::SSL::SSLSocket.new(@socket, ctx) 155: sslsocket.sync_close = true 156: Jabber::debuglog("TLSv1: OpenSSL handshake in progress") 157: sslsocket.connect 158: 159: # Make REXML believe it's a real socket 160: class << sslsocket 161: def kind_of?(o) 162: o == IO ? true : super 163: end 164: end 165: 166: # We're done and will use it 167: @tls = true 168: @socket = sslsocket 169: rescue 170: error = $! 171: ensure 172: Jabber::debuglog("TLSv1: restarting parser") 173: start 174: accept_features 175: raise error if error 176: end 177: end