teeworlds_network/lib/packet.rb

107 lines
2.5 KiB
Ruby
Raw Normal View History

2022-10-29 11:17:42 +00:00
require 'huffman_tw'
2022-10-30 18:00:13 +00:00
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' : '0'
bits += hash[:compressed] ? '1' : '0'
bits += hash[:resend] ? '1' : '0'
bits += hash[:control] ? '1' : '0'
2022-10-30 18:00:13 +00:00
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 Packet
2022-10-30 10:18:15 +00:00
attr_reader :flags, :payload
2022-10-30 10:18:15 +00:00
def initialize(data, prefix = '')
2022-10-29 11:17:42 +00:00
# @data and @payload
# are strings representing the raw bytes
2022-10-30 10:18:15 +00:00
#
# @prefix is a String that will be displayed
# when printing the packet
# use '>' and '<' for example to indicate
# network direction (client/server)
@prefix = prefix
2022-10-29 11:17:42 +00:00
@huffman = Huffman.new
2022-10-30 10:18:15 +00:00
@data = data
flags_byte = @data[0].unpack("B*")
2022-10-30 18:00:13 +00:00
@flags = PacketFlags.new(flags_byte.first[2..5]).hash
2022-10-30 10:18:15 +00:00
@payload = @data[PACKET_HEADER_SIZE..]
2022-10-29 11:17:42 +00:00
if flags_compressed
@payload = @huffman.decompress(@payload.unpack("C*"))
@payload = @payload.pack("C*")
end
end
def annotate_first_row(bytes)
header = bytes[0..2].join(' ').yellow
token = bytes[3..6].join(' ').green
payload = bytes[7..].join(' ')
2022-10-30 10:18:15 +00:00
puts @prefix + " data: #{[header, token, payload].join(' ')}"
print @prefix + " "
print "header".ljust(3 * 3, ' ').yellow
print "token".ljust(4 * 3, ' ').green
puts "data"
end
def to_s()
2022-10-30 10:18:15 +00:00
puts @prefix + "Packet"
puts @prefix + " flags: #{@flags}"
bytes = str_hex(@data).split(' ')
# todo: check terminal size?
max_width = 14
rows = bytes.groups_of(max_width)
annotate_first_row(rows.first)
rows[1..].each do |row|
2022-10-30 10:18:15 +00:00
print @prefix + " "
puts row.join(' ')
end
puts ""
end
2022-10-29 11:17:42 +00:00
def flags_compressed()
@flags[:compressed]
end
def flags_connless()
@flags[:connection] == false
end
def flags_control()
@flags[:control]
end
end