magic-wormhole/docs/w2.dot
Brian Warner 0b28137948 w3.dot: figure out close() pathways
d=M_close() will always do the verbose clean shutdown thing, and the Deferred
won't fire (e.g. we won't move to state "Ss") until we've deallocated our
server resources (nameplates and mailboxes), and we've finished shutting down
our websocket connection. So integration tests should wait on the Deferred to
make sure everything has stopped moving and the reactor is clean.

CLI applications that are following the success path can use M_close() and
wait on the Deferred before terminating.

CLI applications that wind up on some error path can either use M_close(), or
just SIGINT and leave the server to GC stuff later.

GUI applications can use M_close() but ignore the Deferred, and assume that
the program will keep running long enough to get the deallocation messages
through.

GUI+DB applications can use M_close() and then stop recording state changes,
and if the program remains running long enough, everything will be
deallocated, but if it terminates too soon, the server will have to GC.
2017-04-06 12:21:00 -07:00

142 lines
7.0 KiB
Plaintext

digraph {
/* new idea */
{rank=same; M_entry_whole_code M_title M_entry_allocation M_entry_interactive}
M_entry_whole_code [label="whole\ncode"]
M_entry_whole_code -> M_S1A
M_title [label="Message\nMachine" style="dotted"]
M_entry_whole_code -> M_title [style="invis"]
M_entry_allocation [label="allocation" color="orange"]
M_entry_allocation -> M_S1B [label="already\nconnected" color="orange" fontcolor="orange"]
M_entry_interactive [label="interactive" color="orange"]
M_entry_interactive -> M_S1B [color="orange"]
{rank=same; M_S1A M_S1B}
M_S1A [label="S1A:\nknow nothing"]
M_S1B [label="S1B:\nknow nothing\n(bound)" color="orange"]
M_S1A -> M_S1B [label="M_connected()"]
M_S1B -> M_S1A [label="M_lost()"]
M_S1A -> M_S2A [label="M_set_nameplate()"]
M_S1B -> M_P2_claim [label="M_set_nameplate()" color="orange" fontcolor="orange"]
{rank=same; M_S2A M_S2B M_S2C M_P2_claim}
M_S2A [label="S2A:\nnot claimed"]
M_S2C [label="S2C:\nmaybe claimed"]
M_S2B [label="S2B:\nmaybe claimed\n(bound)" color="orange"]
M_S2A -> M_P2_claim [label="M_connected()"]
M_S2A -> M_C_stop [label="M_close()" style="dashed"]
M_C_stop [shape="box" label="C_stop()" style="dashed"]
M_S2B -> M_SrB [label="M_close()" style="dashed"]
M_SrB [label="SrB" style="dashed"]
M_S2C -> M_SrA [label="M_close()" style="dashed"]
M_SrA [label="SrA" style="dashed"]
M_S2C -> M_P2_claim [label="M_connected()"]
M_S2B -> M_S2C [label="M_lost()"]
M_P2_claim [shape="box" label="tx claim" color="orange"]
M_P2_claim -> M_S2B [color="orange"]
M_S2A -> M_P2A_queue [label="M_send(msg)" style="dotted"]
M_P2A_queue [shape="box" label="queue" style="dotted"]
M_P2A_queue -> M_S2A [style="dotted"]
M_S2C -> M_P2C_queue [label="M_send(msg)" style="dotted"]
M_P2C_queue [shape="box" label="queue" style="dotted"]
M_P2C_queue -> M_S2C [style="dotted"]
M_S2B -> M_P2B_queue [label="M_send(msg)" style="dotted"]
M_P2B_queue [shape="box" label="queue" style="dotted"]
M_P2B_queue -> M_S2B [style="dotted"]
M_S2A -> M_S3A [label="(none)" style="invis"]
M_S2B -> M_P_open [label="rx claimed" color="orange" fontcolor="orange"]
M_P_open [shape="box" label="store mailbox\ntx open\ntx add(queued)" color="orange"]
M_P_open -> M_S3B [color="orange"]
{rank=same; M_S3A M_S3B M_P3_open M_P3_send}
M_S3A [label="S3A:\nclaimed\nmaybe open"]
M_S3B [label="S3B:\nclaimed\nmaybe open\n(bound)" color="orange"]
M_S3A -> M_P3_open [label="M_connected()"]
M_S3B -> M_S3A [label="M_lost()"]
M_P3_open [shape="box" label="tx open\ntx add(queued)"]
M_P3_open -> M_S3B
M_S3B -> M_S3B [label="rx claimed"]
M_S3B -> M_P3_send [label="M_send(msg)"]
M_P3_send [shape="box" label="queue\ntx add(msg)"]
M_P3_send -> M_S3B
M_S3A -> M_P3_queue [label="M_send(msg)" style="dotted"]
M_P3_queue [shape="box" label="queue" style="dotted"]
M_P3_queue -> M_S3A [style="dotted"]
M_S3A -> M_S4A [label="(none)" style="invis"]
M_S3B -> M_P3_process_ours [label="rx message(side=me)"]
M_P3_process_ours [shape="box" label="dequeue"]
M_P3_process_ours -> M_S3B
M_S3B -> M_P3_process_theirs1 [label="rx message(side!=me)" color="orange" fontcolor="orange"]
M_P3_process_theirs1 [shape="box" label="tx release" color="orange"]
M_P3_process_theirs1 -> M_P3_process_theirs2 [color="orange"]
M_P3_process_theirs2 [shape="octagon" label="process message" color="orange"]
/* pay attention to the race here: this process_message() will
deliver msg_pake to the WormholeMachine, which will compute_key() and
M_send(version), and we're in between M_S2A (where M_send gets
queued) and M_S3A (where M_send gets sent and queued), and we're no
longer passing through the M_P3_open phase (which drains the queue).
So there's a real possibility of the outbound msg_version getting
dropped on the floor, or put in a queue but never delivered. */
M_P3_process_theirs2 -> M_S4B [color="orange"]
{rank=same; M_S4A M_P4_release M_S4B M_P4_process M_P4_send M_P4_queue}
M_S4A [label="S4A:\nmaybe released\nmaybe open\n"]
M_S4B [label="S4B:\nmaybe released\nmaybe open\n(bound)" color="orange"]
M_S4A -> M_P4_release [label="M_connected()"]
M_P4_release [shape="box" label="tx open\ntx add(queued)\ntx release"]
M_S4B -> M_P4_send [label="M_send(msg)"]
M_P4_send [shape="box" label="queue\ntx add(msg)"]
M_P4_send -> M_S4B
M_S4A -> M_P4_queue [label="M_send(msg)" style="dotted"]
M_P4_queue [shape="box" label="queue" style="dotted"]
M_P4_queue -> M_S4A [style="dotted"]
M_P4_release -> M_S4B
M_S4B -> M_S4A [label="M_lost()"]
M_S4B -> M_P4_process [label="rx message"]
M_P4_process [shape="octagon" label="process message"]
M_P4_process -> M_S4B
M_S4A -> M_S5A [label="(none)" style="invis"]
M_S4B -> M_S5B [label="rx released" color="orange" fontcolor="orange"]
seed [label="from Seed?"]
M_S3A -> seed [style="invis"]
M_S4A -> seed [style="invis"]
seed -> M_S5A
{rank=same; seed M_S5A M_S5B M_P5_open M_process}
M_S5A [label="S5A:\nreleased\nmaybe open"]
M_S5B [label="S5B:\nreleased\nmaybe open\n(bound)" color="green"]
M_S5A -> M_P5_open [label="M_connected()"]
M_P5_open [shape="box" label="tx open\ntx add(queued)"]
M_P5_open -> M_S5B
M_S5B -> M_S5A [label="M_lost()"]
M_S5B -> M_process [label="rx message" color="green" fontcolor="green"]
M_process [shape="octagon" label="process message" color="green"]
M_process -> M_S5B [color="green"]
M_S5B -> M_P5_send [label="M_send(msg)" color="green" fontcolor="green"]
M_P5_send [shape="box" label="queue\ntx add(msg)" color="green"]
M_P5_send -> M_S5B [color="green"]
M_S5A -> M_P5_queue [label="M_send(msg)" style="dotted"]
M_P5_queue [shape="box" label="queue" style="dotted"]
M_P5_queue -> M_S5A [style="dotted"]
M_S5B -> M_CcB_P_close [label="M_close()" style="dashed" color="orange" fontcolor="orange"]
M_CcB_P_close [label="tx close" style="dashed" color="orange"]
M_process [shape="octagon" label="process message"]
M_process_me [shape="box" label="dequeue"]
M_process -> M_process_me [label="side == me"]
M_process_them [shape="box" label="" style="dotted"]
M_process -> M_process_them [label="side != me"]
M_process_them -> M_process_pake [label="phase == pake"]
M_process_pake [shape="box" label="WM_rx_pake()"]
M_process_them -> M_process_other [label="phase in (version,numbered)"]
M_process_other [shape="box" label="WM_rx_msg()"]
}