Skip to content

Commit

Permalink
replace NetcodeInetAddr with type stable NetcodeAddress (#33)
Browse files Browse the repository at this point in the history
* rename NetcodeInetAddr to NetcodeAddress

* make NetcodeAddress type stable

* use UInt32 and UInt128 for TYPE_OF_IPV4_HOST and TYPE_OF_IPV6_HOST

* remove unused constant SIZE_OF_ADDRESS_TYPE
  • Loading branch information
Sid-Bhatia-0 committed Mar 23, 2024
1 parent ae357ea commit d4ef56e
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 36 deletions.
11 changes: 4 additions & 7 deletions netcode/protocol_constants.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import Sockets

const NETCODE_VERSION_INFO = Vector{UInt8}("NETCODE 1.02\0")
const SIZE_OF_NETCODE_VERSION_INFO = length(NETCODE_VERSION_INFO)

Expand All @@ -22,15 +20,14 @@ const SIZE_OF_HMAC = 16
const SIZE_OF_ENCRYPTED_PRIVATE_CONNECT_TOKEN_DATA = 1024

const TYPE_OF_ADDRESS_TYPE = UInt8
const SIZE_OF_ADDRESS_TYPE = sizeof(TYPE_OF_ADDRESS_TYPE)

const ADDRESS_TYPE_IPV4 = TYPE_OF_ADDRESS_TYPE(1)
const TYPE_OF_IPV4_HOST = fieldtype(Sockets.IPv4, :host)
const TYPE_OF_IPV4_PORT = fieldtype(Sockets.InetAddr{Sockets.IPv4}, :port)
const TYPE_OF_IPV4_HOST = UInt32

const ADDRESS_TYPE_IPV6 = TYPE_OF_ADDRESS_TYPE(2)
const TYPE_OF_IPV6_HOST = fieldtype(Sockets.IPv6, :host)
const TYPE_OF_IPV6_PORT = fieldtype(Sockets.InetAddr{Sockets.IPv6}, :port)
const TYPE_OF_IPV6_HOST = UInt128

const TYPE_OF_PORT = UInt16

const TYPE_OF_NUM_SERVER_ADDRESSES = UInt32
const MAX_NUM_SERVER_ADDRESSES = 32
Expand Down
56 changes: 41 additions & 15 deletions netcode/serialization.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,25 @@ get_serialized_size(value::Union{Sockets.IPv4, Sockets.IPv6}) = get_serialized_s

get_serialized_size(value::Union{Sockets.InetAddr{Sockets.IPv4}, Sockets.InetAddr{Sockets.IPv6}}) = get_serialized_size(value.host) + sizeof(value.port)

get_serialized_size(value::NetcodeInetAddr) = SIZE_OF_ADDRESS_TYPE + get_serialized_size(value.address)
function get_serialized_size(netcode_address::NetcodeAddress)
@assert is_valid(netcode_address)

get_serialized_size(value::Vector{NetcodeInetAddr}) = sum(get_serialized_size, value)
n = 0

n += get_serialized_size(netcode_address.address_type)

if netcode_address.address_type == ADDRESS_TYPE_IPV4
n += get_serialized_size(netcode_address.host_ipv4)
else
n += get_serialized_size(netcode_address.host_ipv6)
end

n += get_serialized_size(netcode_address.port)

return n
end

get_serialized_size(value::Vector{NetcodeAddress}) = sum(get_serialized_size, value)

get_serialized_size_fields(value) = sum(get_serialized_size(getfield(value, i)) for i in 1:fieldcount(typeof(value)))

Expand All @@ -38,17 +54,25 @@ function get_serialized_data(value)
return data
end

function Base.write(io::IO, netcode_inetaddr::NetcodeInetAddr)
function Base.write(io::IO, netcode_address::NetcodeAddress)
@assert is_valid(netcode_address)

n = 0

n += write(io, get_address_type(netcode_inetaddr))
n += write(io, netcode_inetaddr.address.host.host)
n += write(io, netcode_inetaddr.address.port)
n += write(io, netcode_address.address_type)

if netcode_address.address_type == ADDRESS_TYPE_IPV4
n += write(io, netcode_address.host_ipv4)
else
n += write(io, netcode_address.host_ipv6)
end

n += write(io, netcode_address.port)

return n
end

function Base.write(io::IO, netcode_addresses::Vector{NetcodeInetAddr})
function Base.write(io::IO, netcode_addresses::Vector{NetcodeAddress})
n = 0

for netcode_address in netcode_addresses
Expand Down Expand Up @@ -90,20 +114,22 @@ Base.write(io::IO, packet::AbstractPacket) = write_fields(io, packet)

Base.write(io::IO, packet::ConnectTokenPacket) = write_fields_and_padding(io, packet)

function try_read(io::IO, ::Type{NetcodeInetAddr})
function try_read(io::IO, ::Type{NetcodeAddress})
address_type = read(io, TYPE_OF_ADDRESS_TYPE)

if address_type == ADDRESS_TYPE_IPV4
host = Sockets.IPv4(read(io, TYPE_OF_IPV4_HOST))
port = read(io, TYPE_OF_IPV4_PORT)
host_ipv4 = read(io, TYPE_OF_IPV4_HOST)
host_ipv6 = zero(TYPE_OF_IPV6_HOST)
elseif address_type == ADDRESS_TYPE_IPV6
host = Sockets.IPv6(read(io, TYPE_OF_IPV6_HOST))
port = read(io, TYPE_OF_IPV6_PORT)
host_ipv4 = zero(TYPE_OF_IPV4_HOST)
host_ipv6 = read(io, TYPE_OF_IPV6_HOST)
else
return nothing
end

return NetcodeInetAddr(Sockets.InetAddr(host, port))
port = read(io, TYPE_OF_PORT)

return NetcodeAddress(address_type, host_ipv4, host_ipv6, port)
end

function try_read(data::Vector{UInt8}, ::Type{ConnectTokenPacket})
Expand Down Expand Up @@ -140,10 +166,10 @@ function try_read(data::Vector{UInt8}, ::Type{ConnectTokenPacket})
return nothing
end

netcode_addresses = NetcodeInetAddr[]
netcode_addresses = NetcodeAddress[]

for i in 1:num_server_addresses
netcode_address = try_read(io, NetcodeInetAddr)
netcode_address = try_read(io, NetcodeAddress)
if !isnothing(netcode_address)
push!(netcode_addresses, netcode_address)
else
Expand Down
6 changes: 3 additions & 3 deletions netcode/simulate.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ include("protocol_constants.jl")
include("types.jl")
include("serialization.jl")

const NULL_NETCODE_ADDRESS = NetcodeInetAddr(Sockets.InetAddr(Sockets.IPv4(zero(TYPE_OF_IPV4_HOST)), zero(TYPE_OF_IPV4_PORT)))
const NULL_NETCODE_ADDRESS = NetcodeAddress(0, 0, 0, 0)

const NULL_CLIENT_SLOT = ClientSlot(false, NULL_NETCODE_ADDRESS)

Expand Down Expand Up @@ -113,7 +113,7 @@ function start_game_server(game_server_address, room_size)

for i in 1:room_size
if !room[i].is_used
client_slot = ClientSlot(true, NetcodeInetAddr(client_address))
client_slot = ClientSlot(true, NetcodeAddress(client_address))
room[i] = client_slot
@info "Client accepted" client_address
break
Expand Down Expand Up @@ -145,7 +145,7 @@ function start_client(auth_server_address, username, password)
error("Invalid connect token packet received")
end

game_server_address = first(connect_token_packet.netcode_addresses).address
game_server_address = get_inetaddr(first(connect_token_packet.netcode_addresses))

@info "Client obtained game_server_address" game_server_address

Expand Down
51 changes: 40 additions & 11 deletions netcode/types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,16 @@ mutable struct GameState
target_ns_per_frame::Int
end

struct NetcodeInetAddr
address::Union{Sockets.InetAddr{Sockets.IPv4}, Sockets.InetAddr{Sockets.IPv6}}
struct NetcodeAddress
address_type::TYPE_OF_ADDRESS_TYPE
host_ipv4::TYPE_OF_IPV4_HOST
host_ipv6::TYPE_OF_IPV6_HOST
port::TYPE_OF_PORT
end

struct ClientSlot
is_used::Bool
netcode_address::NetcodeInetAddr
netcode_address::NetcodeAddress
end

struct ConnectTokenInfo
Expand All @@ -33,7 +36,7 @@ struct ConnectTokenInfo
nonce::Vector{UInt8}
timeout_seconds::TYPE_OF_TIMEOUT_SECONDS
client_id::TYPE_OF_CLIENT_ID
netcode_addresses::Vector{NetcodeInetAddr}
netcode_addresses::Vector{NetcodeAddress}
client_to_server_key::Vector{UInt8}
server_to_client_key::Vector{UInt8}
user_data::Vector{UInt8}
Expand All @@ -43,7 +46,7 @@ struct PrivateConnectToken
client_id::TYPE_OF_CLIENT_ID
timeout_seconds::TYPE_OF_TIMEOUT_SECONDS
num_server_addresses::TYPE_OF_NUM_SERVER_ADDRESSES
netcode_addresses::Vector{NetcodeInetAddr}
netcode_addresses::Vector{NetcodeAddress}
client_to_server_key::Vector{UInt8}
server_to_client_key::Vector{UInt8}
user_data::Vector{UInt8}
Expand All @@ -66,7 +69,7 @@ struct ConnectTokenPacket <: AbstractPacket
encrypted_private_connect_token_data::Vector{UInt8}
timeout_seconds::TYPE_OF_TIMEOUT_SECONDS
num_server_addresses::TYPE_OF_NUM_SERVER_ADDRESSES
netcode_addresses::Vector{NetcodeInetAddr}
netcode_addresses::Vector{NetcodeAddress}
client_to_server_key::Vector{UInt8}
server_to_client_key::Vector{UInt8}
end
Expand All @@ -80,6 +83,36 @@ struct ConnectionRequestPacket <: AbstractPacket
encrypted_private_connect_token_data::Vector{UInt8}
end

function NetcodeAddress(address::Union{Sockets.InetAddr{Sockets.IPv4}, Sockets.InetAddr{Sockets.IPv6}})
if address isa Sockets.InetAddr{Sockets.IPv4}
address_type = ADDRESS_TYPE_IPV4
host_ipv4 = address.host.host
host_ipv6 = zero(TYPE_OF_IPV6_HOST)
else
address_type = ADDRESS_TYPE_IPV6
host_ipv4 = zero(TYPE_OF_IPV4_HOST)
host_ipv6 = address.host.host
end

port = address.port

return NetcodeAddress(address_type, host_ipv4, host_ipv6, port)
end

is_valid(netcode_address::NetcodeAddress) = netcode_address.address_type == ADDRESS_TYPE_IPV4 || netcode_address.address_type == ADDRESS_TYPE_IPV6

function get_inetaddr(netcode_address::NetcodeAddress)
@assert is_valid(netcode_address)

if netcode_address.address_type == ADDRESS_TYPE_IPV4
host = Sockets.IPv4(netcode_address.host_ipv4)
else
host = Sockets.IPv6(netcode_address.host_ipv6)
end

return Sockets.InetAddr(host, netcode_address.port)
end

function ConnectTokenInfo(client_id)
create_timestamp = time_ns()
expire_timestamp = create_timestamp + CONNECT_TOKEN_EXPIRE_SECONDS * 10 ^ 9
Expand All @@ -92,7 +125,7 @@ function ConnectTokenInfo(client_id)
rand(UInt8, SIZE_OF_NONCE),
TIMEOUT_SECONDS,
client_id,
NetcodeInetAddr.(GAME_SERVER_ADDRESSES),
NetcodeAddress.(GAME_SERVER_ADDRESSES),
rand(UInt8, SIZE_OF_KEY),
rand(UInt8, SIZE_OF_KEY),
rand(UInt8, SIZE_OF_USER_DATA),
Expand All @@ -119,10 +152,6 @@ function PrivateConnectTokenAssociatedData(connect_token_info::ConnectTokenInfo)
)
end

get_address_type(::Sockets.InetAddr{Sockets.IPv4}) = ADDRESS_TYPE_IPV4
get_address_type(::Sockets.InetAddr{Sockets.IPv6}) = ADDRESS_TYPE_IPV6
get_address_type(netcode_inetaddr::NetcodeInetAddr) = get_address_type(netcode_inetaddr.address)

function encrypt(message, associated_data, nonce, key)
ciphertext = zeros(UInt8, length(message) + SIZE_OF_HMAC)
ciphertext_length_ref = Ref{UInt}()
Expand Down

0 comments on commit d4ef56e

Please sign in to comment.