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

Constants inherited from Vines::Stream

ERROR, PAD

Instance Attribute Summary collapse

Attributes inherited from Vines::Stream

#user

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Vines::Stream

#advance, #cert_domain_matches?, #close_connection, #encrypt, #encrypt?, #error, #receive_data, #router, #ssl_verify_peer, #storage, #update_user_streams, #write

Methods included from Log

#log

Constructor Details

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

Returns a new instance of Server.



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

def initialize(config, options={})
  @config = config
  @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

#configObject (readonly)

Returns the value of attribute config.



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

def config
  @config
end

#domainObject (readonly)

Returns the value of attribute domain.



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

def domain
  @domain
end

#remote_domainObject

Returns the value of attribute remote_domain.



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

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
# File 'lib/vines/stream/server.rb', line 36

def self.connect(config, to, from, srv, callback)
  if srv.empty?
    callback.call(nil)
  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 Exception => 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

#max_stanza_sizeObject



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

def max_stanza_size
  @config[:server].max_stanza_size
end

#notify_connectedObject



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

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

#post_initObject



64
65
66
67
# File 'lib/vines/stream/server.rb', line 64

def post_init
  super
  send_stream_header if @outbound
end

#ready?Boolean

Returns:

  • (Boolean)


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

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

#ssl_handshake_completedObject



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

def ssl_handshake_completed
  close_connection unless cert_domain_matches?(@remote_domain)
end

#start(node) ⇒ Object



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

def start(node)
  if @outbound then send_stream_header; return end
  @domain, @remote_domain = %w[to from].map {|a| node[a] }
  send_stream_header
  raise StreamErrors::UnsupportedVersion unless node['version'] == '1.0'
  raise StreamErrors::ImproperAddressing if [@domain, @remote_domain].any? {|addr| (addr || '').strip.empty? }
  raise StreamErrors::HostUnknown unless @config.vhost?(@domain)
  raise StreamErrors::NotAuthorized unless @config.s2s?(@remote_domain)
  raise StreamErrors::InvalidNamespace unless node.namespaces['xmlns'] == NAMESPACES[:server]
  raise StreamErrors::InvalidNamespace unless node.namespaces['xmlns:stream'] == NAMESPACES[:stream]
end

#stream_typeObject



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

def stream_type
  :server
end

#unbindObject



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

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

#vhost?(domain) ⇒ Boolean

Returns:

  • (Boolean)


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

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