| 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