Class: Vines::Stream::Server

Inherits:
Vines::Stream
  • Object
show all
Defined in:
lib/vines/stream/server.rb,
lib/vines/stream/server/tls.rb,
lib/vines/stream/server/auth.rb,
lib/vines/stream/server/ready.rb,
lib/vines/stream/server/start.rb,
lib/vines/stream/server/auth_restart.rb,
lib/vines/stream/server/outbound/tls.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_result.rb,
lib/vines/stream/server/outbound/auth_restart.rb,
lib/vines/stream/server/outbound/final_restart.rb,
lib/vines/stream/server/outbound/final_features.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, AuthRestart, FinalRestart, Outbound, Ready, Start, TLS

Constant Summary collapse

MECHANISMS =
%w[EXTERNAL].freeze

Constants inherited from Vines::Stream

ERROR, PAD

Instance Attribute Summary collapse

Attributes inherited from Vines::Stream

#config, #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, #ssl_verify_peer, #storage, #update_user_streams, #vhost, #write

Methods included from Log

#log

Constructor Details

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

Returns a new instance of Server.



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

def initialize(config, options={})
  super(config)
  @connected = false
  @remote_domain = options[:to]
  @domain = options[:from]
  @srv = options[:srv]
  @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, 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, 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, callback: callback}
      EM.connect(rr.target.to_s, rr.port, Server, config, opts)
    rescue => e
      connect(config, to, from, srv, callback)
    end
  end
end

.start(config, to, from, &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, &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, 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.



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

def authentication_mechanisms
  MECHANISMS
end

#max_stanza_sizeObject



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

def max_stanza_size
  config[:server].max_stanza_size
end

#notify_connectedObject



103
104
105
106
107
108
109
# File 'lib/vines/stream/server.rb', line 103

def notify_connected
  @connected = true
  if @callback
    @callback.call(self)
    @callback = nil
  end
end

#post_initObject



66
67
68
69
# File 'lib/vines/stream/server.rb', line 66

def post_init
  super
  send_stream_header if @outbound
end

#ready?Boolean

Returns:

  • (Boolean)


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

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

#ssl_handshake_completedObject



75
76
77
78
79
80
# File 'lib/vines/stream/server.rb', line 75

def ssl_handshake_completed
  unless cert_domain_matches?(@remote_domain)
    log.info { 'Cert domain not maches' }
    close_connection
  end
end

#start(node) ⇒ Object



115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/vines/stream/server.rb', line 115

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::UnsupportedVersion unless node['version'] == '1.0'
  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



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

def stream_type
  :server
end

#unbindObject



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

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

#vhost?(domain) ⇒ Boolean

Returns:

  • (Boolean)


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

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