Module: Hop::TcpBearer
- Defined in:
- lib/hop/tcp_bearer.rb
Overview
The raw-TCP Internet bearer: opaque Hop frames over TCP, core does the Noise. TCP is a stream, so each drained packet is length-prefixed (4-byte big-endian) and reassembled on the far side.
Constant Summary collapse
- MAX_FRAME_BYTES =
1 << 20
Class Method Summary collapse
- .dial(endpoint, host, port) ⇒ Object
- .listen(endpoint, port, host: "0.0.0.0") ⇒ Object
- .next_link ⇒ Object
- .read_exact(sock, n) ⇒ Object
- .recv_loop(endpoint, sock, link) ⇒ Object
- .send_framed(sock, buf) ⇒ Object
Class Method Details
.dial(endpoint, host, port) ⇒ Object
96 97 98 99 100 101 102 103 |
# File 'lib/hop/tcp_bearer.rb', line 96 def self.dial(endpoint, host, port) sock = TCPSocket.new(host, port) link = next_link endpoint.register_link(link, :dialer, ->(buf) { send_framed(sock, buf) }) endpoint.register_closer { sock.close rescue nil } Thread.new { recv_loop(endpoint, sock, link) } sock end |
.listen(endpoint, port, host: "0.0.0.0") ⇒ Object
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/hop/tcp_bearer.rb', line 54 def self.listen(endpoint, port, host: "0.0.0.0") server = TCPServer.new(host, port) sockets = {} sockets_mutex = Mutex.new closing = false endpoint.register_closer do sockets_mutex.synchronize do closing = true server.close rescue nil sockets.each_key { |socket| socket.close rescue nil } end end Thread.new do loop do sock = begin server.accept rescue StandardError break end reject = sockets_mutex.synchronize do if closing true else sockets[sock] = true false end end if reject sock.close rescue nil next end link = next_link endpoint.register_link(link, :acceptor, ->(buf) { send_framed(sock, buf) }) Thread.new do recv_loop(endpoint, sock, link) sockets_mutex.synchronize { sockets.delete(sock) } end end end server end |
.next_link ⇒ Object
12 |
# File 'lib/hop/tcp_bearer.rb', line 12 def self.next_link = @seq_mutex.synchronize { @seq += 1 } |
.read_exact(sock, n) ⇒ Object
20 21 22 23 24 25 26 27 28 29 |
# File 'lib/hop/tcp_bearer.rb', line 20 def self.read_exact(sock, n) data = +"".b while data.bytesize < n chunk = sock.read(n - data.bytesize) return nil unless chunk data << chunk end data end |
.recv_loop(endpoint, sock, link) ⇒ Object
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/hop/tcp_bearer.rb', line 31 def self.recv_loop(endpoint, sock, link) loop do hdr = read_exact(sock, 4) break unless hdr n = hdr.unpack1("N") break if n > MAX_FRAME_BYTES frame = n.zero? ? "".b : read_exact(sock, n) break unless frame endpoint.deliver(link, frame) end rescue IOError, Errno::ECONNRESET, Errno::EBADF nil ensure endpoint.link_down(link) begin sock.close rescue StandardError nil end end |
.send_framed(sock, buf) ⇒ Object
14 15 16 17 18 |
# File 'lib/hop/tcp_bearer.rb', line 14 def self.send_framed(sock, buf) sock.write([buf.bytesize].pack("N") + buf) rescue IOError, Errno::EPIPE, Errno::ECONNRESET, Errno::EBADF nil end |