Class Jabber::Connection
In: lib/xmpp4r/connection.rb
Parent: Stream

The connection class manages the TCP connection to the Jabber server

Methods

Attributes

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

Public Class methods

Create a new connection to the given host and port, using threaded mode or not.

[Source]

    # 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

Public Instance methods

[Source]

    # 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!

[Source]

    # 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

[Source]

    # 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]

[Source]

     # File lib/xmpp4r/connection.rb, line 165
165:     def is_tls?
166:       @tls
167:     end

Start the parser on the previously connected socket

[Source]

     # 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)

[Source]

     # 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

Private Instance methods

[Source]

     # 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.

[Source]

     # 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

[Validate]