Start working on proper packet header
This commit is contained in:
parent
f75eaebcee
commit
b7a2cfb5c3
10
lib/chunk.rb
10
lib/chunk.rb
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
34
teeworlds.rb
34
teeworlds.rb
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue