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 |
Create a new connection to the given host and port, using threaded mode or not.
# File lib/xmpp4r/connection.rb, line 36 36: def initialize(threaded = true) 37: super(threaded) 38: @host = nil 39: @port = nil 40: @allow_tls = true 41: @tls = false 42: @ssl_capath = nil 43: @ssl_verifycb = nil 44: @features_timeout = 10 45: @keepalive_interval = 60 46: end
# File lib/xmpp4r/connection.rb, line 79 79: def accept_features 80: begin 81: Timeout::timeout(@features_timeout) { 82: Jabber::debuglog("FEATURES: waiting...") 83: @features_sem.wait 84: Jabber::debuglog("FEATURES: waiting finished") 85: } 86: rescue Timeout::Error 87: Jabber::debuglog("FEATURES: timed out when waiting, stream peer seems not XMPP compliant") 88: end 89: 90: if @allow_tls and not is_tls? and @stream_features['starttls'] == 'urn:ietf:params:xml:ns:xmpp-tls' 91: begin 92: starttls 93: rescue 94: Jabber::debuglog("STARTTLS:\nFailure: #{$!}") 95: end 96: end 97: end
Closing connection: first kill keepaliveThread, then call Stream#close!
# File lib/xmpp4r/connection.rb, line 74 74: def close! 75: @keepaliveThread.kill if @keepaliveThread and @keepaliveThread.alive? 76: super 77: 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 53 53: def connect(host, port) 54: @host = host 55: @port = port 56: # Reset is_tls?, so that it works when reconnecting 57: @tls = false 58: 59: Jabber::debuglog("CONNECTING:\n#{@host}:#{@port}") 60: @socket = TCPSocket.new(@host, @port) 61: start 62: 63: accept_features 64: 65: @keepaliveThread = Thread.new do 66: Thread.current.abort_on_exception = true 67: keepalive_loop 68: end 69: end
Have we gone to TLS mode?
result: | [true] or [false] |
# File lib/xmpp4r/connection.rb, line 165 165: def is_tls? 166: @tls 167: end
Start the parser on the previously connected socket
# File lib/xmpp4r/connection.rb, line 101 101: def start 102: super(@socket) 103: end
Do a <starttls/> (will be automatically done by connect if stream peer supports this)
# File lib/xmpp4r/connection.rb, line 108 108: def starttls 109: stls = REXML::Element.new('starttls') 110: stls.add_namespace('urn:ietf:params:xml:ns:xmpp-tls') 111: 112: reply = nil 113: send(stls) { |r| 114: reply = r 115: true 116: } 117: if reply.name != 'proceed' 118: raise ErrorException(reply.first_element('error')) 119: end 120: # Don't be interrupted 121: stop 122: 123: begin 124: error = nil 125: 126: # Context/user set-able stuff 127: ctx = OpenSSL::SSL::SSLContext.new('TLSv1') 128: if @ssl_capath 129: ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER 130: ctx.ca_path = @ssl_capath 131: else 132: ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE 133: end 134: ctx.verify_callback = @ssl_verifycb 135: 136: # SSL connection establishing 137: sslsocket = OpenSSL::SSL::SSLSocket.new(@socket, ctx) 138: sslsocket.sync_close = true 139: Jabber::debuglog("TLSv1: OpenSSL handshake in progress") 140: sslsocket.connect 141: 142: # Make REXML believe it's a real socket 143: class << sslsocket 144: def kind_of?(o) 145: o == IO ? true : super 146: end 147: end 148: 149: # We're done and will use it 150: @tls = true 151: @socket = sslsocket 152: rescue 153: error = $! 154: ensure 155: Jabber::debuglog("TLSv1: restarting parser") 156: start 157: accept_features 158: raise error if error 159: end 160: end
# File lib/xmpp4r/connection.rb, line 169 169: def generate_stream_start(to=nil, from=nil, id=nil, xml_lang="en", xmlns="jabber:client", version="1.0") 170: stream_start_string = "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' " 171: stream_start_string += "xmlns='#{xmlns}' " unless xmlns.nil? 172: stream_start_string += "to='#{to}' " unless to.nil? 173: stream_start_string += "from='#{from}' " unless from.nil? 174: stream_start_string += "id='#{id}' " unless id.nil? 175: stream_start_string += "xml:lang='#{xml_lang}' " unless xml_lang.nil? 176: stream_start_string += "version='#{version}' " unless version.nil? 177: stream_start_string += ">" 178: stream_start_string 179: end
A loop to send "keep alive" data to prevent the Jabber connection from closing for inactivity.
This loop sends a single white-space character if no other data has been sent in the last @keepalive_interval seconds.
# File lib/xmpp4r/connection.rb, line 189 189: def keepalive_loop 190: loop do 191: difference = @last_send + @keepalive_interval - Time.now 192: if difference <= 0 193: send(' ') 194: sleep @keepalive_interval 195: else 196: sleep(difference) 197: end 198: end 199: end