101 lines
3.1 KiB
Text
101 lines
3.1 KiB
Text
# codes.ludic - an address and a port as ten letters in two fives, from an alphabet with no 0/O or
|
|
# 1/I: what a host reads out. An "a.b.c.d:port" or a bare "a.b.c.d" is taken too; a room code is
|
|
# six of the same letters.
|
|
const NET_ALPHA: string = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"
|
|
|
|
@alloc_ok("once per join code shown")
|
|
export function net_code_of(ip: int, port: int) -> string {
|
|
let a = NET_ALPHA
|
|
let buf = buffer(11)
|
|
# 48 bits: the port's 16, then the address's 32, five at a time from the top
|
|
var o = 0
|
|
for k in 0 .. 10 {
|
|
let shift = 45 - k * 5
|
|
var v = 0
|
|
for b in 0 .. 5 {
|
|
let bit = shift + 4 - b
|
|
var x = 0
|
|
if bit >= 32 { x = (port >> (bit - 32)) & 1 } else if bit >= 0 { x = (ip >> bit) & 1 }
|
|
v = (v << 1) | x
|
|
}
|
|
buf[o] = a[v]
|
|
o += 1
|
|
if k == 4 {
|
|
buf[o] = '-'
|
|
o += 1
|
|
}
|
|
}
|
|
return text_of(buf, o)
|
|
}
|
|
|
|
# this machine's code: its address on the network and the socket's port
|
|
export function net_join_code(net_st: NetState) -> string {
|
|
var ip = NetSocket.local_ip()
|
|
if ip == 0 { ip = Udp.ip("127.0.0.1") }
|
|
return net_code_of(ip, net_port(net_st))
|
|
}
|
|
|
|
function net__letter(c: int) -> int {
|
|
var ch = c
|
|
if ch >= 'a' and ch <= 'z' { ch = ch - 32 }
|
|
if ch == 'O' { ch = '0' }
|
|
if ch == 'I' { ch = '1' }
|
|
let a = NET_ALPHA
|
|
for i in 0 .. 32 { if a[i] == ch { return i } }
|
|
return -1
|
|
}
|
|
|
|
# a code or an address: true when net_code_ip() / net_code_port() say where
|
|
export function net_parse_code(net_st: mut NetState, text: string) -> bool {
|
|
let p = text
|
|
var colon = -1
|
|
var dots = 0
|
|
for i in 0 .. len(p) {
|
|
if p[i] == ':' { colon = i }
|
|
if p[i] == '.' { dots += 1 }
|
|
}
|
|
if dots == 3 { return net__parse_addr(net_st, text, colon) }
|
|
var hi = 0
|
|
var lo = 0
|
|
var n = 0
|
|
for i in 0 .. len(p) {
|
|
let c = p[i]
|
|
if c == '-' or c == ' ' { continue }
|
|
let v = net__letter(c)
|
|
if v < 0 { return false }
|
|
# 50 bits arrive; the top two are padding. Keep the port (bits 47..32) and the address.
|
|
for b in 0 .. 5 {
|
|
let bit = (v >> (4 - b)) & 1
|
|
let pos = 49 - n * 5 - b
|
|
if pos >= 32 and pos < 48 { hi = hi | (bit << (pos - 32)) }
|
|
if pos >= 0 and pos < 32 { lo = lo | (bit << pos) }
|
|
}
|
|
n += 1
|
|
}
|
|
if n != 10 { return false }
|
|
net_st.net__code_ip = lo
|
|
net_st.net__code_port = hi
|
|
return net_st.net__code_ip != 0 and net_st.net__code_port > 0
|
|
}
|
|
|
|
function net__parse_addr(net_st: mut NetState, text: string, colon: int) -> bool {
|
|
var host = text
|
|
net_st.net__code_port = net__conf(net_st).port
|
|
if colon > 0 {
|
|
host = text[0..colon]
|
|
net_st.net__code_port = Text.to_int(text[colon + 1..len(text)])
|
|
}
|
|
net_st.net__code_ip = Udp.ip(host)
|
|
return net_st.net__code_ip != 0 and net_st.net__code_port > 0 and net_st.net__code_port < 65536
|
|
}
|
|
|
|
export function net_code_ip(net_st: NetState) -> int { return net_st.net__code_ip }
|
|
export function net_code_port(net_st: NetState) -> int { return net_st.net__code_port }
|
|
|
|
# six of the code's letters: a room at the matchmaker
|
|
export function net_is_room(text: string) -> bool {
|
|
let p = text
|
|
if len(p) != 6 { return false }
|
|
for i in 0 .. 6 { if net__letter(p[i]) < 0 { return false } }
|
|
return true
|
|
}
|