Count ack per client and thus fix reconnect
Sadly reconnecting somehow crashes the client :( https://github.com/teeworlds/teeworlds/issues/3182
This commit is contained in:
parent
409f880f36
commit
09bd7bfebb
|
@ -40,9 +40,8 @@ class NetBase
|
||||||
# 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
|
||||||
# @param num_chunks [Integer] Amount of NetChunks in the payload
|
# @param opts [Hash] :chunks, :client and packet header flags for more details check the class +PacketFlags+
|
||||||
# @param flags [Hash] Packet header flags for more details check the class +PacketFlags+
|
def send_packet(payload, opts = { chunks: 1, client: nil, addr: nil })
|
||||||
def send_packet(payload, num_chunks = 1, opts = {})
|
|
||||||
# unsigned char flags_ack; // 6bit flags, 2bit ack
|
# unsigned char flags_ack; // 6bit flags, 2bit ack
|
||||||
# unsigned char ack; // 8bit ack
|
# unsigned char ack; // 8bit ack
|
||||||
# unsigned char numchunks; // 8bit chunks
|
# unsigned char numchunks; // 8bit chunks
|
||||||
|
@ -55,9 +54,21 @@ class NetBase
|
||||||
# // TTTTTTTT
|
# // TTTTTTTT
|
||||||
# // TTTTTTTT
|
# // TTTTTTTT
|
||||||
flags_bits = PacketFlags.new(opts).bits
|
flags_bits = PacketFlags.new(opts).bits
|
||||||
|
ack = @ack
|
||||||
|
ip = @ip
|
||||||
|
port = @port
|
||||||
|
unless opts[:client].nil?
|
||||||
|
ack = opts[:client].ack
|
||||||
|
ip = opts[:client].addr.ip
|
||||||
|
port = opts[:client].addr.port
|
||||||
|
end
|
||||||
|
unless opts[:addr].nil?
|
||||||
|
ip = opts[:addr].ip
|
||||||
|
port = opts[:addr].port
|
||||||
|
end
|
||||||
# unused flags ack num chunks
|
# unused flags ack num chunks
|
||||||
# ff ffff aa aaaa aaaa NNNN NNNN
|
# ff ffff aa aaaa aaaa NNNN NNNN
|
||||||
header_bits = "00#{flags_bits}#{@ack.to_s(2).rjust(10, '0')}#{num_chunks.to_s(2).rjust(8, '0')}"
|
header_bits = "00#{flags_bits}#{ack.to_s(2).rjust(10, '0')}#{opts[:chunks].to_s(2).rjust(8, '0')}"
|
||||||
|
|
||||||
header = header_bits.chars.groups_of(8).map do |eight_bits|
|
header = header_bits.chars.groups_of(8).map do |eight_bits|
|
||||||
eight_bits.join.to_i(2)
|
eight_bits.join.to_i(2)
|
||||||
|
@ -65,12 +76,6 @@ class NetBase
|
||||||
|
|
||||||
header += str_bytes(@peer_token)
|
header += str_bytes(@peer_token)
|
||||||
data = (header + payload).pack('C*')
|
data = (header + payload).pack('C*')
|
||||||
ip = @ip
|
|
||||||
port = @port
|
|
||||||
unless opts[:addr].nil?
|
|
||||||
ip = opts[:addr].ip
|
|
||||||
port = opts[:addr].port
|
|
||||||
end
|
|
||||||
puts "send to #{ip}:#{port}"
|
puts "send to #{ip}:#{port}"
|
||||||
@s.send(data, 0, ip, port)
|
@s.send(data, 0, ip, port)
|
||||||
|
|
||||||
|
|
|
@ -134,7 +134,7 @@ class TeeworldsClient
|
||||||
# TODO: this is same in client and server
|
# TODO: this is same in client and server
|
||||||
# move to NetBase???
|
# move to NetBase???
|
||||||
def send_ctrl_close
|
def send_ctrl_close
|
||||||
@netbase&.send_packet([NET_CTRLMSG_CLOSE], 0, control: true)
|
@netbase&.send_packet([NET_CTRLMSG_CLOSE], chunks: 0, control: true)
|
||||||
end
|
end
|
||||||
|
|
||||||
def disconnect
|
def disconnect
|
||||||
|
@ -160,18 +160,18 @@ class TeeworldsClient
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_ctrl_keepalive
|
def send_ctrl_keepalive
|
||||||
@netbase.send_packet([NET_CTRLMSG_KEEPALIVE], 0, control: true)
|
@netbase.send_packet([NET_CTRLMSG_KEEPALIVE], chunks: 0, control: true)
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_msg_connect
|
def send_msg_connect
|
||||||
msg = [NET_CTRLMSG_CONNECT] + str_bytes(@client_token) + Array.new(501, 0x00)
|
msg = [NET_CTRLMSG_CONNECT] + str_bytes(@client_token) + Array.new(501, 0x00)
|
||||||
@netbase.send_packet(msg, 0, control: true)
|
@netbase.send_packet(msg, chunks: 0, control: true)
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_ctrl_with_token
|
def send_ctrl_with_token
|
||||||
@state = NET_CONNSTATE_TOKEN
|
@state = NET_CONNSTATE_TOKEN
|
||||||
msg = [NET_CTRLMSG_TOKEN] + str_bytes(@client_token) + Array.new(512, 0x00)
|
msg = [NET_CTRLMSG_TOKEN] + str_bytes(@client_token) + Array.new(512, 0x00)
|
||||||
@netbase.send_packet(msg, 0, control: true)
|
@netbase.send_packet(msg, chunks: 0, control: true)
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_info
|
def send_info
|
||||||
|
@ -183,7 +183,7 @@ class TeeworldsClient
|
||||||
[pack_msg_id(NETMSG_INFO, system: true)] +
|
[pack_msg_id(NETMSG_INFO, system: true)] +
|
||||||
data
|
data
|
||||||
|
|
||||||
@netbase.send_packet(msg, 1)
|
@netbase.send_packet(msg)
|
||||||
end
|
end
|
||||||
|
|
||||||
def rcon_auth(name, password = nil)
|
def rcon_auth(name, password = nil)
|
||||||
|
@ -210,7 +210,7 @@ class TeeworldsClient
|
||||||
msg = NetChunk.create_header(vital: true, size: data.size + 1) +
|
msg = NetChunk.create_header(vital: true, size: data.size + 1) +
|
||||||
[pack_msg_id(NETMSG_RCON_AUTH, system: true)] +
|
[pack_msg_id(NETMSG_RCON_AUTH, system: true)] +
|
||||||
data
|
data
|
||||||
@netbase.send_packet(msg, 1)
|
@netbase.send_packet(msg)
|
||||||
end
|
end
|
||||||
|
|
||||||
def rcon(command)
|
def rcon(command)
|
||||||
|
@ -219,7 +219,7 @@ class TeeworldsClient
|
||||||
msg = NetChunk.create_header(vital: true, size: data.size + 1) +
|
msg = NetChunk.create_header(vital: true, size: data.size + 1) +
|
||||||
[pack_msg_id(NETMSG_RCON_CMD, system: true)] +
|
[pack_msg_id(NETMSG_RCON_CMD, system: true)] +
|
||||||
data
|
data
|
||||||
@netbase.send_packet(msg, 1)
|
@netbase.send_packet(msg)
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_msg_startinfo
|
def send_msg_startinfo
|
||||||
|
@ -288,7 +288,7 @@ class TeeworldsClient
|
||||||
msg = NetChunk.create_header(vital: false, size: data.size + 1) +
|
msg = NetChunk.create_header(vital: false, size: data.size + 1) +
|
||||||
[pack_msg_id(NETMSG_INPUT, system: true)] +
|
[pack_msg_id(NETMSG_INPUT, system: true)] +
|
||||||
data
|
data
|
||||||
@netbase.send_packet(msg, 1)
|
@netbase.send_packet(msg)
|
||||||
end
|
end
|
||||||
|
|
||||||
def on_msg_token(data)
|
def on_msg_token(data)
|
||||||
|
|
|
@ -17,11 +17,13 @@ require_relative 'token'
|
||||||
|
|
||||||
class Client
|
class Client
|
||||||
attr_accessor :id, :addr, :vital_sent, :last_recv_time, :token, :player
|
attr_accessor :id, :addr, :vital_sent, :last_recv_time, :token, :player
|
||||||
|
attr_reader :ack
|
||||||
|
|
||||||
def initialize(attr = {})
|
def initialize(attr = {})
|
||||||
@id = attr[:id]
|
@id = attr[:id]
|
||||||
@addr = attr[:addr]
|
@addr = attr[:addr]
|
||||||
@vital_sent = 0
|
@vital_sent = 0
|
||||||
|
@ack = 0
|
||||||
@last_recv_time = Time.now
|
@last_recv_time = Time.now
|
||||||
@player = Player.new(
|
@player = Player.new(
|
||||||
id: @id,
|
id: @id,
|
||||||
|
@ -35,6 +37,10 @@ class Client
|
||||||
SecurityToken.validate(@token)
|
SecurityToken.validate(@token)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def bump_ack
|
||||||
|
@ack = (@ack + 1) % NET_MAX_SEQUENCE
|
||||||
|
end
|
||||||
|
|
||||||
# TODO: use or remove
|
# TODO: use or remove
|
||||||
# not sure if its cool
|
# not sure if its cool
|
||||||
# one can make vital_sent read only
|
# one can make vital_sent read only
|
||||||
|
@ -123,11 +129,19 @@ class TeeworldsServer
|
||||||
end
|
end
|
||||||
|
|
||||||
def on_client_packet(packet)
|
def on_client_packet(packet)
|
||||||
|
client = packet.client
|
||||||
|
if client.nil?
|
||||||
|
# TODO: turn this into a silent return
|
||||||
|
# otherwise bad actors can easily trigger this
|
||||||
|
# with handcrafted packets
|
||||||
|
puts 'Error: got client packet from unknown client'
|
||||||
|
exit 1
|
||||||
|
end
|
||||||
chunks = BigChungusTheChunkGetter.get_chunks(packet.payload)
|
chunks = BigChungusTheChunkGetter.get_chunks(packet.payload)
|
||||||
chunks.each do |chunk|
|
chunks.each do |chunk|
|
||||||
if chunk.flags_vital && !chunk.flags_resend
|
if chunk.flags_vital && !chunk.flags_resend
|
||||||
@netbase.ack = (@netbase.ack + 1) % NET_MAX_SEQUENCE
|
packet.client.bump_ack
|
||||||
puts "got ack: #{@netbase.ack}" if @verbose
|
puts "got ack: #{packet.client.ack}" if @verbose
|
||||||
end
|
end
|
||||||
process_chunk(chunk, packet)
|
process_chunk(chunk, packet)
|
||||||
end
|
end
|
||||||
|
@ -157,14 +171,14 @@ class TeeworldsServer
|
||||||
msg = [NET_CTRLMSG_CLOSE]
|
msg = [NET_CTRLMSG_CLOSE]
|
||||||
msg += Packer.pack_str(reason) unless reason.nil?
|
msg += Packer.pack_str(reason) unless reason.nil?
|
||||||
@netbase.set_peer_token(client.token)
|
@netbase.set_peer_token(client.token)
|
||||||
@netbase.send_packet(msg, 0, control: true, addr: client.addr)
|
@netbase.send_packet(msg, chunks: 0, control: true, client:)
|
||||||
# @netbase.set_peer_token(@server_token)
|
# @netbase.set_peer_token(@server_token)
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_ctrl_with_token(addr, token)
|
def send_ctrl_with_token(addr, token)
|
||||||
msg = [NET_CTRLMSG_TOKEN] + str_bytes(@server_token)
|
msg = [NET_CTRLMSG_TOKEN] + str_bytes(@server_token)
|
||||||
@netbase.set_peer_token(token)
|
@netbase.set_peer_token(token)
|
||||||
@netbase.send_packet(msg, 0, control: true, addr:)
|
@netbase.send_packet(msg, chunks: 0, control: true, addr:)
|
||||||
# @netbase.set_peer_token(@server_token)
|
# @netbase.set_peer_token(@server_token)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -179,33 +193,33 @@ class TeeworldsServer
|
||||||
msg = NetChunk.create_header(vital: true, size: data.size + 1, client:) +
|
msg = NetChunk.create_header(vital: true, size: data.size + 1, client:) +
|
||||||
[pack_msg_id(NETMSG_MAP_CHANGE, system: true)] +
|
[pack_msg_id(NETMSG_MAP_CHANGE, system: true)] +
|
||||||
data
|
data
|
||||||
@netbase.send_packet(msg, 1, addr: client.addr)
|
@netbase.send_packet(msg, chunks: 1, client:)
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_ready(client)
|
def send_ready(client)
|
||||||
msg = NetChunk.create_header(vital: true, size: 1, client:) +
|
msg = NetChunk.create_header(vital: true, size: 1, client:) +
|
||||||
[pack_msg_id(NETMSG_CON_READY, system: true)]
|
[pack_msg_id(NETMSG_CON_READY, system: true)]
|
||||||
@netbase.send_packet(msg, 1, addr: client.addr)
|
@netbase.send_packet(msg, chunks: 1, client:)
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_ready_to_enter(client)
|
def send_ready_to_enter(client)
|
||||||
msg = NetChunk.create_header(vital: true, size: 1, client:) +
|
msg = NetChunk.create_header(vital: true, size: 1, client:) +
|
||||||
[pack_msg_id(NETMSGTYPE_SV_READYTOENTER, system: false)]
|
[pack_msg_id(NETMSGTYPE_SV_READYTOENTER, system: false)]
|
||||||
@netbase.send_packet(msg, 1, addr: client.addr)
|
@netbase.send_packet(msg, chunks: 1, client:)
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_server_info(client, server_info)
|
def send_server_info(client, server_info)
|
||||||
msg = NetChunk.create_header(vital: true, size: 1 + server_info.size, client:) +
|
msg = NetChunk.create_header(vital: true, size: 1 + server_info.size, client:) +
|
||||||
[pack_msg_id(NETMSG_SERVERINFO, system: true)] +
|
[pack_msg_id(NETMSG_SERVERINFO, system: true)] +
|
||||||
server_info
|
server_info
|
||||||
@netbase.send_packet(msg, 1, addr: client.addr)
|
@netbase.send_packet(msg, chunks: 1, client:)
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_game_info(client, data)
|
def send_game_info(client, data)
|
||||||
msg = NetChunk.create_header(vital: true, size: 1 + data.size, client:) +
|
msg = NetChunk.create_header(vital: true, size: 1 + data.size, client:) +
|
||||||
[pack_msg_id(NETMSGTYPE_SV_GAMEINFO, system: false)] +
|
[pack_msg_id(NETMSGTYPE_SV_GAMEINFO, system: false)] +
|
||||||
data
|
data
|
||||||
@netbase.send_packet(msg, 1, addr: client.addr)
|
@netbase.send_packet(msg, chunks: 1, client:)
|
||||||
end
|
end
|
||||||
|
|
||||||
def on_ctrl_token(packet)
|
def on_ctrl_token(packet)
|
||||||
|
@ -247,7 +261,7 @@ class TeeworldsServer
|
||||||
puts "got connection, sending accept (client token: #{token})"
|
puts "got connection, sending accept (client token: #{token})"
|
||||||
client = Client.new(id:, addr: packet.addr, token:)
|
client = Client.new(id:, addr: packet.addr, token:)
|
||||||
@clients[id] = client
|
@clients[id] = client
|
||||||
@netbase.send_packet([NET_CTRLMSG_ACCEPT], 0, control: true, addr: packet.addr)
|
@netbase.send_packet([NET_CTRLMSG_ACCEPT], chunks: 0, control: true, client:)
|
||||||
end
|
end
|
||||||
|
|
||||||
def on_packet(packet)
|
def on_packet(packet)
|
||||||
|
@ -283,7 +297,7 @@ class TeeworldsServer
|
||||||
[pack_msg_id(NETMSG_SNAPEMPTY, system: true)] +
|
[pack_msg_id(NETMSG_SNAPEMPTY, system: true)] +
|
||||||
data
|
data
|
||||||
@clients.each do |_id, client|
|
@clients.each do |_id, client|
|
||||||
@netbase.send_packet(msg_snap_empty, 1, addr: client.addr)
|
@netbase.send_packet(msg_snap_empty, chunks: 1, client:)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue