Class: Pione::Relay::RelaySocket

Inherits:
DRb::DRbSSLSocket
  • Object
show all
Defined in:
lib/pione/relay/relay-socket.rb

Overview

RelaySocket is connection layer between PIONE client and PIONE relay.

Defined Under Namespace

Classes: AuthError, BadMessage, ProxyError

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.open(uri, config) ⇒ Object

Opens the socket on pione-client.



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/pione/relay/relay-socket.rb', line 27

def self.open(uri, config)
  host, port, option = parse_uri(uri)
  host.untaint
  port.untaint

  # make tcp connection with SSL
  soc = TCPSocket.open(host, port)
  ssl_conf = DRb::DRbSSLSocket::SSLConfig.new(config)
  ssl_conf.setup_ssl_context
  ssl = ssl_conf.connect(soc)

  if Global.show_communication
    puts "you connected relay socket to %s" % uri
  end

  # auth like HTTP's digest method
  begin
    Timeout.timeout(Global.relay_client_auth_timeout_sec) do
      realm = ssl.gets.chomp
      uuid = ssl.gets.chomp
       = Global.[realm] || (raise AuthError.new("unknown realm: %s" % realm))
      name = .name
      digest = .digest
      response = "%s:%s" % [name, Digest::SHA512.hexdigest("%s:%s" % [uuid, digest])]
      ssl.puts(response)
      unless ssl.read(3).chomp == "OK"
        raise AuthError.new("authentication failed")
      end
    end
  rescue AuthError => e
    raise e
  rescue Timeout::Error
    raise AuthError.new("authentication timeout")
  end

  if Global.show_communication
    puts "you succeeded relay authentication: %s" % uri
  end

  # create receiver socket
  ReceiverSocket.table["%s:%s" % [host, port]] = ssl
  Global.relay_receiver = DRb::DRbServer.new(
    "receiver://%s:%s" % [host, port],
    Global.relay_tuple_space_server
  )

  # create an instance
  return self.new(uri, ssl, ssl_conf, true)
end

.open_server(uri, config) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Opens relay server port for clients.



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/pione/relay/relay-socket.rb', line 79

def self.open_server(uri, config)
  # parse URI
  uri = 'relay://:%s' % Global.relay_port unless uri
  host, port, option = parse_uri(uri)

  # rebuild URI
  if host.size == 0
    host = getservername
    soc = open_server_inaddr_any(host, port)
  else
    soc = TCPServer.open(host, port)
  end
  port = soc.addr[1] if port == 0
  new_uri = "relay://#{host}:#{port}"

  # prepare SSL
  ssl_conf = DRb::DRbSSLSocket::SSLConfig.new(config).tap do |conf|
    conf.setup_certificate
    conf.setup_ssl_context
  end

  # create instance
  self.new(new_uri, soc, ssl_conf, false)
end

.parse_uri(uri) ⇒ Object



14
15
16
17
18
19
20
21
22
23
24
# File 'lib/pione/relay/relay-socket.rb', line 14

def self.parse_uri(uri)
  if uri =~ /^relay:\/\/(.*?)(:(\d+))?(\?(.*))?$/
    host = $1
    port = $3 ? $3.to_i : Global.relay_port
    option = $5
    return host, port, option
  else
    raise DRb::DRbBadScheme.new(uri) unless uri =~ /^relay:/
    raise DRb::DRbBadURI.new('can\'t parse uri:' + uri)
  end
end

.uri_option(uri, config) ⇒ Object



104
105
106
107
# File 'lib/pione/relay/relay-socket.rb', line 104

def self.uri_option(uri, config)
  host, port, option = parse_uri(uri)
  return "relay://#{host}:#{port}", option
end

Instance Method Details

#acceptObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Accepts pione-clients on server side.



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
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
# File 'lib/pione/relay/relay-socket.rb', line 111

def accept
  begin
    # accept loop
    while true
      soc = @socket.accept
      break if (@acl ? @acl.allow_socket?(soc) : true)
      soc.close
    end

    if Global.show_communication
      puts "someone connected to relay socket..."
    end

    # build ssl
    ssl = @config.accept(soc)

    # relay auth like HTTP's digest method
    ssl.puts(Global.relay_realm)
    uuid = Util::UUID.generate
    ssl.puts(uuid)
    if msg = ssl.gets
      name, digest = msg.chomp.split(":")
      unless Global.relay_client_db.auth(uuid, name, digest)
        raise AuthError.new(name)
      end
      ssl.puts "OK"

      if Global.show_communication
        puts "succeeded authentication for %s" % name
      end

      # setup transmitter_id
      transmitter_id = Util::UUID.generate

      # save ssl socket as receiver side with transmitter_id
      TransmitterSocket.receiver_socket[transmitter_id] = ssl

      # open and save tcp socket with transmitter_id
      Global.relay_transmitter_proxy_side_port_range.each do |port|
        begin
          tcp_socket = TCPServer.new("localhost", port)
          TransmitterSocket.proxy_socket[transmitter_id] = tcp_socket
          break
        rescue
        end
      end

      # create servers
      transmitter_server = create_transmitter_server(transmitter_id)
      proxy_server = create_proxy_server(transmitter_id)

      # start to provide the proxy server
      TupleSpaceProvider.instance.add_tuple_space_server(
        DRb::DRbObject.new_with_uri(proxy_server.uri)
      )

      # create instance
      self.class.new(uri, ssl, @config, true)
    else
      raise BadMessage
    end
  rescue OpenSSL::SSL::SSLError, AuthError, BadMessage => e
    soc.close
    Log::Debug.communication("relay socket was closed: %s" % e.message)
    retry
  end
end

#create_proxy_server(transmitter_id) ⇒ Object

Creates a proxy server for brokers in LAN.

Raises:



191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# File 'lib/pione/relay/relay-socket.rb', line 191

def create_proxy_server(transmitter_id)
  transmitter = DRb::DRbObject.new_with_uri("transmitter://%s" % transmitter_id)
  Global.relay_proxy_port_range.each do |port|
    begin
      uri = "druby://localhost:%s" % port
      server = DRb::DRbServer.new(uri, transmitter)
      if Global.show_communication
        puts "relay created the proxy: %s" % server.uri
      end
      return server
    rescue
      next
    end
  end
  raise ProxyError.new("You cannot start relay proxy server.")
end

#create_transmitter_server(transmitter_id) ⇒ void

This method returns an undefined value.

Creates a transmitter server with the relay socket.



181
182
183
184
185
186
187
188
# File 'lib/pione/relay/relay-socket.rb', line 181

def create_transmitter_server(transmitter_id)
  uri = "transmitter://%s" % transmitter_id
  server = DRb::DRbServer.new(uri, Trampoline.new(uri, @config))
  if Global.show_communication
    puts "relay created the transmitter: %s" % server.uri
  end
  return server
end