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

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



42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/xmpp4r/connection.rb', line 42

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



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/xmpp4r/connection.rb', line 99

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!



93
94
95
96
97
# File 'lib/xmpp4r/connection.rb', line 93

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



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/xmpp4r/connection.rb', line 60

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 = OpenSSL::SSL::SSLSocket.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)


185
186
187
# File 'lib/xmpp4r/connection.rb', line 185

def is_tls?
  @tls
end

#startObject

Start the parser on the previously connected socket



121
122
123
# File 'lib/xmpp4r/connection.rb', line 121

def start
  super(@socket)
end

#starttlsObject

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



128
129
130
131
132
133
134
135
136
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
# File 'lib/xmpp4r/connection.rb', line 128

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 = OpenSSL::SSL::SSLSocket.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