# 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 }