Class: Vines::Stream::Server

Inherits:
Vines::Stream
  • Object
show all
Defined in:
lib/vines/stream/server.rb,
lib/vines/stream/server/auth.rb,
lib/vines/stream/server/ready.rb,
lib/vines/stream/server/start.rb,
lib/vines/stream/server/auth_method.rb,
lib/vines/stream/server/auth_restart.rb,
lib/vines/stream/server/final_restart.rb,
lib/vines/stream/server/outbound/auth.rb,
lib/vines/stream/server/outbound/start.rb,
lib/vines/stream/server/outbound/tls_result.rb,
lib/vines/stream/server/outbound/auth_restart.rb,
lib/vines/stream/server/outbound/auth_external.rb,
lib/vines/stream/server/outbound/authoritative.rb,
lib/vines/stream/server/outbound/final_restart.rb,
lib/vines/stream/server/outbound/final_features.rb,
lib/vines/stream/server/outbound/auth_dialback_result.rb,
lib/vines/stream/server/outbound/auth_external_result.rb

Overview

Implements the XMPP protocol for server-to-server (s2s) streams. This serves connected streams using the jabber:server namespace. This handles both accepting incoming s2s streams and initiating outbound s2s streams to other servers.

Defined Under Namespace

Classes: Auth, AuthMethod, AuthRestart, FinalRestart, Outbound, Ready, Start

Constant Summary collapse

MECHANISMS =
%w[EXTERNAL].freeze

Constants inherited from Vines::Stream

ERROR, PAD, STREAM

Instance Attribute Summary collapse

Attributes inherited from Vines::Stream

#config, #id, #state, #user

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Vines::Stream

#advance, #available_resources, #cert_domain_matches?, #close_connection, #connected_resources, #create_parser, #encrypt, #encrypt?, #error, #interested_resources, #receive_data, #reset, #router, #storage, #update_user_streams, #vhost, #write

Methods included from Log

#log, set_log_file

Constructor Details

#initialize(config, options = {}) ⇒ Server

Returns a new instance of Server.



54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/vines/stream/server.rb', line 54

def initialize(config, options={})
  super(config)
  @outbound_tls_required = false
  @peer_trusted = nil
  @connected = false
  @remote_domain = options[:to]
  @domain = options[:from]
  @srv = options[:srv]
  @dialback_verify_key = options[:dialback_verify_key]
  @callback = options[:callback]
  @outbound = @remote_domain && @domain
  start = @outbound ? Outbound::Start.new(self) : Start.new(self)
  advance(start)
end

Instance Attribute Details

#domainObject (readonly)

Returns the value of attribute domain.



51
52
53
# File 'lib/vines/stream/server.rb', line 51

def domain
  @domain
end

#remote_domainObject

Returns the value of attribute remote_domain.



52
53
54
# File 'lib/vines/stream/server.rb', line 52

def remote_domain
  @remote_domain
end

Class Method Details

.connect(config, to, from, srv, dialback_verify_key = false, callback) ⇒ Object



36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/vines/stream/server.rb', line 36

def self.connect(config, to, from, srv, dialback_verify_key = false, callback)
  if srv.empty?
    # fiber so storage calls work properly
    Fiber.new { callback.call(nil) }.resume
  else
    begin
      rr = srv.shift
      opts = {to: to, from: from, srv: srv, dialback_verify_key: dialback_verify_key, callback: callback}
      EM.connect(rr.target.to_s, rr.port, Server, config, opts)
    rescue => e
      connect(config, to, from, srv, dialback_verify_key, callback)
    end
  end
end

.start(config, to, from, dialback_verify_key = false, &callback) ⇒ Object

Starts the connection to the remote server. When the stream is connected and ready to send stanzas it will yield to the callback block. The callback is run on the EventMachine reactor thread. The yielded stream will be nil if the remote connection failed. We need to use a background thread to avoid blocking the server on DNS SRV lookups.



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/vines/stream/server.rb', line 18

def self.start(config, to, from, dialback_verify_key = false, &callback)
  op = proc do
    Resolv::DNS.open do |dns|
      dns.getresources("_xmpp-server._tcp.#{to}", Resolv::DNS::Resource::IN::SRV)
    end.sort! {|a,b| a.priority == b.priority ? b.weight <=> a.weight : a.priority <=> b.priority }
  end
  cb = proc do |srv|
    if srv.empty?
      srv << {target: to, port: 5269}
      class << srv.first
        def method_missing(name); self[name]; end
      end
    end
    Server.connect(config, to, from, srv, dialback_verify_key, callback)
  end
  EM.defer(proc { op.call rescue [] }, cb)
end

Instance Method Details

#authentication_mechanismsObject

Return an array of allowed authentication mechanisms advertised as server stream features.



106
107
108
# File 'lib/vines/stream/server.rb', line 106

def authentication_mechanisms
  MECHANISMS
end

#callback!Object



131
132
133
# File 'lib/vines/stream/server.rb', line 131

def callback!
  @callback.call(self) if @callback
end

#dialback_retry?Boolean

Returns:

  • (Boolean)


87
88
89
90
# File 'lib/vines/stream/server.rb', line 87

def dialback_retry?
  return false if @peer_trusted.nil? || @peer_trusted
  true
end

#dialback_verify_key?Boolean

Returns:

  • (Boolean)


135
136
137
# File 'lib/vines/stream/server.rb', line 135

def dialback_verify_key?
  @dialback_verify_key
end

#max_stanza_sizeObject



74
75
76
# File 'lib/vines/stream/server.rb', line 74

def max_stanza_size
  config[:server].max_stanza_size
end

#notify_connectedObject



125
126
127
128
129
# File 'lib/vines/stream/server.rb', line 125

def notify_connected
  @connected = true
  self.callback!
  @callback = nil
end

#outbound_tls_required(required) ⇒ Object



100
101
102
# File 'lib/vines/stream/server.rb', line 100

def outbound_tls_required(required)
  @outbound_tls_required = required
end

#outbound_tls_required?Boolean

Returns:

  • (Boolean)


96
97
98
# File 'lib/vines/stream/server.rb', line 96

def outbound_tls_required?
  @outbound_tls_required
end

#peer_trusted?Boolean

Returns:

  • (Boolean)


83
84
85
# File 'lib/vines/stream/server.rb', line 83

def peer_trusted?
  !@peer_trusted.nil? && @peer_trusted
end

#post_initObject



69
70
71
72
# File 'lib/vines/stream/server.rb', line 69

def post_init
  super
  send_stream_header if @outbound
end

#ready?Boolean

Returns:

  • (Boolean)


139
140
141
# File 'lib/vines/stream/server.rb', line 139

def ready?
  state.class == Server::Ready
end

#ssl_handshake_completedObject



92
93
94
# File 'lib/vines/stream/server.rb', line 92

def ssl_handshake_completed
  @peer_trusted = cert_domain_matches?(@remote_domain) && peer_trusted?
end

#ssl_verify_peer(pem) ⇒ Object



78
79
80
81
# File 'lib/vines/stream/server.rb', line 78

def ssl_verify_peer(pem)
  @peer_trusted = @store.trusted?(pem)
  true
end

#start(node) ⇒ Object



143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/vines/stream/server.rb', line 143

def start(node)
  if @outbound then send_stream_header; return end
  to, from = %w[to from].map {|a| node[a] }
  @domain, @remote_domain = to, from unless @domain
  send_stream_header
  raise StreamErrors::NotAuthorized if domain_change?(to, from)
  raise StreamErrors::ImproperAddressing unless valid_address?(@domain) && valid_address?(@remote_domain)
  raise StreamErrors::HostUnknown unless config.vhost?(@domain) || config.pubsub?(@domain) || config.component?(@domain)
  raise StreamErrors::NotAuthorized unless config.s2s?(@remote_domain) && config.allowed?(@domain, @remote_domain)
  raise StreamErrors::InvalidNamespace unless node.namespaces['xmlns'] == NAMESPACES[:server]
  raise StreamErrors::InvalidNamespace unless node.namespaces['xmlns:stream'] == NAMESPACES[:stream]
end

#stream_typeObject



110
111
112
# File 'lib/vines/stream/server.rb', line 110

def stream_type
  :server
end

#unbindObject



114
115
116
117
118
119
# File 'lib/vines/stream/server.rb', line 114

def unbind
  super
  if @outbound && !@connected
    Server.connect(config, @remote_domain, @domain, @srv, @callback)
  end
end

#vhost?(domain) ⇒ Boolean

Returns:

  • (Boolean)


121
122
123
# File 'lib/vines/stream/server.rb', line 121

def vhost?(domain)
  config.vhost?(domain)
end