Start working on proper packet header

This commit is contained in:
ChillerDragon 2022-10-30 19:00:13 +01:00
parent f75eaebcee
commit b7a2cfb5c3
4 changed files with 85 additions and 19 deletions

View file

@ -3,7 +3,7 @@ require_relative 'network'
require_relative 'bytes' require_relative 'bytes'
class NetChunk class NetChunk
attr_reader :next, :data, :msg, :sys attr_reader :next, :data, :msg, :sys, :flags
def initialize(data) def initialize(data)
@next = nil @next = nil
@ -37,6 +37,14 @@ class NetChunk
# sequence number # sequence number
# in da third byte but who needs seq?! # in da third byte but who needs seq?!
end end
def flags_vital
@flags[:vital]
end
def flags_resend
@flags[:resend]
end
end end
MAX_NUM_CHUNKS = 1024 MAX_NUM_CHUNKS = 1024

View file

@ -79,6 +79,8 @@ NET_CTRLMSG_ACCEPT = 2
NET_CTRLMSG_CLOSE = 4 NET_CTRLMSG_CLOSE = 4
NET_CTRLMSG_TOKEN = 5 NET_CTRLMSG_TOKEN = 5
NET_MAX_SEQUENCE = 1<<10
NET_CONNSTATE_OFFLINE = 0 NET_CONNSTATE_OFFLINE = 0
NET_CONNSTATE_TOKEN = 1 NET_CONNSTATE_TOKEN = 1
NET_CONNSTATE_CONNECT = 2 NET_CONNSTATE_CONNECT = 2

View file

@ -1,5 +1,46 @@
require 'huffman_tw' require 'huffman_tw'
class PacketFlags
attr_reader :bits, :hash
def initialize(data)
@hash = {}
@bits = ''
if data.class == Hash
@bits = parse_hash(data)
@hash = data
elsif data.class == String
@hash = parse_bits(data)
@bits = data
else
raise "Flags have to be hash or string"
end
end
def parse_hash(hash)
bits = ''
bits += hash[:connection] == '1' ? '1' : '0'
bits += hash[:compressed] == '1' ? '1' : '0'
bits += hash[:resend] == '1' ? '1' : '0'
bits += hash[:control] == '1' ? '1' : '0'
bits
end
def parse_bits(four_bit_str)
# takes a 4 character string
# representing the middle of the first byte sent
# in binary representation
#
# and creates a hash out of it
hash = {}
hash[:connection] = four_bit_str[0] == '1'
hash[:compressed] = four_bit_str[1] == '1'
hash[:resend] = four_bit_str[2] == '1'
hash[:control] = four_bit_str[3] == '1'
hash
end
end
# Class holding the parsed packet data # Class holding the parsed packet data
class Packet class Packet
attr_reader :flags, :payload attr_reader :flags, :payload
@ -14,10 +55,9 @@ class Packet
# network direction (client/server) # network direction (client/server)
@prefix = prefix @prefix = prefix
@huffman = Huffman.new @huffman = Huffman.new
@flags = {}
@data = data @data = data
flags_byte = @data[0].unpack("B*") flags_byte = @data[0].unpack("B*")
parse_flags(flags_byte.first[2..5]) @flags = PacketFlags.new(flags_byte.first[2..5]).hash
@payload = @data[PACKET_HEADER_SIZE..] @payload = @data[PACKET_HEADER_SIZE..]
if flags_compressed if flags_compressed
@payload = @huffman.decompress(@payload.unpack("C*")) @payload = @huffman.decompress(@payload.unpack("C*"))
@ -51,20 +91,6 @@ class Packet
puts "" puts ""
end end
def parse_flags(four_bit_str)
# takes a 4 character string
# representing the middle of the first byte sent
# in binary representation
#
# and creates a hash out of it
@flags = {}
@flags[:connection] = four_bit_str[0] == '1'
@flags[:compressed] = four_bit_str[1] == '1'
@flags[:resend] = four_bit_str[2] == '1'
@flags[:control] = four_bit_str[3] == '1'
@flags
end
def flags_compressed() def flags_compressed()
@flags[:compressed] @flags[:compressed]
end end

View file

@ -11,25 +11,51 @@ require_relative 'lib/chunk'
require_relative 'lib/server_info' require_relative 'lib/server_info'
class NetBase class NetBase
attr_accessor :client_token, :server_token attr_accessor :client_token, :server_token, :ack
def initialize def initialize
@ip = nil @ip = nil
@port = nil @port = nil
@s = nil @s = nil
@ack = 0
end end
def connect(socket, ip, port) def connect(socket, ip, port)
@s = socket @s = socket
@ip = ip @ip = ip
@port = port @port = port
@ack = 0
end end
## ##
# Sends a packing setting the proper header for you # Sends a packing setting the proper header for you
# #
# @param payload [Array] The Integer list representing the data after the header # @param payload [Array] The Integer list representing the data after the header
def send_packet(payload) # @param flags [Hash] Packet header flags for more details check the class +PacketFlags+
def send_packet(payload, flags = {})
# unsigned char flags_ack; // 6bit flags, 2bit ack
# unsigned char ack; // 8bit ack
# unsigned char numchunks; // 8bit chunks
# unsigned char token[4]; // 32bit token
# // ffffffaa
# // aaaaaaaa
# // NNNNNNNN
# // TTTTTTTT
# // TTTTTTTT
# // TTTTTTTT
# // TTTTTTTT
flags_bits = PacketFlags.new(flags).bits
header_bits =
'00' + # unused flags? # ff
flags_bits + # ffff
@ack.to_s(2).rjust(10, '0') # aa aaaa aaaa
puts "header bits: #{header_bits}"
header = header_bits.chars.groups_of(4).map do |four_bits|
four_bits.join('').to_i(2)
end
puts "header bytes: #{str_hex(header.pack("C*"))}"
header = [0x00, 0x00, 0x01] + str_bytes(@server_token) header = [0x00, 0x00, 0x01] + str_bytes(@server_token)
data = (header + payload).pack('C*') data = (header + payload).pack('C*')
@s.send(data, 0, @ip, @port) @s.send(data, 0, @ip, @port)
@ -212,6 +238,10 @@ class TwClient
def process_server_packet(data) def process_server_packet(data)
chunks = BigChungusTheChunkGetter.get_chunks(data) chunks = BigChungusTheChunkGetter.get_chunks(data)
chunks.each do |chunk| chunks.each do |chunk|
if chunk.flags_vital
@netbase.ack = (@netbase.ack + 1) % NET_MAX_SEQUENCE
puts "got ack: #{@netbase.ack}"
end
process_chunk(chunk) process_chunk(chunk)
end end
end end