Class: Jabber::Connection

Inherits:
Stream
  • Object
show all
Defined in:
lib/xmpp4r/connection.rb

Overview

The connection class manages the TCP connection to the Jabber server

Direct Known Subclasses

Client, Component

Defined Under Namespace

Classes: SSLSocketUTF8

Constant Summary

Constants inherited from Stream

Stream::CONNECTED, Stream::DISCONNECTED

Instance Attribute Summary collapse

Attributes inherited from Stream

#fd, #processing, #status

Instance Method Summary collapse

Methods inherited from Stream

#add_iq_callback, #add_message_callback, #add_presence_callback, #add_stanza_callback, #add_xml_callback, #close, #delete_iq_callback, #delete_message_callback, #delete_presence_callback, #delete_stanza_callback, #delete_xml_callback, #iq_callbacks, #is_connected?, #is_disconnected?, #message_callbacks, #on_exception, #parse_failure, #parser_end, #presence_callbacks, #receive, #send, #send_data, #send_with_id, #stanza_callbacks, #stop, #xml_callbacks

Constructor Details

#initializeConnection

Create a new connection to the given host and port


51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/xmpp4r/connection.rb', line 51

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

Instance Attribute Details

#allow_tlsObject

Allow TLS negotiation? Defaults to true


28
29
30
# File 'lib/xmpp4r/connection.rb', line 28

def allow_tls
  @allow_tls
end

#features_timeoutObject

How many seconds to wait for <stream:features/> before proceeding


20
21
22
# File 'lib/xmpp4r/connection.rb', line 20

def features_timeout
  @features_timeout
end

#hostObject (readonly)

Returns the value of attribute host


16
17
18
# File 'lib/xmpp4r/connection.rb', line 16

def host
  @host
end

#keepalive_intervalObject

Keep-alive interval in seconds, or nil to disable keepalive, defaults to 60 (see private method keepalive_loop for implementation details)


25
26
27
# File 'lib/xmpp4r/connection.rb', line 25

def keepalive_interval
  @keepalive_interval
end

#portObject (readonly)

Returns the value of attribute port


16
17
18
# File 'lib/xmpp4r/connection.rb', line 16

def port
  @port
end

#ssl_capathObject

Optional CA-Path for TLS-handshake


31
32
33
# File 'lib/xmpp4r/connection.rb', line 31

def ssl_capath
  @ssl_capath
end

#ssl_verifycbObject

Optional callback for verification of SSL peer


34
35
36
# File 'lib/xmpp4r/connection.rb', line 34

def ssl_verifycb
  @ssl_verifycb
end

#use_sslObject

whether to use the old and deprecated SSL protocol Defaults to false


38
39
40
# File 'lib/xmpp4r/connection.rb', line 38

def use_ssl
  @use_ssl
end

Instance Method Details

#accept_featuresObject


108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/xmpp4r/connection.rb', line 108

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

#close!Object

Closing connection: first kill keepaliveThread (but only if it's not me), then call Stream#close!


102
103
104
105
106
# File 'lib/xmpp4r/connection.rb', line 102

def close!
  @keepaliveThread.kill if @keepaliveThread and @keepaliveThread.alive? and @keepaliveThread != Thread.current
  super
  @keepaliveThread.kill if @keepaliveThread and @keepaliveThread.alive?
end

#connect(host, port) ⇒ Object

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


69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/xmpp4r/connection.rb', line 69

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 = SSLSocketUTF8.new(@socket)
    ssl.connect # start SSL session
    ssl.sync_close = true
    Jabber::debuglog("SSL connection established.")
    @socket = ssl
  end

  start

  accept_features

  unless @keepalive_interval.nil?
    @keepaliveThread = Thread.new do
      Thread.current.abort_on_exception = true
      keepalive_loop
    end
  end
end

#is_tls?Boolean

Have we gone to TLS mode?

result
true

or [false]

Returns:

  • (Boolean)

194
195
196
# File 'lib/xmpp4r/connection.rb', line 194

def is_tls?
  @tls
end

#startObject

Start the parser on the previously connected socket


130
131
132
# File 'lib/xmpp4r/connection.rb', line 130

def start
  super(@socket)
end

#starttlsObject

Do a <starttls/> (will be automatically done by connect if stream peer supports this)


137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/xmpp4r/connection.rb', line 137

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 = SSLSocketUTF8.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