ludic/packages/ludic.net/session.ludic

102 lines
3.7 KiB
Text

# session.ludic - hosting, joining and leaving. The host is pid 1 and hands out 2 upwards; this
# machine's pid is what its packets say. A token picked by the host names the session.
# open a socket on `port` and take guests; false (net_why) when the port is taken
@alloc_ok("once per party hosted")
export function net_host(net_st: mut NetState, port: int, token: int) -> bool {
if net_live(net_st) { return true }
net_st.net__sock = NetSocket.open(port)
if net_st.net__sock <= 0 {
net_st.net__sock = 0
net_st.net__why = NET_WHY_PORT_TAKEN
return false
}
for i in 0 .. NET_PEERS { np_close(net_st, i) }
net_become_host(net_st, token)
net__log(`hosting on port {NetSocket.port(net_st.net__sock)}`)
net_room_host(net_st)
return true
}
# dial a host at an address; the hello (net_hello_set) goes until a welcome or a refusal
@alloc_ok("once per join")
export function net_join(net_st: mut NetState, ip: int, port: int) -> bool {
if net_live(net_st) { return false }
if not net__socket(net_st) { return false }
for i in 0 .. NET_PEERS { np_close(net_st, i) }
net_st.net__token = 0
net_st.net__my_pid = 0
net_st.net__state = NET_JOINING
net_dial(net_st, ip, port)
net__log(`joining {Udp.ip_text(ip)}:{port}`)
return true
}
function net__socket(net_st: mut NetState) -> bool {
if net_st.net__sock <= 0 { net_st.net__sock = NetSocket.open(0) }
if net_st.net__sock > 0 { return true }
net_st.net__sock = 0
net_st.net__why = NET_WHY_NO_SOCKET
return false
}
# the message just written is the hello: what a host is asked to let this machine in with
export function net_hello_set(net_st: mut NetState) -> void {
nb_copy(net_st.net__hello_b, 0, net_st.net__wb, 0, net_st.net__wl)
net_st.net__hello_l = net_st.net__wl
if net_st.net__hello_l > NET_MTU - 40 { net_st.net__hello_l = NET_MTU - 40 }
}
# (again) to that address, with a fresh connection and the hello sent anew
export function net_dial(net_st: mut NetState, ip: int, port: int) -> void {
np_close(net_st, 0)
net_st.net__join_ip = ip
net_st.net__join_port = port
net__open(net_st, 0, ip, port, 1)
net_st.net__hello_t = -1.0
}
# a host that set out on a new trip, or a new host: the same socket asks to be let in there
export function net_follow(net_st: mut NetState, ip: int, port: int) -> void {
net_dial(net_st, ip, port)
net_st.net__token = 0
net_st.net__my_pid = 0
net_st.net__state = NET_JOINING
}
# the old host is gone and this machine keeps the socket, alone (it may become the host)
export function net_stand_alone(net_st: mut NetState) -> void { net_st.net__state = NET_IDLE }
export function net_become_host(net_st: mut NetState, token: int) -> void {
net_st.net__state = NET_HOSTING
net_st.net__my_pid = 1
net_st.net__next_pid = 2
net_st.net__token = token
}
# a welcome: this machine is `pid` in the session `token`
export function net_joined_as(net_st: mut NetState, token: int, pid: int) -> void {
net_st.net__token = token
net_st.net__my_pid = pid
net_st.net__state = NET_JOINED
net_st.net__wait_more = 0
}
# the host lets the stranger in `slot` in: its pid, from 2 upwards
export function net_accept(net_st: mut NetState, slot: int) -> int {
if net_st.net__state != NET_HOSTING or not net_peer_on(net_st, slot) { return 0 }
let p = net_st.net__peers[slot]
if p.pid >= 2 { return p.pid }
p.pid = net_st.net__next_pid
net_st.net__next_pid += 1
return p.pid
}
# a slow host is given this many more seconds to answer (a map switch, a matchmaker)
export function net_hello_wait(net_st: mut NetState, secs: int) -> void { net_st.net__wait_more = secs }
# a room code: joining, with no address yet - the matchmaker's answer brings one
function net__wait_for_host(net_st: mut NetState) -> void {
net_st.net__state = NET_JOINING
net_st.net__hello_t = 0.0
}