ludic/packages/ludic.net/codes.ludic

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
}