Class: Mnet::Endpoint

Inherits:
Object
  • Object
show all
Defined in:
lib/mnet.rb

Constant Summary collapse

TICK_INTERVAL =
0.05

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(logger: nil, keys: nil, **opts) ⇒ Endpoint

Returns a new instance of Endpoint.



935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
# File 'lib/mnet.rb', line 935

def initialize(logger: nil, keys: nil, **opts)
  @opts   = opts
  @logger = logger
  @socks  = []            # [socket, created_at] pairs; newest last
  @send_mutex     = Mutex.new
  @sessions       = {}
  @sessions_mutex = Mutex.new
  @accept         = Queue.new
  @running        = false
  @bound          = false

  # Receive window (flow control): capped dynamically to the kernel's
  # actual socket buffer size (Linux clamps via net.core.rmem_max).
  @recv_cap = opts.fetch(:recv_capacity, 256 * 1024)

  # Pre-shared session keys (optional): id -> key, derived like mosh.
  @key_by_id = {}
  (keys || []).each { |k| @key_by_id[Mnet.session_id_from_key(k)] = k }
end

Instance Attribute Details

#socketObject (readonly)

Returns the value of attribute socket.



933
934
935
# File 'lib/mnet.rb', line 933

def socket
  @socket
end

Instance Method Details

#acceptObject



981
982
983
# File 'lib/mnet.rb', line 981

def accept
  @accept.pop
end

#closeObject



989
990
991
992
# File 'lib/mnet.rb', line 989

def close
  @running = false
  @socks.each { |s, _| s.close rescue nil }
end

#dial(host, port, timeout: 5, key: nil, proto: :mnet) ⇒ Object



965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
# File 'lib/mnet.rb', line 965

def dial(host, port, timeout: 5, key: nil, proto: :mnet)
  ensure_bound
  id = key ? Mnet.session_id_from_key(key) : SecureRandom.random_bytes(Mnet::SESSION_ID_LEN)
  klass = proto == :kcp ? KcpSession : Session
  sess = klass.new(self, id, role: :client, peer_addr: [host, port],
                          key: key, logger: @logger, **@opts.merge(recv_capacity: @recv_cap))
  register(sess)
  begin
    sess.send_syn
    sess.wait_established(timeout)
  rescue
    remove_session(id)
    raise
  end
end

#hop(local_host = "0.0.0.0") ⇒ Object Also known as: rebind

mosh-style port hop: open a fresh socket (new source address) and switch to it, keeping the old socket alive briefly to catch delayed packets. In real life you do NOT need to call this -- bind the client socket to 0.0.0.0 and the OS re-picks the source address when the route changes; this is the explicit fallback for testing/deterministic roaming.



999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
# File 'lib/mnet.rb', line 999

def hop(local_host = "0.0.0.0")
  new_sock = nil
  @send_mutex.synchronize do
    new_sock = UDPSocket.new
    configure_socket(new_sock)
    new_sock.bind(local_host, 0)
    @socks << [new_sock, Mnet.now]
  end
  prune_sockets
  @sessions_mutex.synchronize { @sessions.each_value(&:reanchor) }
  new_sock
end

#listen(host = "0.0.0.0", port = 0) ⇒ Object



955
956
957
958
959
960
961
962
963
# File 'lib/mnet.rb', line 955

def listen(host = "0.0.0.0", port = 0)
  sock = UDPSocket.new
  configure_socket(sock)
  sock.bind(host, port)
  @socks << [sock, Mnet.now]
  @bound = true
  start
  self
end

#local_addrObject



985
986
987
# File 'lib/mnet.rb', line 985

def local_addr
  @socks.last[0].addr
end

#remove_session(id) ⇒ Object



1024
1025
1026
# File 'lib/mnet.rb', line 1024

def remove_session(id)
  @sessions_mutex.synchronize { @sessions.delete(id) }
end

#send_raw(data, ip, port) ⇒ Object



1014
1015
1016
1017
1018
1019
1020
1021
1022
# File 'lib/mnet.rb', line 1014

def send_raw(data, ip, port)
  sock = @socks.last[0]
  @send_mutex.synchronize do
    sock.send(data, Mnet::MSG_DONTWAIT, ip, port)
    true
  rescue IO::WaitWritable, IO::WaitReadable, SystemCallError, IOError
    false
  end
end