Module: Mnet

Defined in:
lib/mnet.rb,
lib/mnet/version.rb

Defined Under Namespace

Modules: SessionIO Classes: Endpoint, Frame, KcpSession, Packet, Server, Session

Constant Summary collapse

MAGIC =
"\x12\xE9\x97".b
MAGIC_LEN =
3
SESSION_ID_LEN =
16
IP_MTU =

Conservative MTU for mobile networks / VPN tunnels (mosh uses 1280).

1280
DEFAULT_MSS =

IP(20) + UDP(8) + our header + GCM tag(16) leaves ~1190 for a segment.

1200
MIN_RTO =

RTO bounds (mosh: MIN_RTO = 50ms, MAX_RTO = 1000ms).

0.05
MAX_RTO =
1.0
MAX_OLD_SOCKET_AGE =

How long to keep a superseded (hopped-away-from) socket alive to catch delayed packets (mosh: MAX_OLD_SOCKET_AGE = 60000ms).

60.0
MSG_DONTWAIT =

非阻塞发送标志:POSIX 有 MSG_DONTWAIT,Windows 没有(用 nonblock 模式兜底)。

Socket.const_defined?(:MSG_DONTWAIT) ? Socket::MSG_DONTWAIT : 0
TYPE_SYN =

Message types (mirrors the enum-message-types pattern from tmux-protocol.h).

0x01
TYPE_SYNACK =
0x02
TYPE_DATA =
0x03
TYPE_ACK =
0x04
TYPE_FIN =
0x05
TYPE_PING =
0x06
TYPE_PONG =
0x07
FLAG_NONE =
0x00
FLAG_MIGRATE =
0x01
FLAG_KCP =

session uses the KCP (C) engine instead of the Ruby ARQ

0x02
HEADER_LEN =
MAGIC_LEN + SESSION_ID_LEN + 8 + 8 + 1 + 1 + 4
MAX_RETRIES =
10
TYPES =
{
  TYPE_SYN => "SYN", TYPE_SYNACK => "SYNACK", TYPE_DATA => "DATA",
  TYPE_ACK => "ACK", TYPE_FIN => "FIN", TYPE_PING => "PING",
  TYPE_PONG => "PONG"
}.freeze
VERSION =
'0.1.3'

Class Method Summary collapse

Class Method Details

.addr_pair(addr) ⇒ Object



93
94
95
# File 'lib/mnet.rb', line 93

def addr_pair(addr)
  [addr[3], addr[1]]
end

.fmt(addr) ⇒ Object



97
98
99
# File 'lib/mnet.rb', line 97

def fmt(addr)
  "#{addr[0]}:#{addr[1]}"
end

.now ⇒ Object



101
102
103
# File 'lib/mnet.rb', line 101

def now
  Process.clock_gettime(Process::CLOCK_MONOTONIC)
end

.pack(session_id, seq, ack, type, flags, window, payload = "".b) ⇒ Object



76
77
78
79
# File 'lib/mnet.rb', line 76

def pack(session_id, seq, ack, type, flags, window, payload = "".b)
  [MAGIC, session_id, seq, ack, type, flags, window, payload]
    .pack("a3a16Q>Q>CCNa*")
end

.session_id_from_key(key) ⇒ Object

Session id is derived from the shared session key (mosh-style), so the id identifies the key and vice versa; without a key it is just random.



107
108
109
# File 'lib/mnet.rb', line 107

def session_id_from_key(key)
  OpenSSL::Digest::SHA256.digest(key)[0, SESSION_ID_LEN]
end

.socket_pair ⇒ Object

A connected stream socket pair, portable across Windows/Linux/macOS. Prefers a UNIX socketpair; falls back to a loopback TCP pair where AF_UNIX socketpair is unavailable (Windows).



114
115
116
117
118
119
120
121
122
123
# File 'lib/mnet.rb', line 114

def socket_pair
  Socket.pair(:UNIX, :STREAM, 0)
rescue SystemCallError, NotImplementedError
  server = TCPServer.new("127.0.0.1", 0)
  port   = server.addr[1]
  client = TCPSocket.new("127.0.0.1", port)
  accepted = server.accept
  server.close
  [accepted, client]
end

.type_name(type) ⇒ Object



89
90
91
# File 'lib/mnet.rb', line 89

def type_name(type)
  TYPES.fetch(type, "UNKNOWN(#{type})")
end

.unpack(data) ⇒ Object



81
82
83
84
85
86
87
# File 'lib/mnet.rb', line 81

def unpack(data)
  return nil if data.bytesize < HEADER_LEN
  magic, sid, seq, ack, type, flags, window = data.unpack("a3a16Q>Q>CCN")
  return nil unless magic == MAGIC
  Packet.new(sid, seq, ack, type, flags, window,
             data.byteslice(HEADER_LEN, data.bytesize - HEADER_LEN) || "".b)
end