2019-06-29 01:27:59 +03:00
:: Ames extends Arvo's %pass/%give move semantics across the network.
::
2019-12-21 09:56:51 +03:00
:: Ames receives packets as Arvo events and emits packets as Arvo
:: effects. The runtime is responsible for transferring the bytes in
:: an Ames packet across a physical network to another ship.
::
:: The runtime tells Ames which physical address a packet came from,
:: represented as an opaque atom. Ames can emit a packet effect to
:: one of those opaque atoms or to the Urbit address of a galaxy
:: (root node), which the runtime is responsible for translating to a
:: physical address. One runtime implementation sends UDP packets
:: using IPv4 addresses for ships and DNS lookups for galaxies, but
:: other implementations may overlay over other kinds of networks.
::
:: A local vane can pass Ames a %plea request message. Ames
:: transmits the message over the wire to the peer ship's Ames, which
:: passes the message to the destination vane.
::
:: Once the peer has processed the %plea message, it sends a
:: message-acknowledgment packet over the wire back to the local
:: Ames. This ack can either be positive to indicate the request was
:: processed, or negative to indicate the request failed, in which
:: case it's called a "nack". (Don't confuse Ames nacks with TCP
:: nacks, which are a different concept).
::
:: When the local Ames receives either a positive message-ack or a
:: combination of a nack and naxplanation (explained in more detail
2019-06-29 01:27:59 +03:00
:: below), it gives an %done move to the local vane that had
2019-12-21 09:56:51 +03:00
:: requested the original %plea message be sent.
::
:: A local vane can give Ames zero or more %boon response messages in
:: response to a %plea, on the same duct that Ames used to pass the
:: %plea to the vane. Ames transmits a %boon over the wire to the
:: peer's Ames, which gives it to the destination vane on the same
:: duct the vane had used to pass the original %plea to Ames.
::
:: %boon messages are acked automatically by the receiver Ames. They
:: cannot be nacked, and Ames only uses the ack internally, without
:: notifying the client vane that gave Ames the %boon.
::
:: If the Arvo event that completed receipt of a %boon message
:: crashes, Ames instead sends the client vane a %lost message
:: indicating the %boon was missed.
::
:: %plea messages can be nacked, in which case the peer will send
:: both a message-nack packet and a naxplanation message, which is
:: sent in a way that does not interfere with normal operation. The
:: naxplanation is sent as a full Ames message, instead of just a
:: packet, because the contained error information can be arbitrarily
:: large. A naxplanation can only give rise to a positive ack --
:: never ack an ack, and never nack a naxplanation.
::
:: Ames guarantees a total ordering of messages within a "flow",
:: identified in other vanes by a duct and over the wire by a "bone":
:: an opaque number. Each flow has a FIFO queue of %plea requests
:: from the requesting ship to the responding ship and a FIFO queue
:: of %boon's in the other direction.
::
:: Message order across flows is not specified and may vary based on
:: network conditions.
::
:: Ames guarantees that a message will only be delivered once to the
:: destination vane.
::
:: Ames encrypts every message using symmetric-key encryption by
:: performing an elliptic curve Diffie-Hellman using our private key
:: and the public key of the peer. For ships in the Jael PKI
:: (public-key infrastructure), Ames looks up the peer's public key
:: from Jael. Comets (128-bit ephemeral addresses) are not
:: cryptographic assets and must self-attest over Ames by sending a
:: single self-signed packet containing their public key.
::
:: When a peer suffers a continuity breach, Ames removes all
:: messaging state related to it. Ames does not guarantee that all
:: messages will be fully delivered to the now-stale peer. From
:: Ames's perspective, the newly restarted peer is a new ship.
:: Ames's guarantees are not maintained across a breach.
::
:: A vane can pass Ames a %heed $task to request Ames track a peer's
:: responsiveness. If our %boon's to it start backing up locally,
:: Ames will give a %clog back to the requesting vane containing the
:: unresponsive peer's urbit address. This interaction does not use
:: ducts as unique keys. Stop tracking a peer by sending Ames a
:: %jilt $task.
::
:: Debug output can be adjusted using %sift and %spew $task's.
2019-06-29 01:27:59 +03:00
::
2022-01-27 16:32:49 +03:00
::TODO fine
:: - receiving packets: +on-hear (1st) -> +on-hear-packet -> %fine
:: - sending packets: +on-plea -> +make-peer-core (make a function kind of like +on-memo) -> call +on-pump-send kind of like how +run-message-pump does
:: (assuming as event, scry just stateless)
::
2019-05-25 08:53:29 +03:00
:: protocol-version: current version of the ames wire protocol
::
2019-06-29 02:43:52 +03:00
!:
2022-01-27 16:32:49 +03:00
=/ protocol-version=?(%0 %1 %2 %3 %4 %5 %6 %7) %0
2019-06-29 02:43:52 +03:00
=, ames
2020-12-08 03:47:06 +03:00
=* point point:jael
=* public-keys-result public-keys-result:jael
2019-12-03 02:46:40 +03:00
:: veb: verbosity flags
::
=/ veb-all-off
:* snd=`?`%.n :: sending packets
rcv=`?`%.n :: receiving packets
odd=`?`%.n :: unusual events
2019-12-11 21:55:16 +03:00
msg=`?`%.n :: message-level events
2019-12-03 02:46:40 +03:00
ges=`?`%.n :: congestion control
2019-12-11 21:55:16 +03:00
for=`?`%.n :: packet forwarding
2019-12-03 02:46:40 +03:00
rot=`?`%.n :: routing attempts
2019-11-15 03:10:48 +03:00
==
2019-12-03 02:46:40 +03:00
=>
2020-12-05 07:32:17 +03:00
~% %ames ..part ~
2019-11-15 03:10:48 +03:00
|%
2020-12-01 17:51:14 +03:00
+| %helpers
2019-12-11 21:55:16 +03:00
:: +trace: print if .verb is set and we're tracking .ship
2019-12-03 02:46:40 +03:00
::
2019-11-15 03:10:48 +03:00
++ trace
2019-12-11 21:55:16 +03:00
|= [verb=? =ship ships=(set ship) print=(trap tape)]
^+ same
2019-11-15 03:10:48 +03:00
?. verb
same
2019-12-11 21:55:16 +03:00
?. => [ship=ship ships=ships in=in]
~+ |(=(~ ships) (~(has in ships) ship))
same
(slog leaf/"ames: {(scow %p ship)}: {(print)}" ~)
2020-12-01 17:51:14 +03:00
:: +qos-update-text: notice text for if connection state changes
::
++ qos-update-text
|= [=ship old=qos new=qos]
^- (unit tape)
::
?+ [-.old -.new] ~
[%unborn %live] `"; {(scow %p ship)} is your neighbor"
[%dead %live] `"; {(scow %p ship)} is ok"
[%live %dead] `"; {(scow %p ship)} not responding still trying"
[%unborn %dead] `"; {(scow %p ship)} not responding still trying"
[%live %unborn] `"; {(scow %p ship)} has sunk"
[%dead %unborn] `"; {(scow %p ship)} has sunk"
==
:: +lte-packets: yes if a is before b
::
++ lte-packets
|= [a=live-packet-key b=live-packet-key]
^- ?
::
?: (lth message-num.a message-num.b)
%.y
?: (gth message-num.a message-num.b)
%.n
(lte fragment-num.a fragment-num.b)
:: +split-message: split message into kilobyte-sized fragments
::
:: We don't literally split it here since that would allocate many
:: large atoms with no structural sharing. Instead, each
:: static-fragment has the entire message and a counter. In
:: +encrypt, we interpret this to get the actual fragment.
::
++ split-message
~/ %split-message
|= [=message-num =message-blob]
^- (list static-fragment)
::
=/ num-fragments=fragment-num (met 13 message-blob)
=| counter=@
::
|- ^- (list static-fragment)
?: (gte counter num-fragments)
~
::
:- [message-num num-fragments counter `@`message-blob]
$(counter +(counter))
:: +assemble-fragments: concatenate fragments into a $message
::
++ assemble-fragments
~/ %assemble-fragments
|= [num-fragments=fragment-num fragments=(map fragment-num fragment)]
^- *
::
=| sorted=(list fragment)
=. sorted
=/ index=fragment-num 0
|- ^+ sorted
?: =(index num-fragments)
sorted
$(index +(index), sorted [(~(got by fragments) index) sorted])
::
2020-12-04 01:26:55 +03:00
(cue (rep 13 (flop sorted)))
2021-01-20 23:29:45 +03:00
:: +jim: caching +jam
::
++ jim |=(n=* ~+((jam n)))
2020-12-01 17:51:14 +03:00
:: +bind-duct: find or make new $bone for .duct in .ossuary
::
++ bind-duct
|= [=ossuary =duct]
^+ [next-bone.ossuary ossuary]
::
?^ existing=(~(get by by-duct.ossuary) duct)
[u.existing ossuary]
::
:- next-bone.ossuary
:+ (add 4 next-bone.ossuary)
(~(put by by-duct.ossuary) duct next-bone.ossuary)
(~(put by by-bone.ossuary) next-bone.ossuary duct)
:: +make-bone-wire: encode ship and bone in wire for sending to vane
::
++ make-bone-wire
|= [her=ship =bone]
^- wire
::
/bone/(scot %p her)/(scot %ud bone)
:: +parse-bone-wire: decode ship and bone from wire from local vane
::
++ parse-bone-wire
|= =wire
^- [her=ship =bone]
::
~| %ames-wire-bone^wire
?> ?=([%bone @ @ ~] wire)
[`@p`(slav %p i.t.wire) `@ud`(slav %ud i.t.t.wire)]
:: +make-pump-timer-wire: construct wire for |packet-pump timer
::
++ make-pump-timer-wire
|= [her=ship =bone]
^- wire
/pump/(scot %p her)/(scot %ud bone)
:: +parse-pump-timer-wire: parse .her and .bone from |packet-pump wire
::
++ parse-pump-timer-wire
|= =wire
^- (unit [her=ship =bone])
::
~| %ames-wire-timer^wire
?. ?=([%pump @ @ ~] wire)
~
?~ ship=`(unit @p)`(slaw %p i.t.wire)
~
?~ bone=`(unit @ud)`(slaw %ud i.t.t.wire)
~
`[u.ship u.bone]
:: +derive-symmetric-key: $symmetric-key from $private-key and $public-key
::
:: Assumes keys have a tag on them like the result of the |ex:crub core.
::
++ derive-symmetric-key
~/ %derive-symmetric-key
|= [=public-key =private-key]
^- symmetric-key
::
2020-12-04 01:25:31 +03:00
?> =('b' (end 3 public-key))
=. public-key (rsh 8 (rsh 3 public-key))
2020-12-01 17:51:14 +03:00
::
2020-12-04 01:25:31 +03:00
?> =('B' (end 3 private-key))
=. private-key (rsh 8 (rsh 3 private-key))
2020-12-01 17:51:14 +03:00
::
`@`(shar:ed:crypto public-key private-key)
2022-01-27 16:32:49 +03:00
:: +encode-packet: serialize a packet into a bytestream
::
++ encode-packet
|= [ames=? packet]
^- blob
::
=/ sndr-meta (encode-ship-metadata sndr)
=/ rcvr-meta (encode-ship-metadata rcvr)
::
=/ body=@
;: mix
sndr-tick
(lsh 2 rcvr-tick)
(lsh 3 sndr)
(lsh [3 +(size.sndr-meta)] rcvr)
(lsh [3 +((add size.sndr-meta size.rcvr-meta))] content)
==
=/ checksum (end [0 20] (mug body))
=? body ?=(^ origin) (mix u.origin (lsh [3 6] body))
::
=/ header=@
%+ can 0
:~ [3 reserved=0]
[1 is-ames=ames]
[3 protocol-version]
[2 rank.sndr-meta]
[2 rank.rcvr-meta]
[20 checksum]
[1 relayed=.?(origin)]
==
(mix header (lsh 5 body))
:: +decode-packet: deserialize packet from bytestream or crash
::
++ decode-packet
|= =blob
^- [ames=? =packet]
~| %decode-packet-fail
:: first 32 (2^5) bits are header; the rest is body
::
=/ header (end 5 blob)
=/ body (rsh 5 blob)
:: read header; first three bits are reserved
::
=/ is-ames (cut 0 [3 1] header)
:- =(& is-ames)
::
=/ version (cut 0 [4 3] header)
?. =(protocol-version version)
~| ames-protocol-version+version !!
::
=/ sndr-size (decode-ship-size (cut 0 [7 2] header))
=/ rcvr-size (decode-ship-size (cut 0 [9 2] header))
=/ checksum (cut 0 [11 20] header)
=/ relayed (cut 0 [31 1] header)
:: origin, if present, is 6 octets long, at the end of the body
::
=^ origin=(unit @) body
?: =(| relayed)
[~ body]
=/ len (sub (met 3 body) 6)
[`(end [3 6] body) (rsh [3 6] body)]
:: .checksum does not apply to the origin
::
?. =(checksum (end [0 20] (mug body)))
~| %ames-checksum !!
:: read fixed-length sndr and rcvr life data from body
::
:: These represent the last four bits of the sender and receiver
:: life fields, to be used for quick dropping of honest packets to
:: or from the wrong life.
::
=/ sndr-tick (cut 0 [0 4] body)
=/ rcvr-tick (cut 0 [4 4] body)
:: read variable-length .sndr and .rcvr addresses
::
=/ off 1
=^ sndr off [(cut 3 [off sndr-size] body) (add off sndr-size)]
?. (is-valid-rank sndr sndr-size)
~| ames-sender-impostor+[sndr sndr-size] !!
::
=^ rcvr off [(cut 3 [off rcvr-size] body) (add off rcvr-size)]
?. (is-valid-rank rcvr rcvr-size)
~| ames-receiver-impostor+[rcvr rcvr-size] !!
:: read variable-length .content from the rest of .body
::
=/ content (cut 3 [off (sub (met 3 body) off)] body)
[[sndr rcvr] sndr-tick rcvr-tick origin content]
:: +is-valid-rank: does .ship match its stated .size?
::
++ is-valid-rank
|= [=ship size=@ubC]
^- ?
.= size
=/ wid (met 3 ship)
?: (lte wid 1) 2
?: =(2 wid) 2
?: (lte wid 4) 4
?: (lte wid 8) 8
?> (lte wid 16) 16
2020-12-01 17:51:14 +03:00
:: +encode-open-packet: convert $open-packet attestation to $packet
::
++ encode-open-packet
~/ %encode-open-packet
|= [pac=open-packet =acru:ames]
^- packet
:* [sndr rcvr]:pac
(mod sndr-life.pac 16)
(mod rcvr-life.pac 16)
origin=~
content=`@`(sign:as:acru (jam pac))
==
:: +decode-open-packet: decode comet attestation into an $open-packet
::
++ decode-open-packet
~/ %decode-open-packet
|= [=packet our=ship our-life=@]
^- open-packet
:: deserialize and type-check packet contents
::
=+ ;; [signature=@ signed=@] (cue content.packet)
=+ ;; =open-packet (cue signed)
:: assert .our and .her and lives match
::
?> .= sndr.open-packet sndr.packet
?> .= rcvr.open-packet our
?> .= sndr-life.open-packet 1
?> .= rcvr-life.open-packet our-life
:: only a star can sponsor a comet
::
?> =(%king (clan:title (^sein:title sndr.packet)))
:: comet public-key must hash to its @p address
::
?> =(sndr.packet fig:ex:(com:nu:crub:crypto public-key.open-packet))
:: verify signature
::
:: Logic duplicates +com:nu:crub:crypto and +sure:as:crub:crypto.
::
2020-12-04 01:25:31 +03:00
=/ key (end 8 (rsh 3 public-key.open-packet))
2020-12-01 17:51:14 +03:00
?> (veri:ed:crypto signature signed key)
open-packet
:: +encode-shut-packet: encrypt and packetize a $shut-packet
::
++ encode-shut-packet
~/ %encode-shut-packet
|= $: =shut-packet
=symmetric-key
sndr=ship
rcvr=ship
sndr-life=@
rcvr-life=@
==
^- packet
::
=? meat.shut-packet
?& ?=(%& -.meat.shut-packet)
(gth (met 13 fragment.p.meat.shut-packet) 1)
==
%_ meat.shut-packet
fragment.p
(cut 13 [[fragment-num 1] fragment]:p.meat.shut-packet)
==
::
=/ vec ~[sndr rcvr sndr-life rcvr-life]
=/ [siv=@uxH len=@ cyf=@ux]
(~(en sivc:aes:crypto (shaz symmetric-key) vec) (jam shut-packet))
2020-12-04 01:25:31 +03:00
=/ content :(mix siv (lsh 7 len) (lsh [3 18] cyf))
2020-12-01 17:51:14 +03:00
[[sndr rcvr] (mod sndr-life 16) (mod rcvr-life 16) origin=~ content]
:: +decode-shut-packet: decrypt a $shut-packet from a $packet
::
++ decode-shut-packet
~/ %decode-shut-packet
|= [=packet =symmetric-key sndr-life=@ rcvr-life=@]
^- shut-packet
?. =(sndr-tick.packet (mod sndr-life 16))
~| ames-sndr-tick+sndr-tick.packet !!
?. =(rcvr-tick.packet (mod rcvr-life 16))
~| ames-rcvr-tick+rcvr-tick.packet !!
2020-12-04 01:25:31 +03:00
=/ siv (end 7 content.packet)
=/ len (end 4 (rsh 7 content.packet))
=/ cyf (rsh [3 18] content.packet)
2020-12-01 17:51:14 +03:00
~| ames-decrypt+[[sndr rcvr origin]:packet len siv]
=/ vec ~[sndr.packet rcvr.packet sndr-life rcvr-life]
;; shut-packet %- cue %- need
(~(de sivc:aes:crypto (shaz symmetric-key) vec) siv len cyf)
2022-01-27 16:32:49 +03:00
:: +decode-ship-size: decode a 2-bit ship type specifier into a byte width
::
:: Type 0: galaxy or star -- 2 bytes
:: Type 1: planet -- 4 bytes
:: Type 2: moon -- 8 bytes
:: Type 3: comet -- 16 bytes
::
++ decode-ship-size
|= rank=@ubC
^- @
::
?+ rank !!
%0b0 2
%0b1 4
%0b10 8
%0b11 16
==
:: +encode-ship-metadata: produce size (in bytes) and address rank for .ship
::
:: 0: galaxy or star
:: 1: planet
:: 2: moon
:: 3: comet
::
++ encode-ship-metadata
|= =ship
^- [size=@ =rank]
::
=/ size=@ (met 3 ship)
::
?: (lte size 2) [2 %0b0]
?: (lte size 4) [4 %0b1]
?: (lte size 8) [8 %0b10]
[16 %0b11]
2019-05-25 08:53:29 +03:00
+| %atomics
2019-05-25 05:03:33 +03:00
::
2019-06-11 23:22:24 +03:00
+$ private-key @uwprivatekey
2019-05-27 02:54:23 +03:00
+$ signature @uwsignature
2022-01-27 16:32:49 +03:00
:: $rank: which kind of ship address, by length
::
:: 0b0: galaxy or star -- 2 bytes
:: 0b1: planet -- 4 bytes
:: 0b10: moon -- 8 bytes
:: 0b11: comet -- 16 bytes
::
+$ rank ?(%0b0 %0b1 %0b10 %0b11)
2019-05-25 08:53:29 +03:00
::
2019-05-27 06:22:38 +03:00
+| %kinetics
2019-05-27 04:48:41 +03:00
:: $channel: combined sender and receiver identifying data
2019-05-25 08:53:29 +03:00
::
2019-05-27 04:48:41 +03:00
+$ channel
2019-05-27 04:52:31 +03:00
$: [our=ship her=ship]
2019-05-29 01:05:59 +03:00
now=@da
2019-05-27 04:48:41 +03:00
:: our data, common to all dyads
::
$: =our=life
crypto-core=acru:ames
2019-12-11 21:55:16 +03:00
=bug
2019-05-27 04:48:41 +03:00
==
:: her data, specific to this dyad
::
$: =symmetric-key
=her=life
=her=public-key
2019-06-22 03:07:19 +03:00
her-sponsor=ship
2019-05-27 04:48:41 +03:00
== ==
2022-01-27 16:32:49 +03:00
:: $dyad: pair of sender and receiver ships
::
+$ dyad [sndr=ship rcvr=ship]
:: $packet: noun representation of an ames datagram packet
::
:: Roundtrips losslessly through atom encoding and decoding.
::
:: .origin is ~ unless the packet is being forwarded. If present,
:: it's an atom that encodes a route to another ship, such as an IPv4
:: address. Routes are opaque to Arvo and only have meaning in the
:: interpreter. This enforces that Ames is transport-agnostic.
::
+$ packet
$: dyad
sndr-tick=@ubC
rcvr-tick=@ubC
origin=(unit @uxaddress)
content=@uxcontent
==
2019-05-27 02:54:23 +03:00
:: $open-packet: unencrypted packet payload, for comet self-attestation
::
2019-11-27 09:15:05 +03:00
:: This data structure gets signed and jammed to form the .contents
:: field of a $packet.
2019-06-18 02:23:32 +03:00
::
2019-05-27 02:54:23 +03:00
+$ open-packet
2019-11-27 09:15:05 +03:00
$: =public-key
2019-06-18 02:23:32 +03:00
sndr=ship
2019-05-27 02:54:23 +03:00
=sndr=life
rcvr=ship
2019-06-18 02:23:32 +03:00
=rcvr=life
2019-05-27 02:54:23 +03:00
==
:: $shut-packet: encrypted packet payload
::
+$ shut-packet
2020-12-01 17:51:14 +03:00
$: =bone
2019-05-27 02:54:23 +03:00
=message-num
meat=(each fragment-meat ack-meat)
==
:: $fragment-meat: contents of a message-fragment packet
::
+$ fragment-meat
$: num-fragments=fragment-num
=fragment-num
=fragment
==
:: $ack-meat: contents of an acknowledgment packet; fragment or message
::
:: Fragment acks reference the $fragment-num of the target packet.
::
:: Message acks contain a success flag .ok, which is %.n in case of
:: negative acknowledgment (nack), along with .lag that describes the
:: time it took to process the message. .lag is zero if the message
:: was processed during a single Arvo event. At the moment, .lag is
:: always zero.
::
+$ ack-meat (each fragment-num [ok=? lag=@dr])
2019-11-03 03:52:48 +03:00
:: $naxplanation: nack trace; explains which message failed and why
::
+$ naxplanation [=message-num =error]
2019-05-25 08:53:29 +03:00
::
2019-05-27 04:52:31 +03:00
+| %statics
2019-05-25 08:53:29 +03:00
::
:: $ames-state: state for entire vane
::
2019-12-11 21:55:16 +03:00
:: peers: states of connections to other ships
:: unix-duct: handle to give moves to unix
:: life: our $life; how many times we've rekeyed
:: crypto-core: interface for encryption and signing
:: bug: debug printing configuration
::
2019-05-25 08:53:29 +03:00
+$ ames-state
$: peers=(map ship ship-state)
2019-06-08 13:13:38 +03:00
=unix=duct
2019-05-25 08:53:29 +03:00
=life
crypto-core=acru:ames
2019-12-11 21:55:16 +03:00
=bug
2022-01-27 16:32:49 +03:00
=fine-state
==
+$ ames-state-5
2022-01-29 01:09:50 +03:00
$: peers=(map ship ship-state-5)
2022-01-27 16:32:49 +03:00
=unix=duct
=life
crypto-core=acru:ames
=bug
==
2022-01-29 01:09:50 +03:00
+$ ship-state-5
$% [%alien alien-agenda-5]
[%known peer-state]
==
+$ alien-agenda-5
$: messages=(list [=duct =plea])
packets=(set =blob)
heeds=(set duct)
==
2022-01-27 16:32:49 +03:00
:: $fine-state: remote scry subsystem state
::
:: hear: awaiting existence
:: want: awaiting response
:: part: partial responses
::
+$ fine-state
$: hear=(jug path duct)
want=(jug path duct)
part=(map path partial-fine)
::TODO re-send request timers?
==
:: $partial-fine: partial remote scry response
::
+$ partial-fine
$: num-fragments=@ud
num-received=@ud
fragments=(map @ud byts) ::TODO not byts, always 1024 bytes, just @
2019-12-11 21:55:16 +03:00
==
:: $bug: debug printing configuration
::
:: veb: verbosity toggles
:: ships: identity filter; if ~, print for all
::
+$ bug
$: veb=_veb-all-off
ships=(set ship)
2019-05-25 08:53:29 +03:00
==
2019-05-27 06:22:38 +03:00
::
+| %dialectics
::
2019-05-28 05:43:47 +03:00
:: $move: output effect; either request or response
::
2019-05-28 06:15:17 +03:00
+$ move [=duct card=(wind note gift)]
2019-06-29 00:26:40 +03:00
:: $queued-event: event to be handled after initial boot completes
2019-05-28 05:43:47 +03:00
::
2019-06-29 00:26:40 +03:00
+$ queued-event
2020-12-06 11:38:37 +03:00
$% [%call =duct wrapped-task=(hobo task)]
[%take =wire =duct =sign]
2019-05-28 04:43:10 +03:00
==
:: $note: request to other vane
::
2019-07-28 10:50:32 +03:00
:: Ames passes a %plea note to another vane when it receives a
2019-06-19 02:15:50 +03:00
:: message on a "forward flow" from a peer, originally passed from
:: one of the peer's vanes to the peer's Ames.
::
2019-07-28 10:50:32 +03:00
:: Ames passes a %plea to itself to trigger a heartbeat message to
2019-06-25 01:18:18 +03:00
:: our sponsor.
::
2019-06-25 02:52:22 +03:00
:: Ames passes a %private-keys to Jael to request our private keys.
:: Ames passes a %public-keys to Jael to request a peer's public
:: keys.
::
2019-05-28 04:43:10 +03:00
+$ note
2019-06-29 00:26:40 +03:00
$~ [%b %wait *@da]
$% $: %b
2019-05-28 04:43:10 +03:00
$% [%wait date=@da]
[%rest date=@da]
== ==
2019-08-08 07:57:04 +03:00
$: %d
$% [%flog flog:dill]
2019-05-28 04:43:10 +03:00
== ==
$: %j
2019-06-29 00:26:40 +03:00
$% [%private-keys ~]
2019-06-29 01:27:59 +03:00
[%public-keys ships=(set ship)]
2019-05-28 04:43:10 +03:00
[%turf ~]
== ==
2019-06-29 00:26:40 +03:00
$: @tas
2019-07-28 10:50:32 +03:00
$% [%plea =ship =plea]
2019-05-28 04:43:10 +03:00
== == ==
:: $sign: response from other vane
::
+$ sign
2020-12-08 03:22:26 +03:00
$~ [%behn %wake ~]
$% $: %behn
2020-12-08 05:51:58 +03:00
$% $>(%wake gift:behn)
2019-05-28 04:43:10 +03:00
== ==
2020-12-08 03:22:26 +03:00
$: %jael
2019-07-23 05:16:19 +03:00
$% [%private-keys =life vein=(map life ring)]
2019-07-29 12:08:26 +03:00
[%public-keys =public-keys-result]
2019-06-22 01:17:09 +03:00
[%turf turfs=(list turf)]
2019-06-18 21:21:12 +03:00
== ==
2019-06-29 00:26:40 +03:00
$: @tas
2019-06-20 10:21:37 +03:00
$% [%done error=(unit error)]
2019-07-28 10:50:32 +03:00
[%boon payload=*]
2019-05-28 04:43:10 +03:00
== == ==
2019-05-27 06:22:38 +03:00
:: $message-pump-task: job for |message-pump
::
2019-06-25 19:00:03 +03:00
:: %memo: packetize and send application-level message
2019-06-20 10:21:37 +03:00
:: %hear: handle receipt of ack on fragment or message
2019-12-02 23:20:57 +03:00
:: %near: handle receipt of naxplanation
2019-05-27 06:22:38 +03:00
:: %wake: handle timer firing
::
+$ message-pump-task
2019-07-28 10:50:32 +03:00
$% [%memo =message-blob]
2019-06-20 10:21:37 +03:00
[%hear =message-num =ack-meat]
2019-12-02 23:20:57 +03:00
[%near =naxplanation]
2019-05-27 06:22:38 +03:00
[%wake ~]
==
:: $message-pump-gift: effect from |message-pump
::
2019-06-20 10:21:37 +03:00
:: %done: report message acknowledgment
2019-05-31 03:20:42 +03:00
:: %send: emit message fragment
:: %wait: set a new timer at .date
:: %rest: cancel timer at .date
2019-05-27 06:22:38 +03:00
::
+$ message-pump-gift
2019-12-02 23:20:57 +03:00
$% [%done =message-num error=(unit error)]
2019-05-31 03:20:42 +03:00
[%send =static-fragment]
[%wait date=@da]
[%rest date=@da]
2019-05-27 06:22:38 +03:00
==
:: $packet-pump-task: job for |packet-pump
::
2019-06-20 10:21:37 +03:00
:: %hear: deal with a packet acknowledgment
:: %done: deal with message acknowledgment
:: %halt: finish event, possibly updating timer
2019-05-27 06:22:38 +03:00
:: %wake: handle timer firing
::
+$ packet-pump-task
2019-06-20 10:21:37 +03:00
$% [%hear =message-num =fragment-num]
[%done =message-num lag=@dr]
[%halt ~]
2019-12-10 10:14:06 +03:00
[%wake current=message-num]
2019-05-27 06:22:38 +03:00
==
:: $packet-pump-gift: effect from |packet-pump
::
2019-05-31 03:20:42 +03:00
:: %send: emit message fragment
:: %wait: set a new timer at .date
:: %rest: cancel timer at .date
2019-05-27 06:22:38 +03:00
::
+$ packet-pump-gift
2019-05-31 03:20:42 +03:00
$% [%send =static-fragment]
[%wait date=@da]
[%rest date=@da]
2019-05-27 06:22:38 +03:00
==
2019-10-30 23:12:57 +03:00
:: $message-sink-task: job for |message-sink
2019-05-29 01:05:59 +03:00
::
2019-06-18 21:21:12 +03:00
:: %done: receive confirmation from vane of processing or failure
2019-06-20 10:21:37 +03:00
:: %drop: clear .message-num from .nax.state
2019-06-11 03:31:50 +03:00
:: %hear: handle receiving a message fragment packet
2019-08-06 02:05:40 +03:00
:: .ok: %.y unless previous failed attempt
2019-05-29 01:05:59 +03:00
::
2019-10-30 23:12:57 +03:00
+$ message-sink-task
2019-06-18 21:21:12 +03:00
$% [%done ok=?]
2019-06-20 10:21:37 +03:00
[%drop =message-num]
2019-08-06 02:05:40 +03:00
[%hear =lane =shut-packet ok=?]
2019-05-29 01:05:59 +03:00
==
2019-10-30 23:12:57 +03:00
:: $message-sink-gift: effect from |message-sink
2019-05-29 01:05:59 +03:00
::
2019-07-28 10:50:32 +03:00
:: %memo: assembled from received packets
2019-06-20 10:21:37 +03:00
:: %send: emit an ack packet
2019-05-29 01:05:59 +03:00
::
2019-10-30 23:12:57 +03:00
+$ message-sink-gift
2019-07-28 10:50:32 +03:00
$% [%memo =message-num message=*]
2019-06-20 10:21:37 +03:00
[%send =message-num =ack-meat]
2019-05-29 01:05:59 +03:00
==
2019-05-25 05:03:33 +03:00
--
2019-05-28 04:43:10 +03:00
:: external vane interface
::
2020-12-06 11:38:37 +03:00
|= our=ship
2019-06-29 00:26:40 +03:00
:: larval ames, before %born sets .unix-duct; wraps adult ames core
::
=< =* adult-gate .
=| queued-events=(qeu queued-event)
::
2020-12-06 11:38:37 +03:00
|= [now=@da eny=@ rof=roof]
2019-06-29 00:26:40 +03:00
=* larval-gate .
=* adult-core (adult-gate +<)
|%
:: +call: handle request $task
::
++ call
2020-12-06 11:38:37 +03:00
|= [=duct dud=(unit goof) wrapped-task=(hobo task)]
2019-07-23 05:16:19 +03:00
::
2020-01-21 02:01:36 +03:00
=/ =task ((harden task) wrapped-task)
2020-02-24 22:09:37 +03:00
::
2020-12-08 05:01:48 +03:00
:: reject larval error notifications
2020-02-24 22:09:37 +03:00
::
2020-12-08 05:01:48 +03:00
?^ dud
~|(%ames-larval-call-dud (mean tang.u.dud))
2020-02-24 22:09:37 +03:00
::
2019-06-29 00:26:40 +03:00
:: %born: set .unix-duct and start draining .queued-events
::
2019-07-23 05:16:19 +03:00
?: ?=(%born -.task)
2019-06-29 00:26:40 +03:00
:: process %born using wrapped adult ames
::
2020-12-06 11:38:37 +03:00
=^ moves adult-gate (call:adult-core duct dud task)
2019-06-29 00:26:40 +03:00
:: if no events were queued up, metamorphose
::
?~ queued-events
2019-08-10 21:48:40 +03:00
~> %slog.0^leaf/"ames: metamorphosis"
2019-06-29 00:26:40 +03:00
[moves adult-gate]
:: kick off a timer to process the first of .queued-events
::
=. moves :_(moves [duct %pass /larva %b %wait now])
[moves larval-gate]
:: any other event: enqueue it until we have a .unix-duct
::
2020-02-11 01:03:03 +03:00
:: XX what to do with errors?
::
2020-12-06 11:38:37 +03:00
=. queued-events (~(put to queued-events) %call duct task)
2019-06-29 00:26:40 +03:00
[~ larval-gate]
:: +take: handle response $sign
::
++ take
2020-12-06 11:38:37 +03:00
|= [=wire =duct dud=(unit goof) =sign]
2020-02-25 01:10:59 +03:00
?^ dud
~|(%ames-larval-take-dud (mean tang.u.dud))
2019-06-29 00:26:40 +03:00
:: enqueue event if not a larval drainage timer
::
2020-02-11 01:03:03 +03:00
:: XX what to do with errors?
::
2019-06-29 00:26:40 +03:00
?. =(/larva wire)
2020-12-06 11:38:37 +03:00
=. queued-events (~(put to queued-events) %take wire duct sign)
2019-06-29 00:26:40 +03:00
[~ larval-gate]
:: larval event drainage timer; pop and process a queued event
::
2020-12-08 03:22:26 +03:00
?. ?=([%behn %wake *] sign)
2019-08-10 21:48:40 +03:00
~> %slog.0^leaf/"ames: larva: strange sign"
2019-07-23 05:16:19 +03:00
[~ larval-gate]
2019-12-04 19:04:09 +03:00
:: if crashed, print, dequeue, and set next drainage timer
::
2019-12-04 17:45:52 +03:00
?^ error.sign
2019-12-04 21:43:07 +03:00
:: .queued-events should never be ~ here, but if it is, don't crash
::
?: =(~ queued-events)
=/ =tang [leaf/"ames: cursed metamorphosis" u.error.sign]
=/ moves [duct %pass /larva-crash %d %flog %crud %larva tang]~
[moves adult-gate]
:: dequeue and discard crashed event
::
2019-12-04 19:04:09 +03:00
=. queued-events +:~(get to queued-events)
:: .queued-events has been cleared; metamorphose
::
?~ queued-events
~> %slog.0^leaf/"ames: metamorphosis"
[~ adult-gate]
:: set timer to drain next event
::
2019-12-04 19:29:01 +03:00
=/ moves
=/ =tang [leaf/"ames: larva: drain crash" u.error.sign]
:~ [duct %pass /larva-crash %d %flog %crud %larva tang]
[duct %pass /larva %b %wait now]
==
2019-12-04 17:45:52 +03:00
[moves larval-gate]
:: normal drain timer; dequeue and run event
::
2019-06-29 00:26:40 +03:00
=^ first-event queued-events ~(get to queued-events)
=^ moves adult-gate
?- -.first-event
2020-12-06 11:38:37 +03:00
%call (call:adult-core [duct ~ wrapped-task]:+.first-event)
%take (take:adult-core [wire duct ~ sign]:+.first-event)
2019-06-29 00:26:40 +03:00
==
:: .queued-events has been cleared; metamorphose
::
?~ queued-events
2019-08-10 21:48:40 +03:00
~> %slog.0^leaf/"ames: metamorphosis"
2019-06-29 00:26:40 +03:00
[moves adult-gate]
:: set timer to drain next event
::
=. moves :_(moves [duct %pass /larva %b %wait now])
[moves larval-gate]
:: lifecycle arms; mostly pass-throughs to the contained adult ames
::
++ scry scry:adult-core
2022-01-27 16:32:49 +03:00
++ stay [%6 %larva queued-events ames-state.adult-gate]
2019-06-29 00:26:40 +03:00
++ load
2019-07-31 21:51:31 +03:00
|= $= old
2020-06-12 08:55:08 +03:00
$% $: %4
$% $: %larva
events=(qeu queued-event)
2022-01-27 16:32:49 +03:00
state=ames-state-5
2020-06-12 08:55:08 +03:00
==
2022-01-27 16:32:49 +03:00
[%adult state=ames-state-5]
2020-06-12 08:55:08 +03:00
== ==
2021-02-27 07:53:27 +03:00
$: %5
2022-01-27 16:32:49 +03:00
$% $: %larva
events=(qeu queued-event)
state=ames-state-5
==
[%adult state=ames-state-5]
== ==
$: %6
2021-02-27 07:53:27 +03:00
$% $: %larva
events=(qeu queued-event)
state=_ames-state.adult-gate
==
[%adult state=_ames-state.adult-gate]
== ==
2020-11-25 18:22:20 +03:00
==
2019-12-01 10:47:24 +03:00
?- old
2020-06-12 08:55:08 +03:00
[%4 %adult *] (load:adult-core %4 state.old)
2019-12-11 21:55:16 +03:00
::
2020-06-12 08:55:08 +03:00
[%4 %larva *]
2019-12-11 21:55:16 +03:00
~> %slog.1^leaf/"ames: larva: load"
=. queued-events events.old
2020-06-12 08:55:08 +03:00
=. adult-gate (load:adult-core %4 state.old)
larval-gate
2021-02-27 07:53:27 +03:00
::
[%5 %adult *] (load:adult-core %5 state.old)
::
[%5 %larva *]
~> %slog.1^leaf/"ames: larva: load"
=. queued-events events.old
=. adult-gate (load:adult-core %5 state.old)
larval-gate
2022-01-27 16:32:49 +03:00
::
[%6 %adult *] (load:adult-core %6 state.old)
::
[%6 %larva *]
~> %slog.1^leaf/"ames: larva: load"
=. queued-events events.old
=. adult-gate (load:adult-core %6 state.old)
larval-gate
2019-07-24 02:55:35 +03:00
==
2019-06-29 00:26:40 +03:00
--
:: adult ames, after metamorphosis from larva
::
=<
2019-05-28 04:43:10 +03:00
=| =ames-state
2020-12-06 11:38:37 +03:00
|= [now=@da eny=@ rof=roof]
2019-05-28 04:43:10 +03:00
=* ames-gate .
2019-12-11 21:55:16 +03:00
=* veb veb.bug.ames-state
2019-05-28 04:43:10 +03:00
|%
:: +call: handle request $task
::
++ call
2020-12-06 11:38:37 +03:00
|= [=duct dud=(unit goof) wrapped-task=(hobo task)]
2019-05-28 04:43:10 +03:00
^- [(list move) _ames-gate]
::
2020-01-21 02:01:36 +03:00
=/ =task ((harden task) wrapped-task)
2020-12-06 13:55:19 +03:00
=/ event-core (per-event [now eny rof] duct ames-state)
2019-05-28 05:43:47 +03:00
::
=^ moves ames-state
2020-12-08 05:01:48 +03:00
:: handle error notifications
::
?^ dud
2022-01-27 16:32:49 +03:00
=< abet
2020-12-08 05:01:48 +03:00
?+ -.task
(on-crud:event-core -.task tang.u.dud)
2020-12-12 03:49:55 +03:00
%hear (on-hear:event-core lane.task blob.task dud)
2020-12-08 05:01:48 +03:00
==
::
2022-01-27 16:32:49 +03:00
?: ?=(?(%keen %yawn %bide) -.task)
=/ fine-core (fine now rof duct ames-state)
?- -.task
%keen (on-keen:fine-core +.task)
%yawn (on-yawn:fine-core +.task)
%bide (on-bide:fine-core +.task)
==
::
=< abet
2019-05-28 05:43:47 +03:00
?- -.task
2019-06-22 01:26:26 +03:00
%born on-born:event-core
2020-12-12 03:49:55 +03:00
%hear (on-hear:event-core [lane blob ~]:task)
2019-11-04 04:35:45 +03:00
%heed (on-heed:event-core ship.task)
2020-12-06 11:38:37 +03:00
%init on-init:event-core
2019-11-04 04:35:45 +03:00
%jilt (on-jilt:event-core ship.task)
2019-12-11 21:55:16 +03:00
%sift (on-sift:event-core ships.task)
2019-12-03 02:46:40 +03:00
%spew (on-spew:event-core veb.task)
2020-05-28 20:24:29 +03:00
%stir (on-stir:event-core arg.task)
2020-05-20 10:29:54 +03:00
%trim on-trim:event-core
2019-06-22 01:19:24 +03:00
%vega on-vega:event-core
2019-07-28 10:50:32 +03:00
%plea (on-plea:event-core [ship plea]:task)
2019-05-28 05:43:47 +03:00
==
::
[moves ames-gate]
2019-05-28 04:43:10 +03:00
:: +take: handle response $sign
::
++ take
2020-12-06 11:38:37 +03:00
|= [=wire =duct dud=(unit goof) =sign]
2019-05-28 04:43:10 +03:00
^- [(list move) _ames-gate]
2020-02-25 01:10:59 +03:00
?^ dud
~|(%ames-take-dud (mean tang.u.dud))
::
2019-05-28 04:43:10 +03:00
::
2020-12-06 13:55:19 +03:00
=/ event-core (per-event [now eny rof] duct ames-state)
2019-06-18 21:21:12 +03:00
::
=^ moves ames-state
=< abet
?- sign
2019-06-29 00:26:40 +03:00
[@ %done *] (on-take-done:event-core wire error.sign)
2019-07-28 10:50:32 +03:00
[@ %boon *] (on-take-boon:event-core wire payload.sign)
2019-06-19 02:15:50 +03:00
::
2020-12-08 03:22:26 +03:00
[%behn %wake *] (on-take-wake:event-core wire error.sign)
2019-06-19 02:15:50 +03:00
::
2020-12-08 03:22:26 +03:00
[%jael %turf *] (on-take-turf:event-core turfs.sign)
[%jael %private-keys *] (on-priv:event-core [life vein]:sign)
[%jael %public-keys *] (on-publ:event-core wire public-keys-result.sign)
2019-06-18 21:21:12 +03:00
==
::
[moves ames-gate]
2019-05-28 04:43:10 +03:00
:: +stay: extract state before reload
::
2022-01-27 16:32:49 +03:00
++ stay [%6 %adult ames-state]
2019-05-28 04:43:10 +03:00
:: +load: load in old state after reload
::
++ load
2022-01-27 16:32:49 +03:00
|^
2021-02-27 07:53:27 +03:00
|= $= old-state
2022-01-27 16:32:49 +03:00
$% [%4 ames-state-5]
[%5 ames-state-5]
[%6 ^ames-state]
2021-02-27 07:53:27 +03:00
==
2020-11-27 15:55:21 +03:00
^+ ames-gate
2021-02-27 07:53:27 +03:00
=? old-state ?=(%4 -.old-state) %5^(state-4-to-5 +.old-state)
2022-01-27 16:32:49 +03:00
=? old-state ?=(%5 -.old-state) %6^(state-5-to-6 +.old-state)
2021-02-27 07:53:27 +03:00
::
2022-01-27 16:32:49 +03:00
?> ?=(%6 -.old-state)
2020-11-27 15:55:21 +03:00
ames-gate(ames-state +.old-state)
2021-02-27 07:53:27 +03:00
::
2022-01-27 16:32:49 +03:00
++ state-5-to-6
|= old=ames-state-5
^- ^ames-state
2022-01-29 01:09:50 +03:00
%= old
peers (~(run by peers.old) ship-state-5-to-6)
bug [bug.old *fine-state]
==
::
++ ship-state-5-to-6
|= old=ship-state-5
^- ship-state
?. ?=(%alien -.old) old
old(heeds [heeds.old ~])
2022-01-27 16:32:49 +03:00
::
2021-02-27 07:53:27 +03:00
++ state-4-to-5
2022-01-27 16:32:49 +03:00
|= ames-state=ames-state-5
^- ames-state-5
2021-02-27 07:53:27 +03:00
=. peers.ames-state
%- ~(run by peers.ames-state)
2022-01-29 01:09:50 +03:00
|= ship-state=ship-state-5
2021-02-27 07:53:27 +03:00
?. ?=(%known -.ship-state)
ship-state
=. snd.ship-state
%- ~(run by snd.ship-state)
|= =message-pump-state
=. num-live.metrics.packet-pump-state.message-pump-state
~(wyt in live.packet-pump-state.message-pump-state)
message-pump-state
ship-state
ames-state
--
2019-05-28 04:43:10 +03:00
:: +scry: dereference namespace
::
++ scry
2020-12-08 00:52:12 +03:00
^- roon
|= [lyc=gang car=term bem=beam]
2019-05-28 04:43:10 +03:00
^- (unit (unit cage))
2020-12-08 00:52:12 +03:00
=* ren car
2020-11-24 00:06:50 +03:00
=* why=shop &/p.bem
=* syd q.bem
=* lot=coin $/r.bem
=* tyl s.bem
::
2020-06-25 21:20:57 +03:00
::TODO don't special-case whey scry
::
?: &(=(%$ ren) =(tyl /whey))
2020-05-07 11:51:08 +03:00
=/ maz=(list mass)
=+ [known alien]=(skid ~(val by peers.ames-state) |=(^ =(%known +<-)))
:~ peers-known+&+known
peers-alien+&+alien
==
``mass+!>(maz)
2020-06-25 21:20:57 +03:00
:: only respond for the local identity, %$ desk, current timestamp
::
?. ?& =(&+our why)
=([%$ %da now] lot)
=(%$ syd)
==
2020-09-18 23:06:13 +03:00
?. for.veb.bug.ames-state ~
~> %slog.0^leaf/"ames: scry-fail {<[why=why lot=lot now=now syd=syd]>}"
2020-06-25 21:20:57 +03:00
~
2020-07-03 01:51:54 +03:00
:: /ax/protocol/version @
:: /ax/peers (map ship ?(%alien %known))
:: /ax/peers/[ship] ship-state
:: /ax/peers/[ship]/forward-lane (list lane)
:: /ax/bones/[ship] [snd=(set bone) rcv=(set bone)]
:: /ax/snd-bones/[ship]/[bone] vase
2022-01-27 16:32:49 +03:00
:: /ax/fine/message/[path/...] song
2020-06-25 21:20:57 +03:00
::
?. ?=(%x ren) ~
2020-07-03 01:51:54 +03:00
?+ tyl ~
[%protocol %version ~]
``noun+!>(protocol-version)
::
2020-06-25 21:20:57 +03:00
[%peers ~]
2020-05-08 02:37:07 +03:00
:^ ~ ~ %noun
!> ^- (map ship ?(%alien %known))
(~(run by peers.ames-state) head)
::
2020-07-03 01:51:54 +03:00
[%peers @ *]
2020-06-25 21:20:57 +03:00
=/ who (slaw %p i.t.tyl)
2020-01-11 01:41:49 +03:00
?~ who [~ ~]
2020-12-06 07:02:31 +03:00
=/ peer (~(get by peers.ames-state) u.who)
?+ t.t.tyl [~ ~]
~
?~ peer
[~ ~]
``noun+!>(u.peer)
2020-07-03 01:51:54 +03:00
::
[%forward-lane ~]
2020-10-23 03:37:46 +03:00
::
:: this duplicates the routing hack from +send-blob:event-core
:: so long as neither the peer nor the peer's sponsoring galaxy is us:
::
:: - no route to the peer: send to the peer's sponsoring galaxy
:: - direct route to the peer: use that
:: - indirect route to the peer: send to both that route and the
:: the peer's sponsoring galaxy
2020-07-03 01:51:54 +03:00
::
:^ ~ ~ %noun
!> ^- (list lane)
2020-10-23 03:37:46 +03:00
?. ?& ?=([~ %known *] peer)
!=(our u.who)
==
2020-07-03 01:51:54 +03:00
~
2020-10-23 03:37:46 +03:00
=; zar=(trap (list lane))
?~ route.u.peer $:zar
=* rot u.route.u.peer
?:(direct.rot [lane.rot ~] [lane.rot $:zar])
::
|. ^- (list lane)
?: ?=(%czar (clan:title sponsor.u.peer))
?: =(our sponsor.u.peer)
~
[%& sponsor.u.peer]~
=/ next (~(get by peers.ames-state) sponsor.u.peer)
2020-07-03 01:51:54 +03:00
?. ?=([~ %known *] next)
~
2020-10-23 03:37:46 +03:00
$(peer next)
2020-07-03 01:51:54 +03:00
==
2020-01-11 01:41:49 +03:00
::
2020-06-25 21:20:57 +03:00
[%bones @ ~]
=/ who (slaw %p i.t.tyl)
2020-01-11 01:41:49 +03:00
?~ who [~ ~]
=/ per (~(get by peers.ames-state) u.who)
?. ?=([~ %known *] per) [~ ~]
=/ res
=, u.per
[snd=~(key by snd) rcv=~(key by rcv)]
``noun+!>(res)
::
2020-06-25 21:20:57 +03:00
[%snd-bones @ @ ~]
=/ who (slaw %p i.t.tyl)
2020-01-11 01:41:49 +03:00
?~ who [~ ~]
2020-06-25 21:20:57 +03:00
=/ ost (slaw %ud i.t.t.tyl)
2020-01-11 01:41:49 +03:00
?~ ost [~ ~]
=/ per (~(get by peers.ames-state) u.who)
?. ?=([~ %known *] per) [~ ~]
=/ mps (~(get by snd.u.per) u.ost)
?~ mps [~ ~]
=/ res
u.mps
``noun+!>(!>(res))
2022-01-27 16:32:49 +03:00
::
[%fine %message @ *]
:: t.t.tyl is expected to be a scry path of the shape /vc/desk/rev/etc,
:: so we need to give it the right shape
::
=/ pax=path
[i.t.t.tyl (scot %p our) t.t.t.tyl]
=/ fin
(fine now rof *duct ames-state)
``noun+!>((encode-response:fin pax (get-scry-result:fin lyc pax)))
2020-01-11 01:41:49 +03:00
==
2019-05-28 04:43:10 +03:00
--
2020-12-01 17:51:14 +03:00
:: |per-event: inner event-handling core
2019-05-28 04:43:10 +03:00
::
2022-01-27 16:32:49 +03:00
~% %per-event ..decode-packet ~
2019-05-25 05:03:33 +03:00
|%
2019-05-28 05:43:47 +03:00
++ per-event
=| moves=(list move)
2020-12-01 17:51:14 +03:00
~% %event-gate ..per-event ~
2020-12-06 13:55:19 +03:00
|= [[now=@da eny=@ rof=roof] =duct =ames-state]
2019-12-11 21:55:16 +03:00
=* veb veb.bug.ames-state
2020-12-01 17:51:14 +03:00
~% %event-core ..$ ~
2019-05-28 05:43:47 +03:00
|%
++ event-core .
++ abet [(flop moves) ames-state]
2019-05-28 06:15:17 +03:00
++ emit |=(=move event-core(moves [move moves]))
2019-12-11 21:55:16 +03:00
++ channel-state [life crypto-core bug]:ames-state
++ trace
|= [verb=? =ship print=(trap tape)]
^+ same
(^trace verb ship ships.bug.ames-state print)
2019-06-20 10:47:13 +03:00
:: +on-take-done: handle notice from vane that it processed a message
2019-05-28 05:43:47 +03:00
::
2019-06-20 10:47:13 +03:00
++ on-take-done
2019-06-19 02:59:25 +03:00
|= [=wire error=(unit error)]
2019-06-18 21:21:12 +03:00
^+ event-core
2019-08-10 00:20:16 +03:00
:: relay the vane ack to the foreign peer
2019-06-25 01:18:18 +03:00
::
2019-06-19 03:38:25 +03:00
=+ ^- [her=ship =bone] (parse-bone-wire wire)
::
2019-06-25 00:32:53 +03:00
=/ =peer-state (got-peer-state her)
2019-12-03 02:46:40 +03:00
=/ =channel [[our her] now channel-state -.peer-state]
2019-06-25 00:32:53 +03:00
=/ peer-core (make-peer-core peer-state channel)
2019-07-28 10:50:32 +03:00
:: if processing succeded, send positive ack packet and exit
2019-06-19 03:38:25 +03:00
::
2019-07-28 10:50:32 +03:00
?~ error
2019-10-30 23:12:57 +03:00
abet:(run-message-sink:peer-core bone %done ok=%.y)
2019-07-28 10:50:32 +03:00
:: failed; send message nack packet
2019-06-19 03:38:25 +03:00
::
2019-10-30 23:12:57 +03:00
=. event-core abet:(run-message-sink:peer-core bone %done ok=%.n)
2019-11-27 10:11:43 +03:00
=/ =^peer-state (got-peer-state her)
2019-12-03 02:46:40 +03:00
=/ =^channel [[our her] now channel-state -.peer-state]
2019-07-28 10:50:32 +03:00
:: construct nack-trace message, referencing .failed $message-num
::
=/ failed=message-num last-acked:(~(got by rcv.peer-state) bone)
2019-11-03 03:52:48 +03:00
=/ =naxplanation [failed u.error]
=/ =message-blob (jam naxplanation)
2019-07-28 10:50:32 +03:00
:: send nack-trace message on associated .nack-trace-bone
2019-06-19 03:38:25 +03:00
::
=. peer-core (make-peer-core peer-state channel)
=/ nack-trace-bone=^bone (mix 0b10 bone)
::
2019-07-29 09:37:49 +03:00
abet:(run-message-pump:peer-core nack-trace-bone %memo message-blob)
2019-12-11 21:55:16 +03:00
:: +on-sift: handle request to filter debug output by ship
::
++ on-sift
|= ships=(list ship)
^+ event-core
=. ships.bug.ames-state (sy ships)
event-core
:: +on-spew: handle request to set verbosity toggles on debug output
2019-12-03 02:46:40 +03:00
::
++ on-spew
|= verbs=(list verb)
^+ event-core
:: start from all %.n's, then flip requested toggles
::
2019-12-11 21:55:16 +03:00
=. veb.bug.ames-state
2019-12-03 02:46:40 +03:00
%+ roll verbs
|= [=verb acc=_veb-all-off]
2019-12-11 21:55:16 +03:00
^+ veb.bug.ames-state
2019-12-03 02:46:40 +03:00
?- verb
%snd acc(snd %.y)
%rcv acc(rcv %.y)
%odd acc(odd %.y)
%msg acc(msg %.y)
%ges acc(ges %.y)
%for acc(for %.y)
%rot acc(rot %.y)
==
event-core
2020-05-28 20:24:29 +03:00
:: +on-stir: start timers for any flow that lack them
::
:: .arg is unused, meant to ease future debug commands
::
++ on-stir
|= arg=@t
=/ states=(list [ship peer-state])
%+ murn ~(tap by peers.ames-state)
|= [=ship =ship-state]
^- (unit [^ship peer-state])
?. ?=(%known -.ship-state)
~
`[ship +.ship-state]
=/ snds=(list (list [ship bone message-pump-state]))
%+ turn states
|= [=ship peer-state]
%+ turn ~(tap by snd)
|= [=bone =message-pump-state]
[ship bone message-pump-state]
=/ next-wakes
%+ turn `(list [ship bone message-pump-state])`(zing snds)
|= [=ship =bone message-pump-state]
[ship bone next-wake.packet-pump-state]
=/ next-real-wakes=(list [=ship =bone =@da])
%+ murn next-wakes
|= [=ship =bone tym=(unit @da)]
^- (unit [^ship ^bone @da])
?~(tym ~ `[ship bone u.tym])
=/ timers
%- silt
;; (list [@da ^duct])
=< q.q %- need %- need
2020-12-06 13:55:19 +03:00
(rof ~ %b [[our %timers da+now] /])
2020-05-28 20:24:29 +03:00
=/ to-stir
%+ skip next-real-wakes
|= [=ship =bone =@da]
(~(has in timers) [da `^duct`~[a+(make-pump-timer-wire ship bone) /ames]])
~& [%stirring to-stir]
|- ^+ event-core
?~ to-stir
event-core
=/ =wire (make-pump-timer-wire [ship bone]:i.to-stir)
=. event-core (emit duct %pass wire %b %wait da.i.to-stir)
$(to-stir t.to-stir)
2019-08-08 07:57:04 +03:00
:: +on-crud: handle event failure; print to dill
::
++ on-crud
|= =error
^+ event-core
(emit duct %pass /crud %d %flog %crud error)
2019-11-04 04:35:45 +03:00
:: +on-heed: handle request to track .ship's responsiveness
::
++ on-heed
|= =ship
^+ event-core
=/ ship-state (~(get by peers.ames-state) ship)
?. ?=([~ %known *] ship-state)
%+ enqueue-alien-todo ship
|= todos=alien-agenda
todos(heeds (~(put in heeds.todos) duct))
::
=/ =peer-state +.u.ship-state
2019-12-03 02:46:40 +03:00
=/ =channel [[our ship] now channel-state -.peer-state]
2019-11-04 04:35:45 +03:00
abet:on-heed:(make-peer-core peer-state channel)
:: +on-jilt: handle request to stop tracking .ship's responsiveness
::
++ on-jilt
|= =ship
^+ event-core
=/ ship-state (~(get by peers.ames-state) ship)
?. ?=([~ %known *] ship-state)
%+ enqueue-alien-todo ship
|= todos=alien-agenda
todos(heeds (~(del in heeds.todos) duct))
::
=/ =peer-state +.u.ship-state
2019-12-03 02:46:40 +03:00
=/ =channel [[our ship] now channel-state -.peer-state]
2019-11-04 04:35:45 +03:00
abet:on-jilt:(make-peer-core peer-state channel)
2019-06-25 03:48:05 +03:00
:: +on-hear: handle raw packet receipt
2019-07-26 00:50:08 +03:00
::
2020-12-12 03:49:55 +03:00
++ on-hear
|= [l=lane b=blob d=(unit goof)]
2022-01-27 16:32:49 +03:00
=/ [ames=? =packet]
(decode-packet b)
?: ames
(on-hear-packet l packet d)
::
=^ moz ames-state
%- on-hear-response:(fine now rof duct ames-state)
~| [%fine %request-events-forbidden]
?> response==(& (cut 0 [2 1] b))
[l packet d]
=. moves (weld (flop moz) moves)
..on-hear
2019-06-25 03:48:05 +03:00
:: +on-hear-packet: handle mildly processed packet receipt
::
++ on-hear-packet
2020-12-01 17:51:14 +03:00
~/ %on-hear-packet
2020-12-12 03:49:55 +03:00
|= [=lane =packet dud=(unit goof)]
2019-06-25 03:48:05 +03:00
^+ event-core
::
2019-07-24 03:31:51 +03:00
?: =(our sndr.packet)
event-core
::
2019-07-28 10:50:32 +03:00
%. +<
2019-05-28 05:43:47 +03:00
::
?. =(our rcvr.packet)
on-hear-forward
::
2020-12-01 17:51:14 +03:00
?: ?& ?=(%pawn (clan:title sndr.packet))
2021-02-26 03:07:00 +03:00
!?=([~ %known *] (~(get by peers.ames-state) sndr.packet))
2020-12-01 17:51:14 +03:00
==
on-hear-open
on-hear-shut
2019-06-22 00:21:58 +03:00
:: +on-hear-forward: maybe forward a packet to someone else
2019-05-28 05:43:47 +03:00
::
2019-10-30 23:12:57 +03:00
:: Note that this performs all forwarding requests without
:: filtering. Any protection against DDoS amplification will be
:: provided by Vere.
2019-06-22 00:35:07 +03:00
::
2019-05-28 05:43:47 +03:00
++ on-hear-forward
2020-12-01 17:51:14 +03:00
~/ %on-hear-forward
2020-12-12 03:49:55 +03:00
|= [=lane =packet dud=(unit goof)]
2019-05-28 05:43:47 +03:00
^+ event-core
2019-12-11 21:55:16 +03:00
%- %^ trace for.veb sndr.packet
|.("forward: {<sndr.packet>} -> {<rcvr.packet>}")
2019-08-21 00:44:44 +03:00
:: set .origin.packet if it doesn't already have one, re-encode, and send
2019-05-28 05:43:47 +03:00
::
2020-12-01 17:51:14 +03:00
=? origin.packet
&(?=(~ origin.packet) !=(%czar (clan:title sndr.packet)))
?: ?=(%& -.lane)
~
?. (lte (met 3 p.lane) 6)
~| ames-lane-size+p.lane !!
`p.lane
::
2022-01-27 16:32:49 +03:00
=/ =blob (encode-packet & packet)
2019-12-11 03:20:12 +03:00
(send-blob & rcvr.packet blob)
2019-06-18 02:23:32 +03:00
:: +on-hear-open: handle receipt of plaintext comet self-attestation
2019-05-28 05:43:47 +03:00
::
++ on-hear-open
2020-12-01 17:51:14 +03:00
~/ %on-hear-open
2020-12-12 03:49:55 +03:00
|= [=lane =packet dud=(unit goof)]
2019-05-28 05:43:47 +03:00
^+ event-core
2020-10-28 00:20:25 +03:00
:: assert the comet can't pretend to be a moon or other address
::
2020-10-28 00:28:07 +03:00
?> ?=(%pawn (clan:title sndr.packet))
2019-06-18 02:23:32 +03:00
:: if we already know .sndr, ignore duplicate attestation
2019-05-28 05:43:47 +03:00
::
2019-06-18 02:23:32 +03:00
=/ ship-state (~(get by peers.ames-state) sndr.packet)
?: ?=([~ %known *] ship-state)
event-core
::
2020-12-01 17:51:14 +03:00
=/ =open-packet (decode-open-packet packet our life.ames-state)
2019-06-18 02:23:32 +03:00
:: store comet as peer in our state
::
=. peers.ames-state
%+ ~(put by peers.ames-state) sndr.packet
^- ^ship-state
:- %known
2019-06-22 00:40:38 +03:00
=| =peer-state
2019-06-18 02:23:32 +03:00
=/ our-private-key sec:ex:crypto-core.ames-state
=/ =symmetric-key
(derive-symmetric-key public-key.open-packet our-private-key)
::
2019-06-22 00:40:38 +03:00
%_ peer-state
2019-12-01 09:37:04 +03:00
qos [%unborn now]
2019-06-18 02:23:32 +03:00
symmetric-key symmetric-key
2019-06-22 00:40:38 +03:00
life sndr-life.open-packet
public-key public-key.open-packet
2019-06-22 03:07:19 +03:00
sponsor (^sein:title sndr.packet)
2019-11-28 09:17:34 +03:00
route `[direct=%.n lane]
2019-06-18 02:23:32 +03:00
==
::
event-core
2019-06-22 00:35:07 +03:00
:: +on-hear-shut: handle receipt of encrypted packet
2019-05-28 05:43:47 +03:00
::
++ on-hear-shut
2020-12-01 17:51:14 +03:00
~/ %on-hear-shut
2020-12-12 03:49:55 +03:00
|= [=lane =packet dud=(unit goof)]
2019-05-28 05:43:47 +03:00
^+ event-core
=/ sndr-state (~(get by peers.ames-state) sndr.packet)
2021-02-26 03:29:29 +03:00
:: if we don't know them, ask jael for their keys and enqueue
2019-11-28 04:58:18 +03:00
::
2019-05-28 05:43:47 +03:00
?. ?=([~ %known *] sndr-state)
2019-10-30 23:12:57 +03:00
(enqueue-alien-todo sndr.packet |=(alien-agenda +<))
2019-11-22 05:17:43 +03:00
:: decrypt packet contents using symmetric-key.channel
2019-06-01 06:32:13 +03:00
::
:: If we know them, we have a $channel with them, which we've
:: populated with a .symmetric-key derived from our private key
:: and their public key using elliptic curve Diffie-Hellman.
2019-05-28 05:43:47 +03:00
::
2019-05-28 06:59:53 +03:00
=/ =peer-state +.u.sndr-state
2019-12-03 02:46:40 +03:00
=/ =channel [[our sndr.packet] now channel-state -.peer-state]
2019-11-22 16:42:19 +03:00
~| %ames-crash-on-packet-from^her.channel
2020-12-01 17:51:14 +03:00
=/ =shut-packet
(decode-shut-packet packet [symmetric-key her-life our-life]:channel)
2019-08-08 07:57:04 +03:00
:: non-galaxy: update route with heard lane or forwarded lane
2019-06-22 00:40:38 +03:00
::
2020-12-01 17:51:14 +03:00
=? route.peer-state !=(%czar (clan:title her.channel))
ames: fix lane discovery during some lane changes
We used to not accept new indirect lanes if we already have a direct
lane. This means that if Bob, with a publicly-accessible lane, changes
lanes (eg by restarting the process and getting a new port or changing
ip addresses), tries to talk to Alice, who is behind a NAT, then Bob
will try directly but fail (because Alice is behind a NAT), so he will
route the message through her galaxy. This is good -- the message gets
to Alice. However, Alice had a direct route to Bob's old lane, so she
will try to ack on that lane, which fails. She will not time out this
lane because she doesn't know that Bob isn't getting the acks (acks
don't have their own acks).
The solution is that if Alice receives an indirect lane for Bob when she
already has a direct lane, she shouldn't ignore it. If the lane is the
same as what she has, she shouldn't change anything (in particular, she
shouldn't mark it as indirect). But if it's a new lane, she should
discard her old direct lane and use the new indirect lane.
2020-07-25 06:41:48 +03:00
:: if new packet is direct, use that. otherwise, if the new new
:: and old lanes are indirect, use the new one. if the new lane
:: is indirect but the old lane is direct, then if the lanes are
:: identical, don't mark it indirect; if they're not identical,
:: use the new lane and mark it indirect.
::
:: if you mark lane as indirect because you got an indirect
:: packet even though you already had a direct identical lane,
:: then delayed forwarded packets will come later and reset to
:: indirect, so you're unlikely to get a stable direct route
:: (unless the forwarder goes offline for a while).
::
:: conversely, if you don't accept indirect routes with different
:: lanes, then if your lane is stale and they're trying to talk
:: to you, your acks will go to the stale lane, and you'll never
:: time it out unless you reach out to them. this manifests as
:: needing to |hi or dotpost to get a response when the other
:: ship has changed lanes.
2020-01-13 00:06:27 +03:00
::
ames: fix lane discovery during some lane changes
We used to not accept new indirect lanes if we already have a direct
lane. This means that if Bob, with a publicly-accessible lane, changes
lanes (eg by restarting the process and getting a new port or changing
ip addresses), tries to talk to Alice, who is behind a NAT, then Bob
will try directly but fail (because Alice is behind a NAT), so he will
route the message through her galaxy. This is good -- the message gets
to Alice. However, Alice had a direct route to Bob's old lane, so she
will try to ack on that lane, which fails. She will not time out this
lane because she doesn't know that Bob isn't getting the acks (acks
don't have their own acks).
The solution is that if Alice receives an indirect lane for Bob when she
already has a direct lane, she shouldn't ignore it. If the lane is the
same as what she has, she shouldn't change anything (in particular, she
shouldn't mark it as indirect). But if it's a new lane, she should
discard her old direct lane and use the new indirect lane.
2020-07-25 06:41:48 +03:00
?: ?=(~ origin.packet)
2019-08-16 12:26:03 +03:00
`[direct=%.y lane]
ames: fix lane discovery during some lane changes
We used to not accept new indirect lanes if we already have a direct
lane. This means that if Bob, with a publicly-accessible lane, changes
lanes (eg by restarting the process and getting a new port or changing
ip addresses), tries to talk to Alice, who is behind a NAT, then Bob
will try directly but fail (because Alice is behind a NAT), so he will
route the message through her galaxy. This is good -- the message gets
to Alice. However, Alice had a direct route to Bob's old lane, so she
will try to ack on that lane, which fails. She will not time out this
lane because she doesn't know that Bob isn't getting the acks (acks
don't have their own acks).
The solution is that if Alice receives an indirect lane for Bob when she
already has a direct lane, she shouldn't ignore it. If the lane is the
same as what she has, she shouldn't change anything (in particular, she
shouldn't mark it as indirect). But if it's a new lane, she should
discard her old direct lane and use the new indirect lane.
2020-07-25 06:41:48 +03:00
?: ?=([~ %& *] route.peer-state)
2020-12-01 17:51:14 +03:00
?: =(lane.u.route.peer-state |+u.origin.packet)
ames: fix lane discovery during some lane changes
We used to not accept new indirect lanes if we already have a direct
lane. This means that if Bob, with a publicly-accessible lane, changes
lanes (eg by restarting the process and getting a new port or changing
ip addresses), tries to talk to Alice, who is behind a NAT, then Bob
will try directly but fail (because Alice is behind a NAT), so he will
route the message through her galaxy. This is good -- the message gets
to Alice. However, Alice had a direct route to Bob's old lane, so she
will try to ack on that lane, which fails. She will not time out this
lane because she doesn't know that Bob isn't getting the acks (acks
don't have their own acks).
The solution is that if Alice receives an indirect lane for Bob when she
already has a direct lane, she shouldn't ignore it. If the lane is the
same as what she has, she shouldn't change anything (in particular, she
shouldn't mark it as indirect). But if it's a new lane, she should
discard her old direct lane and use the new indirect lane.
2020-07-25 06:41:48 +03:00
route.peer-state
2020-12-01 17:51:14 +03:00
`[direct=%.n |+u.origin.packet]
`[direct=%.n |+u.origin.packet]
2019-08-08 07:57:04 +03:00
:: perform peer-specific handling of packet
2019-05-29 01:05:59 +03:00
::
2019-06-10 19:23:33 +03:00
=/ peer-core (make-peer-core peer-state channel)
2020-12-12 03:49:55 +03:00
abet:(on-hear-shut-packet:peer-core lane shut-packet dud)
2019-07-28 10:50:32 +03:00
:: +on-take-boon: receive request to give message to peer
2019-06-19 02:51:06 +03:00
::
2019-07-28 10:50:32 +03:00
++ on-take-boon
|= [=wire payload=*]
2019-06-19 02:51:06 +03:00
^+ event-core
::
2019-06-21 00:46:31 +03:00
=+ ^- [her=ship =bone] (parse-bone-wire wire)
::
2019-06-25 00:32:53 +03:00
=/ =peer-state (got-peer-state her)
2019-12-03 02:46:40 +03:00
=/ =channel [[our her] now channel-state -.peer-state]
2019-06-19 02:51:06 +03:00
::
2019-11-27 07:52:43 +03:00
abet:(on-memo:(make-peer-core peer-state channel) bone payload %boon)
2019-07-28 10:50:32 +03:00
:: +on-plea: handle request to send message
2019-06-09 09:26:01 +03:00
::
2019-07-28 10:50:32 +03:00
++ on-plea
|= [=ship =plea]
2019-06-09 09:26:01 +03:00
^+ event-core
2019-08-08 07:57:04 +03:00
:: .plea is from local vane to foreign ship
2019-06-09 09:26:01 +03:00
::
2019-06-22 00:35:07 +03:00
=/ ship-state (~(get by peers.ames-state) ship)
2019-06-09 09:26:01 +03:00
::
2019-06-22 00:35:07 +03:00
?. ?=([~ %known *] ship-state)
2019-06-25 00:13:45 +03:00
%+ enqueue-alien-todo ship
2019-10-30 23:12:57 +03:00
|= todos=alien-agenda
todos(messages [[duct plea] messages.todos])
2019-06-09 09:26:01 +03:00
::
2019-06-22 00:35:07 +03:00
=/ =peer-state +.u.ship-state
2019-12-03 02:46:40 +03:00
=/ =channel [[our ship] now channel-state -.peer-state]
2019-06-09 09:26:01 +03:00
::
2019-08-05 23:58:53 +03:00
=^ =bone ossuary.peer-state (bind-duct ossuary.peer-state duct)
2019-12-11 21:55:16 +03:00
%- %^ trace msg.veb ship
2019-11-15 03:10:48 +03:00
|. ^- tape
=/ sndr [our our-life.channel]
=/ rcvr [ship her-life.channel]
2020-12-12 03:45:13 +03:00
"plea {<sndr^rcvr^bone=bone^vane.plea^path.plea>}"
2019-06-21 00:46:31 +03:00
::
2019-11-27 07:52:43 +03:00
abet:(on-memo:(make-peer-core peer-state channel) bone plea %plea)
2019-06-19 02:59:25 +03:00
:: +on-take-wake: receive wakeup or error notification from behn
::
++ on-take-wake
|= [=wire error=(unit tang)]
^+ event-core
::
2019-12-02 03:00:32 +03:00
=/ res=(unit [her=ship =bone]) (parse-pump-timer-wire wire)
?~ res
2019-12-03 10:13:48 +03:00
%- (slog leaf+"ames: got timer for strange wire: {<wire>}" ~)
2019-12-02 03:00:32 +03:00
event-core
2019-06-22 00:35:07 +03:00
::
2019-12-02 03:00:32 +03:00
=/ state=(unit peer-state) (get-peer-state her.u.res)
?~ state
2019-12-03 10:13:48 +03:00
%- (slog leaf+"ames: got timer for strange ship: {<her.u.res>}, ignoring" ~)
2019-12-02 03:00:32 +03:00
event-core
::
2019-12-03 02:46:40 +03:00
=/ =channel [[our her.u.res] now channel-state -.u.state]
2019-06-22 00:35:07 +03:00
::
2019-12-02 03:00:32 +03:00
abet:(on-wake:(make-peer-core u.state channel) bone.u.res error)
2019-06-22 01:25:18 +03:00
:: +on-init: first boot; subscribe to our info from jael
::
++ on-init
^+ event-core
::
2019-08-20 00:43:39 +03:00
=~ (emit duct %pass /turf %j %turf ~)
(emit duct %pass /private-keys %j %private-keys ~)
2019-06-25 00:48:53 +03:00
==
2019-06-25 02:52:22 +03:00
:: +on-priv: set our private key to jael's response
::
++ on-priv
2019-07-23 05:16:19 +03:00
|= [=life vein=(map life private-key)]
2019-06-25 02:52:22 +03:00
^+ event-core
::
2019-07-23 05:16:19 +03:00
=/ =private-key (~(got by vein) life)
2019-06-25 02:52:22 +03:00
=. life.ames-state life
=. crypto-core.ames-state (nol:nu:crub:crypto private-key)
2019-06-25 22:55:51 +03:00
:: recalculate each peer's symmetric key
::
=/ our-private-key sec:ex:crypto-core.ames-state
=. peers.ames-state
%- ~(run by peers.ames-state)
|= =ship-state
^+ ship-state
::
?. ?=(%known -.ship-state)
ship-state
::
=/ =peer-state +.ship-state
=. symmetric-key.peer-state
(derive-symmetric-key public-key.+.ship-state our-private-key)
::
[%known peer-state]
2019-06-25 02:52:22 +03:00
::
event-core
:: +on-publ: update pki data for peer or self
::
++ on-publ
2019-07-29 12:08:26 +03:00
|= [=wire =public-keys-result]
2019-06-25 02:52:22 +03:00
^+ event-core
::
|^ ^+ event-core
::
2019-07-29 12:08:26 +03:00
?- public-keys-result
[%diff @ %rift *]
2019-11-27 01:56:20 +03:00
event-core
2019-06-25 02:52:22 +03:00
::
2019-07-29 12:08:26 +03:00
[%diff @ %keys *]
(on-publ-rekey [who to.diff]:public-keys-result)
2019-06-25 02:52:22 +03:00
::
2019-07-29 12:08:26 +03:00
[%diff @ %spon *]
(on-publ-sponsor [who to.diff]:public-keys-result)
2019-06-25 02:52:22 +03:00
::
2019-10-30 23:12:57 +03:00
[%full *]
(on-publ-full points.public-keys-result)
2019-11-03 07:07:51 +03:00
::
[%breach *]
(on-publ-breach who.public-keys-result)
2019-06-25 02:52:22 +03:00
==
2019-06-25 02:56:27 +03:00
:: +on-publ-breach: handle continuity breach of .ship; wipe its state
::
2019-08-23 06:53:45 +03:00
:: Abandon all pretense of continuity and delete all messaging state
2019-06-25 02:56:27 +03:00
:: associated with .ship, including sent and unsent messages.
2019-12-21 09:56:51 +03:00
:: Also cancel all timers related to .ship.
2019-06-25 02:56:27 +03:00
::
2019-06-25 02:52:22 +03:00
++ on-publ-breach
2019-11-03 07:07:51 +03:00
|= =ship
2019-06-25 02:52:22 +03:00
^+ event-core
::
2019-08-23 05:51:51 +03:00
=/ ship-state (~(get by peers.ames-state) ship)
:: we shouldn't be hearing about ships we don't care about
::
?~ ship-state
2019-11-03 07:07:51 +03:00
~> %slog.0^leaf/"ames: breach unknown {<our^ship>}"
2019-08-23 05:51:51 +03:00
event-core
:: if an alien breached, this doesn't affect us
::
2019-08-23 06:53:45 +03:00
?: ?=([~ %alien *] ship-state)
2019-11-03 07:07:51 +03:00
~> %slog.0^leaf/"ames: breach alien {<our^ship>}"
2019-08-23 05:51:51 +03:00
event-core
2019-11-03 07:07:51 +03:00
~> %slog.0^leaf/"ames: breach peer {<our^ship>}"
2019-08-23 05:51:51 +03:00
:: a peer breached; drop messaging state
::
=/ =peer-state +.u.ship-state
2019-08-23 06:53:45 +03:00
=/ old-qos=qos qos.peer-state
2019-11-22 05:20:39 +03:00
:: cancel all timers related to .ship
::
2019-11-22 05:22:05 +03:00
=. event-core
2019-11-22 05:20:39 +03:00
%+ roll ~(tap by snd.peer-state)
2019-11-22 05:22:05 +03:00
|= [[=snd=bone =message-pump-state] core=_event-core]
2019-11-22 05:20:39 +03:00
^+ core
::
2019-11-22 05:23:34 +03:00
?~ next-wake=next-wake.packet-pump-state.message-pump-state
2019-11-22 05:20:39 +03:00
core
:: note: copies +on-pump-rest:message-pump
::
2019-11-22 05:24:34 +03:00
=/ wire (make-pump-timer-wire ship snd-bone)
=/ duct ~[/ames]
2019-11-22 05:20:39 +03:00
(emit:core duct %pass wire %b %rest u.next-wake)
2019-08-23 06:53:45 +03:00
:: reset all peer state other than pki data
::
=. +.peer-state +:*^peer-state
:: print change to quality of service, if any
::
=/ text=(unit tape) (qos-update-text ship old-qos qos.peer-state)
::
=? event-core ?=(^ text)
(emit duct %pass /qos %d %flog %text u.text)
:: reinitialize galaxy route if applicable
::
=? route.peer-state =(%czar (clan:title ship))
`[direct=%.y lane=[%& ship]]
::
2019-08-23 05:51:51 +03:00
=. peers.ames-state
2019-08-23 06:53:45 +03:00
(~(put by peers.ames-state) ship [%known peer-state])
2019-08-23 05:51:51 +03:00
::
2019-06-25 02:56:27 +03:00
event-core
2019-06-25 03:14:02 +03:00
:: +on-publ-rekey: handle new key for peer
::
:: TODO: assert .crypto-suite compatibility
2019-06-25 02:52:22 +03:00
::
++ on-publ-rekey
|= $: =ship
=life
crypto-suite=@ud
2019-07-23 05:16:19 +03:00
=public-key
2019-06-25 02:52:22 +03:00
==
^+ event-core
::
2019-08-14 03:56:56 +03:00
=/ ship-state (~(get by peers.ames-state) ship)
?. ?=([~ %known *] ship-state)
=| =point
=. life.point life
=. keys.point (my [life crypto-suite public-key]~)
2021-09-25 23:52:53 +03:00
=. sponsor.point `(^^sein:title rof our now ship)
2019-08-14 03:56:56 +03:00
::
(on-publ-full (my [ship point]~))
::
=/ =peer-state +.u.ship-state
::
=/ =private-key sec:ex:crypto-core.ames-state
=. symmetric-key.peer-state
(derive-symmetric-key public-key private-key)
::
=. life.peer-state life
=. public-key.peer-state public-key
::
=. peers.ames-state (~(put by peers.ames-state) ship %known peer-state)
event-core
2019-08-10 00:20:16 +03:00
:: +on-publ-sponsor: handle new or lost sponsor for peer
2019-06-25 03:30:43 +03:00
::
:: TODO: handle sponsor loss
2019-06-25 02:52:22 +03:00
::
++ on-publ-sponsor
|= [=ship sponsor=(unit ship)]
^+ event-core
::
2019-06-25 03:16:32 +03:00
?~ sponsor
2019-08-10 21:48:40 +03:00
~| %ames-lost-sponsor^our^ship !!
2019-06-25 03:16:32 +03:00
::
2019-08-10 00:20:16 +03:00
=/ =peer-state (got-peer-state ship)
2019-06-25 03:16:32 +03:00
=. sponsor.peer-state u.sponsor
::
=. peers.ames-state (~(put by peers.ames-state) ship %known peer-state)
event-core
2019-06-25 03:30:43 +03:00
:: +on-publ-full: handle new pki data for peer(s)
2019-06-25 02:52:22 +03:00
::
++ on-publ-full
|= points=(map ship point)
^+ event-core
::
2019-06-25 03:30:43 +03:00
=> .(points ~(tap by points))
|^ ^+ event-core
?~ points event-core
::
2019-08-06 03:00:04 +03:00
=+ ^- [=ship =point] i.points
2019-06-25 03:30:43 +03:00
::
2019-12-05 01:03:13 +03:00
?. (~(has by keys.point) life.point)
$(points t.points)
::
2019-08-14 03:56:56 +03:00
=/ old-ship-state (~(get by peers.ames-state) ship)
::
=. event-core (insert-peer-state ship point)
::
=? event-core ?=([~ %alien *] old-ship-state)
(meet-alien ship point +.u.old-ship-state)
2019-06-25 03:30:43 +03:00
::
$(points t.points)
::
++ meet-alien
2019-10-30 23:12:57 +03:00
|= [=ship =point todos=alien-agenda]
2019-06-25 03:30:43 +03:00
^+ event-core
2019-08-23 08:53:38 +03:00
:: if we're a comet, send self-attestation packet first
2019-06-26 21:45:07 +03:00
::
=? event-core =(%pawn (clan:title our))
2019-12-11 03:20:12 +03:00
(send-blob | ship (attestation-packet ship life.point))
2019-11-27 01:56:20 +03:00
:: save current duct
::
=/ original-duct duct
:: apply heeds
::
=. event-core
%+ roll ~(tap in heeds.todos)
|= [=^duct core=_event-core]
(on-heed:core(duct duct) ship)
2019-10-05 06:38:32 +03:00
:: apply outgoing messages, reversing for FIFO order
2019-06-25 03:48:05 +03:00
::
=. event-core
2019-10-30 23:12:57 +03:00
%+ reel messages.todos
2019-10-05 06:21:29 +03:00
|= [[=^duct =plea] core=_event-core]
(on-plea:core(duct duct) ship plea)
2019-06-26 21:45:07 +03:00
:: apply outgoing packet blobs
2019-06-25 03:48:05 +03:00
::
=. event-core
2019-10-30 23:12:57 +03:00
%+ roll ~(tap in packets.todos)
2019-10-05 06:21:29 +03:00
|= [=blob core=_event-core]
2019-12-11 03:20:12 +03:00
(send-blob:core | ship blob)
2022-01-29 01:09:50 +03:00
:: apply remote scry requests
::
=^ moz=(list move) ames-state
%+ roll ~(tap in keens.todos)
|= [=path moz=(list move) =_ames-state]
=^ mos ames-state
%. [ship path 1]
send-request:(fine now rof original-duct ames-state)
[(weld moz mos) ames-state]
=. moves (weld (flop moz) moves)
2019-06-25 03:48:05 +03:00
::
2019-11-27 01:56:20 +03:00
event-core(duct original-duct)
2019-06-25 03:30:43 +03:00
--
2019-06-25 03:48:05 +03:00
::
++ insert-peer-state
2019-08-14 03:56:56 +03:00
|= [=ship =point]
2019-06-25 03:48:05 +03:00
^+ event-core
::
2019-08-14 03:56:56 +03:00
=/ =peer-state (gut-peer-state ship)
=/ =public-key pass:(~(got by keys.point) life.point)
2019-06-25 03:48:05 +03:00
=/ =private-key sec:ex:crypto-core.ames-state
=/ =symmetric-key (derive-symmetric-key public-key private-key)
::
2019-12-01 09:37:04 +03:00
=. qos.peer-state [%unborn now]
2019-08-14 03:56:56 +03:00
=. life.peer-state life.point
2019-06-25 03:48:05 +03:00
=. public-key.peer-state public-key
=. symmetric-key.peer-state symmetric-key
2019-12-05 01:03:13 +03:00
=. sponsor.peer-state
?^ sponsor.point
u.sponsor.point
2021-09-25 23:52:53 +03:00
(^^sein:title rof our now ship)
2019-07-24 02:55:35 +03:00
:: automatically set galaxy route, since unix handles lookup
::
=? route.peer-state ?=(%czar (clan:title ship))
`[direct=%.y lane=[%& ship]]
2019-06-25 03:48:05 +03:00
::
=. peers.ames-state
(~(put by peers.ames-state) ship %known peer-state)
::
event-core
2019-06-25 02:52:22 +03:00
--
2019-06-22 01:17:09 +03:00
:: +on-take-turf: relay %turf move from jael to unix
::
++ on-take-turf
|= turfs=(list turf)
^+ event-core
::
(emit unix-duct.ames-state %give %turf turfs)
2019-06-22 01:26:26 +03:00
:: +on-born: handle unix process restart
2019-07-25 01:56:13 +03:00
::
2019-07-31 05:31:15 +03:00
++ on-born
^+ event-core
::
=. unix-duct.ames-state duct
::
=/ turfs
;; (list turf)
=< q.q %- need %- need
2020-12-06 13:55:19 +03:00
(rof ~ %j `beam`[[our %turf %da now] /])
2019-07-31 05:31:15 +03:00
::
(emit unix-duct.ames-state %give %turf turfs)
2020-05-21 10:45:08 +03:00
:: +on-trim: handle request to free memory
2019-06-22 01:19:24 +03:00
:: +on-vega: handle kernel reload
2020-05-20 10:29:54 +03:00
:: +on-trim: handle request to free memory
2019-06-22 01:19:24 +03:00
::
++ on-vega event-core
2022-01-27 16:32:49 +03:00
++ on-trim event-core ::TODO trim fine parts on high prio
2019-06-25 00:13:45 +03:00
:: +enqueue-alien-todo: helper to enqueue a pending request
::
2019-06-26 21:45:07 +03:00
:: Also requests key and life from Jael on first request.
:: On a comet, enqueues self-attestation packet on first request.
2019-06-25 00:13:45 +03:00
::
++ enqueue-alien-todo
2019-10-30 23:12:57 +03:00
|= [=ship mutate=$-(alien-agenda alien-agenda)]
2019-06-25 00:13:45 +03:00
^+ event-core
::
=/ ship-state (~(get by peers.ames-state) ship)
2019-10-30 23:12:57 +03:00
:: create a default $alien-agenda on first contact
2019-06-25 00:13:45 +03:00
::
2019-10-30 23:12:57 +03:00
=+ ^- [already-pending=? todos=alien-agenda]
2019-06-25 00:13:45 +03:00
?~ ship-state
2019-10-30 23:12:57 +03:00
[%.n *alien-agenda]
2019-06-25 00:13:45 +03:00
[%.y ?>(?=(%alien -.u.ship-state) +.u.ship-state)]
:: mutate .todos and apply to permanent state
::
=. todos (mutate todos)
=. peers.ames-state (~(put by peers.ames-state) ship %alien todos)
:: ask jael for .sndr life and keys on first contact
::
?: already-pending
event-core
2020-05-29 00:27:08 +03:00
:: NB: we specifically look for this wire in +public-keys-give in
:: Jael. if you change it here, you must change it there.
::
2019-08-20 00:43:39 +03:00
(emit duct %pass /public-keys %j %public-keys [n=ship ~ ~])
2019-06-22 03:07:19 +03:00
:: +send-blob: fire packet at .ship and maybe sponsors
::
2019-11-28 07:06:39 +03:00
:: Send to .ship and sponsors until we find a direct lane,
:: skipping .our in the sponsorship chain.
2019-08-16 12:26:03 +03:00
::
2019-06-22 03:07:19 +03:00
:: If we have no PKI data for a recipient, enqueue the packet and
:: request the information from Jael if we haven't already.
::
++ send-blob
2020-12-01 17:51:14 +03:00
~/ %send-blob
2019-12-11 03:20:12 +03:00
|= [for=? =ship =blob]
2019-06-22 03:07:19 +03:00
::
2019-12-12 04:59:21 +03:00
=/ final-ship ship
%- (trace rot.veb final-ship |.("send-blob: to {<ship>}"))
ames: don't overwrite lane if already direct
This is why basically all packets are going through the galaxies right
now. Most of the time, the flow right now is:
* talking to ~dopzod but don't know where it is, so ask ~zod to forward,
which it does
* ~dopzod responds both directly (on the origin lane) and through ~zod
* (if NAT, the direct response doesn't get back, but the one through
~zod does. Then you respond directly to ~dopzod because their lane
piggybacked on the response. ~dopzod responds both directly and
through ~zod, and the story picks up the same as if you weren't behind a
NAT)
* now you have a direct lane to ~dopzod, so all is well.
* now the duplicate response from ~dopzod through ~zod comes in (takes a
little longer because it's bouncing off ~zod), resetting your lane to
"provisional"
* since your lane is provisional, you send your next packet both
directly and through ~zod
* GOTO 2
This change says "if I already have a direct lane, don't overwrite it
with a provisional one". This way, the only way the direct lane can be
overwritten is if they stop responding on it (cleared on "not
responding; still trying").
I also added |- to +send-blob to make |ames-verb %rot less confusing.
2019-12-05 06:39:34 +03:00
|-
2019-08-16 12:26:03 +03:00
|^ ^+ event-core
::
=/ ship-state (~(get by peers.ames-state) ship)
::
?. ?=([~ %known *] ship-state)
%+ enqueue-alien-todo ship
2019-10-30 23:12:57 +03:00
|= todos=alien-agenda
todos(packets (~(put in packets.todos) blob))
2019-08-16 12:26:03 +03:00
::
=/ =peer-state +.u.ship-state
::
2019-12-17 09:57:11 +03:00
:: XX routing hack to mimic old ames.
::
:: Before removing this, consider: moons when their planet is
:: behind a NAT; a planet receiving initial acknowledgment
:: from a star; a planet talking to another planet under
:: another galaxy.
::
?: ?| =(our ship)
?& !=(final-ship ship)
!=(%czar (clan:title ship))
==
==
(try-next-sponsor sponsor.peer-state)
::
2019-11-28 07:06:39 +03:00
?: =(our ship)
2019-12-11 03:20:12 +03:00
:: if forwarding, don't send to sponsor to avoid loops
::
?: for
event-core
2019-11-28 07:06:39 +03:00
(try-next-sponsor sponsor.peer-state)
::
2019-08-16 12:26:03 +03:00
?~ route=route.peer-state
2019-12-12 04:59:21 +03:00
%- (trace rot.veb final-ship |.("no route to: {<ship>}"))
2019-08-16 12:26:03 +03:00
(try-next-sponsor sponsor.peer-state)
::
2019-12-12 04:59:21 +03:00
%- (trace rot.veb final-ship |.("trying route: {<ship>}"))
2019-08-16 12:26:03 +03:00
=. event-core
(emit unix-duct.ames-state %give %send lane.u.route blob)
::
?: direct.u.route
event-core
(try-next-sponsor sponsor.peer-state)
2019-06-22 03:07:19 +03:00
::
2019-08-16 12:26:03 +03:00
++ try-next-sponsor
|= sponsor=^ship
^+ event-core
::
?: =(ship sponsor)
2019-06-22 03:07:19 +03:00
event-core
2019-08-16 12:26:03 +03:00
^$(ship sponsor)
--
2019-07-30 04:03:40 +03:00
:: +attestation-packet: generate signed self-attestation for .her
::
:: Sent by a comet on first contact with a peer. Not acked.
::
++ attestation-packet
|= [her=ship =her=life]
^- blob
2022-01-27 16:32:49 +03:00
%+ encode-packet &
2020-12-01 17:51:14 +03:00
%- encode-open-packet
:_ crypto-core.ames-state
:* ^= public-key pub:ex:crypto-core.ames-state
^= sndr our
^= sndr-life life.ames-state
^= rcvr her
^= rcvr-life her-life
==
2019-12-02 03:00:32 +03:00
:: +get-peer-state: lookup .her state or ~
::
++ get-peer-state
|= her=ship
^- (unit peer-state)
::
=- ?.(?=([~ %known *] -) ~ `+.u)
(~(get by peers.ames-state) her)
2019-06-25 00:32:53 +03:00
:: +got-peer-state: lookup .her state or crash
::
++ got-peer-state
|= her=ship
^- peer-state
::
~| %freaky-alien^her
=- ?>(?=(%known -<) ->)
(~(got by peers.ames-state) her)
2019-08-14 03:56:56 +03:00
:: +gut-peer-state: lookup .her state or default
::
++ gut-peer-state
|= her=ship
^- peer-state
=/ ship-state (~(get by peers.ames-state) her)
?. ?=([~ %known *] ship-state)
*peer-state
+.u.ship-state
2019-06-09 09:26:01 +03:00
:: +make-peer-core: create nested |peer-core for per-peer processing
2019-06-05 07:36:10 +03:00
::
++ make-peer-core
|= [=peer-state =channel]
2019-12-11 21:55:16 +03:00
=* veb veb.bug.channel
2019-06-05 07:36:10 +03:00
|%
++ peer-core .
++ emit |=(move peer-core(event-core (^emit +<)))
++ abet
^+ event-core
::
=. peers.ames-state
(~(put by peers.ames-state) her.channel %known peer-state)
::
event-core
2019-12-11 21:55:16 +03:00
++ trace
|= [verb=? print=(trap tape)]
^+ same
(^trace verb her.channel print)
2019-11-04 04:35:45 +03:00
++ on-heed peer-core(heeds.peer-state (~(put in heeds.peer-state) duct))
++ on-jilt peer-core(heeds.peer-state (~(del in heeds.peer-state) duct))
2019-08-08 07:57:04 +03:00
:: +update-qos: update and maybe print connection status
::
++ update-qos
|= =new=qos
^+ peer-core
::
=^ old-qos qos.peer-state [qos.peer-state new-qos]
2019-11-04 04:35:45 +03:00
:: if no update worth reporting, we're done
2019-08-08 07:57:04 +03:00
::
?~ text=(qos-update-text her.channel old-qos new-qos)
peer-core
2019-11-04 04:35:45 +03:00
:: print message
::
=. peer-core (emit duct %pass /qos %d %flog %text u.text)
2019-11-27 07:52:43 +03:00
:: if peer has stopped responding, check if %boon's are backing up
2019-11-04 04:35:45 +03:00
::
?. ?=(?(%dead %unborn) -.qos.peer-state)
peer-core
2019-11-27 07:52:43 +03:00
check-clog
:: +check-clog: notify clients if peer has stopped responding
::
++ check-clog
^+ peer-core
2019-11-04 04:35:45 +03:00
::
2019-11-22 16:43:08 +03:00
:: Only look at response bones. Request bones are unregulated,
:: since requests tend to be much smaller than responses.
::
=/ pumps=(list message-pump-state)
%+ murn ~(tap by snd.peer-state)
|= [=bone =message-pump-state]
2020-12-04 01:25:31 +03:00
?: =(0 (end 0 bone))
2019-11-22 16:43:08 +03:00
~
`u=message-pump-state
:: clogged: are five or more response messages unsent to this peer?
::
=/ clogged=?
=| acc=@ud
|- ^- ?
?~ pumps
%.n
2019-11-28 02:58:38 +03:00
=. acc
%+ add acc
%+ add
:: in-flight messages
::
(sub [next current]:i.pumps)
:: queued messages
::
~(wyt in unsent-messages.i.pumps)
::
2019-11-22 16:43:08 +03:00
?: (gte acc 5)
%.y
$(pumps t.pumps)
:: if clogged, notify client vanek
::
?. clogged
peer-core
2019-11-04 04:35:45 +03:00
%+ roll ~(tap in heeds.peer-state)
|=([d=^duct core=_peer-core] (emit:core d %give %clog her.channel))
2019-06-10 19:23:33 +03:00
:: +on-hear-shut-packet: handle receipt of ack or message fragment
2019-06-05 07:36:10 +03:00
::
2019-06-10 19:23:33 +03:00
++ on-hear-shut-packet
2020-12-12 03:49:55 +03:00
|= [=lane =shut-packet dud=(unit goof)]
2019-06-05 07:36:10 +03:00
^+ peer-core
2019-08-08 07:57:04 +03:00
:: update and print connection status
::
2019-08-08 08:18:25 +03:00
=. peer-core (update-qos %live last-contact=now)
2019-06-05 07:36:10 +03:00
::
2019-06-11 23:22:24 +03:00
=/ =bone bone.shut-packet
2019-06-05 07:36:10 +03:00
::
2019-06-10 19:13:11 +03:00
?: ?=(%& -.meat.shut-packet)
2021-03-19 03:04:08 +03:00
=+ ?. &(?=(^ dud) msg.veb) ~
2021-02-19 05:47:02 +03:00
%. ~
2021-03-19 03:04:08 +03:00
%- slog
:_ tang.u.dud
leaf+"ames: {<her.channel>} fragment crashed {<mote.u.dud>}"
2020-12-12 03:49:55 +03:00
(run-message-sink bone %hear lane shut-packet ?=(~ dud))
:: Just try again on error, printing trace
2019-08-06 02:05:40 +03:00
::
2019-12-10 11:21:03 +03:00
:: Note this implies that vanes should never crash on %done,
:: since we have no way to continue using the flow if they do.
::
2020-12-12 03:49:55 +03:00
=+ ?~ dud ~
%. ~
2021-02-19 19:54:34 +03:00
%+ slog leaf+"ames: {<her.channel>} ack crashed {<mote.u.dud>}"
2021-02-27 07:53:27 +03:00
?. msg.veb ~
:- >[bone=bone message-num=message-num meat=meat]:shut-packet<
tang.u.dud
2019-06-20 10:21:37 +03:00
(run-message-pump bone %hear [message-num +.meat]:shut-packet)
2019-06-20 11:18:07 +03:00
:: +on-memo: handle request to send message
::
++ on-memo
2019-11-27 07:52:43 +03:00
|= [=bone payload=* valence=?(%plea %boon)]
2019-06-20 11:18:07 +03:00
^+ peer-core
2021-01-20 23:29:45 +03:00
=/ =message-blob (dedup-message (jim payload))
2019-11-27 07:52:43 +03:00
=. peer-core (run-message-pump bone %memo message-blob)
::
2021-05-04 00:33:56 +03:00
?: ?& =(%boon valence)
(gte now (add ~s30 last-contact.qos.peer-state))
==
2019-11-27 07:52:43 +03:00
check-clog
peer-core
2020-05-02 08:55:14 +03:00
:: +dedup-message: replace with any existing copy of this message
::
++ dedup-message
|= =message-blob
^+ message-blob
2020-05-05 07:18:26 +03:00
?: (lte (met 13 message-blob) 1)
message-blob
2020-05-02 08:55:14 +03:00
=/ peers-l=(list [=ship =ship-state]) ~(tap by peers.ames-state)
|- ^+ message-blob
=* peer-loop $
?~ peers-l
message-blob
?. ?=(%known -.ship-state.i.peers-l)
peer-loop(peers-l t.peers-l)
=/ snd-l=(list [=bone =message-pump-state])
~(tap by snd.ship-state.i.peers-l)
|- ^+ message-blob
=* bone-loop $
?~ snd-l
peer-loop(peers-l t.peers-l)
=/ blob-l=(list ^message-blob)
~(tap to unsent-messages.message-pump-state.i.snd-l)
|- ^+ message-blob
=* blob-loop $
2020-05-02 13:33:28 +03:00
?^ blob-l
?: =(i.blob-l message-blob)
i.blob-l
blob-loop(blob-l t.blob-l)
?~ unsent-fragments.message-pump-state.i.snd-l
2020-05-02 08:55:14 +03:00
bone-loop(snd-l t.snd-l)
2020-05-02 13:33:28 +03:00
?: =(message-blob fragment.i.unsent-fragments.message-pump-state.i.snd-l)
`@`fragment.i.unsent-fragments.message-pump-state.i.snd-l
bone-loop(snd-l t.snd-l)
2019-06-22 00:35:07 +03:00
:: +on-wake: handle timer expiration
::
++ on-wake
|= [=bone error=(unit tang)]
^+ peer-core
2019-11-22 03:52:57 +03:00
:: if we previously errored out, print and reset timer for later
2019-06-22 00:35:07 +03:00
::
2019-11-22 03:52:57 +03:00
:: This really shouldn't happen, but if it does, make sure we
:: don't brick either this messaging flow or Behn.
::
?^ error
=. peer-core
(emit duct %pass /wake-fail %d %flog %crud %ames-wake u.error)
::
2019-11-22 05:13:09 +03:00
?~ message-pump-state=(~(get by snd.peer-state) bone)
peer-core
?~ next-wake.packet-pump-state.u.message-pump-state
peer-core
2020-05-28 03:38:18 +03:00
:: If we crashed because we woke up too early, assume another
:: timer is already set.
::
?: (lth now.channel u.next-wake.packet-pump-state.u.message-pump-state)
peer-core
2019-11-22 05:13:09 +03:00
::
2019-11-22 03:52:57 +03:00
=/ =wire (make-pump-timer-wire her.channel bone)
2019-11-22 04:41:17 +03:00
(emit duct %pass wire %b %wait (add now.channel ~s30))
2019-08-08 07:57:04 +03:00
:: update and print connection state
::
=. peer-core %- update-qos
2019-12-01 09:37:04 +03:00
=/ expiry=@da (add ~s30 last-contact.qos.peer-state)
=? -.qos.peer-state
(gte now.channel expiry)
%dead
qos.peer-state
2019-06-25 00:09:42 +03:00
:: expire direct route
::
2019-12-01 09:37:04 +03:00
:: If the peer is not responding, mark the .lane.route as
2019-06-25 00:09:42 +03:00
:: indirect. The next packets we emit will be sent to the
:: receiver's sponsorship chain in case the receiver's
:: transport address has changed and this lane is no longer
:: valid.
::
2019-07-30 04:03:40 +03:00
:: If .her is a galaxy, the lane will always remain direct.
::
2019-07-24 02:20:21 +03:00
=? route.peer-state
2019-12-01 09:37:04 +03:00
?& ?=(%dead -.qos.peer-state)
?=(^ route.peer-state)
2019-07-24 02:55:35 +03:00
direct.u.route.peer-state
!=(%czar (clan:title her.channel))
==
2019-07-24 02:20:21 +03:00
route.peer-state(direct.u %.n)
2019-07-30 04:03:40 +03:00
:: resend comet attestation packet if first message times out
::
:: The attestation packet doesn't get acked, so if we tried to
:: send a packet but it timed out, maybe they didn't get our
:: attestation.
::
:: Only resend on timeout of packets in the first message we
:: send them, since they should remember forever.
::
=? event-core
?& ?=(%pawn (clan:title our))
=(1 current:(~(got by snd.peer-state) bone))
==
2019-12-11 03:20:12 +03:00
(send-blob | her.channel (attestation-packet [her her-life]:channel))
2019-07-30 04:03:40 +03:00
:: maybe resend some timed out packets
2019-06-25 00:09:42 +03:00
::
2019-06-22 00:35:07 +03:00
(run-message-pump bone %wake ~)
2019-07-28 10:50:32 +03:00
:: +send-shut-packet: fire encrypted packet at rcvr and maybe sponsors
::
++ send-shut-packet
|= =shut-packet
^+ peer-core
2019-12-21 09:56:51 +03:00
:: swizzle last bone bit before sending
::
:: The peer has the opposite perspective from ours about what
:: kind of flow this is (forward/backward), so flip the bit
:: here.
2019-07-28 10:50:32 +03:00
::
2020-12-01 17:51:14 +03:00
=. event-core
%^ send-blob | her.channel
2022-01-27 16:32:49 +03:00
%+ encode-packet &
2020-12-01 17:51:14 +03:00
%: encode-shut-packet
shut-packet(bone (mix 1 bone.shut-packet))
symmetric-key.channel
our her.channel
our-life.channel her-life.channel
==
2019-07-28 10:50:32 +03:00
peer-core
2019-08-05 23:58:53 +03:00
:: +got-duct: look up $duct by .bone, asserting already bound
::
++ got-duct
|= =bone
^- ^duct
~| %dangling-bone^her.channel^bone
(~(got by by-bone.ossuary.peer-state) bone)
2019-06-10 19:13:11 +03:00
:: +run-message-pump: process $message-pump-task and its effects
2019-06-09 09:26:01 +03:00
::
++ run-message-pump
|= [=bone task=message-pump-task]
^+ peer-core
:: pass .task to the |message-pump and apply state mutations
::
=/ =message-pump-state
2019-06-30 15:50:00 +03:00
(~(gut by snd.peer-state) bone *message-pump-state)
2019-06-05 07:36:10 +03:00
::
2019-06-09 09:26:01 +03:00
=/ message-pump (make-message-pump message-pump-state channel)
=^ pump-gifts message-pump-state (work:message-pump task)
=. snd.peer-state (~(put by snd.peer-state) bone message-pump-state)
2019-06-05 07:36:10 +03:00
:: process effects from |message-pump
::
2019-06-09 09:26:01 +03:00
|^ ^+ peer-core
?~ pump-gifts peer-core
=* gift i.pump-gifts
=. peer-core
?- -.gift
2019-12-03 00:20:37 +03:00
%done (on-pump-done [message-num error]:gift)
2019-06-20 11:13:54 +03:00
%send (on-pump-send static-fragment.gift)
%wait (on-pump-wait date.gift)
%rest (on-pump-rest date.gift)
2019-06-09 09:26:01 +03:00
==
$(pump-gifts t.pump-gifts)
2019-06-20 11:13:54 +03:00
:: +on-pump-done: handle |message-pump's report of message (n)ack
2019-06-05 07:36:10 +03:00
::
2019-06-20 11:13:54 +03:00
++ on-pump-done
2019-12-03 00:20:37 +03:00
|= [=message-num error=(unit error)]
2019-06-09 09:26:01 +03:00
^+ peer-core
2019-06-20 03:48:29 +03:00
:: if odd bone, ack is on "subscription update" message; no-op
2019-06-19 03:52:10 +03:00
::
2020-12-04 01:25:31 +03:00
?: =(1 (end 0 bone))
2019-06-19 03:52:10 +03:00
peer-core
2019-06-20 03:48:29 +03:00
:: even bone; is this bone a nack-trace bone?
2019-06-19 03:38:25 +03:00
::
2020-12-04 01:25:31 +03:00
?: =(1 (end 0 (rsh 0 bone)))
2019-10-30 23:12:57 +03:00
:: nack-trace bone; assume .ok, clear nack from |message-sink
2019-06-19 03:52:10 +03:00
::
=/ target-bone=^bone (mix 0b10 bone)
::
2019-10-30 23:12:57 +03:00
(run-message-sink target-bone %drop message-num)
2019-12-03 00:20:37 +03:00
:: not a nack-trace bone; relay ack to client vane
2019-06-05 07:36:10 +03:00
::
2019-12-03 00:20:37 +03:00
(emit (got-duct bone) %give %done error)
2019-07-24 02:20:21 +03:00
:: +on-pump-send: emit message fragment requested by |message-pump
2019-06-09 09:26:01 +03:00
::
2019-06-20 11:13:54 +03:00
++ on-pump-send
2020-12-01 17:51:14 +03:00
|=(f=static-fragment (send-shut-packet bone [message-num %& +]:f))
2019-06-20 11:13:54 +03:00
:: +on-pump-wait: relay |message-pump's set-timer request
2019-06-09 09:26:01 +03:00
::
2019-06-20 11:13:54 +03:00
++ on-pump-wait
2019-06-09 09:26:01 +03:00
|= date=@da
^+ peer-core
::
2019-06-19 02:59:25 +03:00
=/ =wire (make-pump-timer-wire her.channel bone)
2019-09-27 14:45:22 +03:00
=/ duct ~[/ames]
2019-08-05 23:58:53 +03:00
(emit duct %pass wire %b %wait date)
2019-06-20 11:13:54 +03:00
:: +on-pump-rest: relay |message-pump's unset-timer request
2019-06-09 09:26:01 +03:00
::
2019-06-20 11:13:54 +03:00
++ on-pump-rest
2019-06-09 09:26:01 +03:00
|= date=@da
^+ peer-core
::
2019-06-19 02:59:25 +03:00
=/ =wire (make-pump-timer-wire her.channel bone)
2019-09-27 14:45:22 +03:00
=/ duct ~[/ames]
2019-08-05 23:58:53 +03:00
(emit duct %pass wire %b %rest date)
2019-06-09 09:26:01 +03:00
--
2019-10-30 23:12:57 +03:00
:: +run-message-sink: process $message-sink-task and its effects
2019-06-05 07:36:10 +03:00
::
2019-10-30 23:12:57 +03:00
++ run-message-sink
|= [=bone task=message-sink-task]
2019-06-05 07:36:10 +03:00
^+ peer-core
2019-10-30 23:12:57 +03:00
:: pass .task to the |message-sink and apply state mutations
2019-06-08 12:45:30 +03:00
::
2019-10-30 23:12:57 +03:00
=/ =message-sink-state
(~(gut by rcv.peer-state) bone *message-sink-state)
2019-06-08 12:45:30 +03:00
::
2019-10-30 23:12:57 +03:00
=/ message-sink (make-message-sink message-sink-state channel)
=^ sink-gifts message-sink-state (work:message-sink task)
=. rcv.peer-state (~(put by rcv.peer-state) bone message-sink-state)
:: process effects from |message-sink
2019-06-08 12:45:30 +03:00
::
2019-06-20 11:13:54 +03:00
|^ ^+ peer-core
2019-11-28 03:58:26 +03:00
?~ sink-gifts peer-core
2019-10-30 23:12:57 +03:00
=* gift i.sink-gifts
2019-06-20 11:13:54 +03:00
=. peer-core
?- -.gift
2019-10-30 23:12:57 +03:00
%memo (on-sink-memo [message-num message]:gift)
%send (on-sink-send [message-num ack-meat]:gift)
2019-06-20 11:13:54 +03:00
==
2019-10-30 23:12:57 +03:00
$(sink-gifts t.sink-gifts)
:: +on-sink-send: emit ack packet as requested by |message-sink
2019-06-05 07:36:10 +03:00
::
2019-10-30 23:12:57 +03:00
++ on-sink-send
2020-12-01 17:51:14 +03:00
|=([num=message-num ack=ack-meat] (send-shut-packet bone num %| ack))
2019-10-30 23:12:57 +03:00
:: +on-sink-memo: dispatch message received by |message-sink
2019-06-20 11:13:54 +03:00
::
2019-07-28 10:50:32 +03:00
:: odd bone: %plea request message
:: even bone, 0 second bit: %boon response message
:: even bone, 1 second bit: nack-trace %boon message
2019-06-20 11:13:54 +03:00
::
2019-10-30 23:12:57 +03:00
++ on-sink-memo
2020-12-04 01:25:31 +03:00
?: =(1 (end 0 bone))
2019-10-30 23:12:57 +03:00
on-sink-plea
2020-12-04 01:25:31 +03:00
?: =(0 (end 0 (rsh 0 bone)))
2019-10-30 23:12:57 +03:00
on-sink-boon
on-sink-nack-trace
:: +on-sink-boon: handle response message received by |message-sink
2019-07-28 10:50:32 +03:00
::
2019-08-05 23:58:53 +03:00
:: .bone must be mapped in .ossuary.peer-state, or we crash.
2019-12-21 09:56:51 +03:00
:: This means a malformed message will kill a flow. We
2019-08-05 23:58:53 +03:00
:: could change this to a no-op if we had some sort of security
:: reporting.
::
2019-12-03 01:49:10 +03:00
:: Note that if we had several consecutive packets in the queue
:: and crashed while processing any of them, the %hole card
:: will turn *all* of them into losts/nacks.
::
2019-08-28 06:12:56 +03:00
:: TODO: This handles a previous crash in the client vane, but not in
:: Ames itself.
::
2019-10-30 23:12:57 +03:00
++ on-sink-boon
2019-07-28 10:50:32 +03:00
|= [=message-num message=*]
2019-06-20 11:13:54 +03:00
^+ peer-core
2019-08-05 23:58:53 +03:00
:: send ack unconditionally
2019-06-20 11:13:54 +03:00
::
2019-12-18 06:20:32 +03:00
=. peer-core (emit (got-duct bone) %give %boon message)
2019-10-30 23:12:57 +03:00
=. peer-core (run-message-sink bone %done ok=%.y)
2019-06-20 11:13:54 +03:00
::
2019-08-28 06:12:56 +03:00
?. ?=([%hear * * ok=%.n] task)
:: fresh boon; give message to client vane
2019-06-25 01:18:18 +03:00
::
2021-02-19 05:47:02 +03:00
%- %+ trace msg.veb
=/ dat [her.channel bone=bone message-num=message-num -.task]
|.("sink boon {<dat>}")
2019-12-18 06:20:32 +03:00
peer-core
2019-08-28 06:12:56 +03:00
:: we previously crashed on this message; notify client vane
2019-06-20 11:13:54 +03:00
::
2020-12-12 03:45:13 +03:00
%- %+ trace msg.veb
2021-02-19 05:47:02 +03:00
=/ dat [her.channel bone=bone message-num=message-num -.task]
|.("crashed on sink boon {<dat>}")
2019-12-18 06:20:32 +03:00
boon-to-lost
:: +boon-to-lost: convert all boons to losts
::
++ boon-to-lost
^+ peer-core
=. moves
%+ turn moves
|= =move
?. ?=([* %give %boon *] move)
move
[duct.move %give %lost ~]
peer-core
2019-10-30 23:12:57 +03:00
:: +on-sink-nack-trace: handle nack-trace received by |message-sink
2019-07-28 10:50:32 +03:00
::
2019-10-30 23:12:57 +03:00
++ on-sink-nack-trace
2019-07-28 10:50:32 +03:00
|= [=message-num message=*]
^+ peer-core
2021-02-19 05:47:02 +03:00
%- %+ trace msg.veb
=/ dat [her.channel bone=bone message-num=message-num]
|.("sink naxplanation {<dat>}")
2019-06-20 11:13:54 +03:00
::
2019-11-03 03:52:48 +03:00
=+ ;; =naxplanation message
2019-08-05 23:58:53 +03:00
:: ack nack-trace message (only applied if we don't later crash)
2019-06-20 11:13:54 +03:00
::
2019-10-30 23:12:57 +03:00
=. peer-core (run-message-sink bone %done ok=%.y)
2019-06-20 11:13:54 +03:00
:: flip .bone's second bit to find referenced flow
::
=/ target-bone=^bone (mix 0b10 bone)
2019-12-02 23:20:57 +03:00
:: notify |message-pump that this message got naxplained
2019-06-20 11:13:54 +03:00
::
2019-12-02 23:20:57 +03:00
(run-message-pump target-bone %near naxplanation)
2019-10-30 23:12:57 +03:00
:: +on-sink-plea: handle request message received by |message-sink
2019-06-09 09:40:30 +03:00
::
2019-10-30 23:12:57 +03:00
++ on-sink-plea
2019-07-28 10:50:32 +03:00
|= [=message-num message=*]
^+ peer-core
2021-02-19 05:47:02 +03:00
%- %+ trace msg.veb
=/ dat [her.channel bone=bone message-num=message-num]
|.("sink plea {<dat>}")
2019-08-06 02:05:40 +03:00
:: is this the first time we're trying to process this message?
2019-07-28 10:50:32 +03:00
::
2019-08-06 02:05:40 +03:00
?. ?=([%hear * * ok=%.n] task)
:: fresh plea; pass to client vane
::
2019-08-08 07:57:04 +03:00
=+ ;; =plea message
::
=/ =wire (make-bone-wire her.channel bone)
::
?+ vane.plea ~| %ames-evil-vane^our^her.channel^vane.plea !!
%a (emit duct %pass wire %a %plea her.channel plea)
2019-08-06 02:05:40 +03:00
%c (emit duct %pass wire %c %plea her.channel plea)
%g (emit duct %pass wire %g %plea her.channel plea)
2019-08-20 00:43:39 +03:00
%j (emit duct %pass wire %j %plea her.channel plea)
2019-08-06 02:05:40 +03:00
==
:: we previously crashed on this message; send nack
::
2019-10-30 23:12:57 +03:00
=. peer-core (run-message-sink bone %done ok=%.n)
2019-11-03 03:52:48 +03:00
:: also send nack-trace with blank .error for security
2019-08-06 02:05:40 +03:00
::
=/ nack-trace-bone=^bone (mix 0b10 bone)
2019-11-03 03:52:48 +03:00
=/ =naxplanation [message-num *error]
=/ =message-blob (jam naxplanation)
2019-08-06 02:05:40 +03:00
::
(run-message-pump nack-trace-bone %memo message-blob)
2019-07-28 10:50:32 +03:00
--
2019-06-05 07:36:10 +03:00
--
2019-05-28 05:43:47 +03:00
--
2019-06-01 06:32:13 +03:00
:: +make-message-pump: constructor for |message-pump
2019-05-29 01:05:59 +03:00
::
++ make-message-pump
2019-06-02 01:16:41 +03:00
|= [state=message-pump-state =channel]
2019-12-11 21:55:16 +03:00
=* veb veb.bug.channel
2019-05-29 01:05:59 +03:00
=| gifts=(list message-pump-gift)
2019-05-29 05:56:05 +03:00
::
2019-05-29 01:05:59 +03:00
|%
2019-05-29 05:56:05 +03:00
++ message-pump .
++ give |=(gift=message-pump-gift message-pump(gifts [gift gifts]))
2019-06-19 02:33:53 +03:00
++ packet-pump (make-packet-pump packet-pump-state.state channel)
2019-12-11 21:55:16 +03:00
++ trace
|= [verb=? print=(trap tape)]
^+ same
(^trace verb her.channel ships.bug.channel print)
2019-05-29 05:56:05 +03:00
:: +work: handle a $message-pump-task
::
2019-05-29 01:05:59 +03:00
++ work
|= task=message-pump-task
2019-06-02 01:16:41 +03:00
^+ [gifts state]
2019-05-29 01:05:59 +03:00
::
2019-06-19 02:33:53 +03:00
=~ (dispatch-task task)
2019-05-29 05:56:05 +03:00
feed-packets
2019-06-20 10:21:37 +03:00
(run-packet-pump %halt ~)
2019-12-10 10:14:06 +03:00
assert
2019-06-02 01:16:41 +03:00
[(flop gifts) state]
2019-05-29 05:56:05 +03:00
==
2019-06-19 02:33:53 +03:00
:: +dispatch-task: perform task-specific processing
::
++ dispatch-task
|= task=message-pump-task
^+ message-pump
::
?- -.task
2019-07-28 10:50:32 +03:00
%memo (on-memo message-blob.task)
2019-12-10 10:14:06 +03:00
%wake (run-packet-pump %wake current.state)
2019-06-20 10:21:37 +03:00
%hear
2019-06-19 02:33:53 +03:00
?- -.ack-meat.task
2019-06-20 10:21:37 +03:00
%& (on-hear [message-num fragment-num=p.ack-meat]:task)
2019-12-02 23:20:57 +03:00
%| (on-done [message-num ?:(ok.p.ack-meat [%ok ~] [%nack ~])]:task)
==
%near (on-done [message-num %naxplanation error]:naxplanation.task)
==
2019-06-25 19:01:05 +03:00
:: +on-memo: handle request to send a message
2019-05-29 05:56:05 +03:00
::
2019-06-25 19:01:05 +03:00
++ on-memo
2019-07-28 10:50:32 +03:00
|= =message-blob
2019-05-29 05:56:05 +03:00
^+ message-pump
::
2019-07-28 10:50:32 +03:00
=. unsent-messages.state (~(put to unsent-messages.state) message-blob)
2019-05-29 05:56:05 +03:00
message-pump
2019-06-20 10:21:37 +03:00
:: +on-hear: handle packet acknowledgment
2019-06-02 01:16:41 +03:00
::
2019-06-20 10:21:37 +03:00
++ on-hear
2019-06-02 01:16:41 +03:00
|= [=message-num =fragment-num]
^+ message-pump
:: pass to |packet-pump unless duplicate or future ack
::
?. (is-message-num-in-range message-num)
2019-11-15 03:10:48 +03:00
%- (trace snd.veb |.("hear pump out of range"))
2019-06-02 01:16:41 +03:00
message-pump
2019-06-20 10:21:37 +03:00
(run-packet-pump %hear message-num fragment-num)
:: +on-done: handle message acknowledgment
2019-05-29 05:56:05 +03:00
::
2019-12-02 23:20:57 +03:00
:: A nack-trace message counts as a valid message nack on the
:: original failed message.
::
:: This prevents us from having to wait for a message nack packet,
:: which would mean we couldn't immediately ack the nack-trace
:: message, which would in turn violate the semantics of backward
:: flows.
::
2019-06-20 10:21:37 +03:00
++ on-done
2019-12-02 23:20:57 +03:00
|= [=message-num =ack]
2019-05-29 05:56:05 +03:00
^+ message-pump
2019-06-21 04:36:16 +03:00
:: unsent messages from the future should never get acked
::
?> (lth message-num next.state)
:: ignore duplicate message acks
::
?: (lth message-num current.state)
2020-12-12 03:45:13 +03:00
%- %+ trace snd.veb
|.("duplicate done {<current=current.state message-num=message-num>}")
2019-06-21 04:36:16 +03:00
message-pump
2019-06-02 01:16:41 +03:00
:: ignore duplicate and future acks
2019-05-29 05:56:05 +03:00
::
2019-06-02 01:16:41 +03:00
?. (is-message-num-in-range message-num)
2019-05-29 05:56:05 +03:00
message-pump
:: clear and print .unsent-fragments if nonempty
::
2019-06-02 01:16:41 +03:00
=? unsent-fragments.state
2019-06-09 09:31:42 +03:00
&(=(current next) ?=(^ unsent-fragments)):state
2019-06-02 01:16:41 +03:00
::
2019-12-03 00:20:37 +03:00
~> %slog.0^leaf/"ames: early message ack {<her.channel>}"
2019-05-29 05:56:05 +03:00
~
:: clear all packets from this message from the packet pump
::
2019-12-02 23:20:57 +03:00
=. message-pump (run-packet-pump %done message-num lag=*@dr)
2019-06-02 01:16:41 +03:00
:: enqueue this ack to be sent back to local client vane
2019-05-29 05:56:05 +03:00
::
2019-12-02 23:20:57 +03:00
:: Don't clobber a naxplanation with just a nack packet.
::
=? queued-message-acks.state
=/ old (~(get by queued-message-acks.state) message-num)
!?=([~ %naxplanation *] old)
(~(put by queued-message-acks.state) message-num ack)
2019-06-02 01:16:41 +03:00
:: emit local acks from .queued-message-acks until incomplete
2019-05-29 05:56:05 +03:00
::
|- ^+ message-pump
2019-06-02 01:16:41 +03:00
:: if .current hasn't been fully acked, we're done
2019-05-29 05:56:05 +03:00
::
2019-12-02 23:20:57 +03:00
?~ cur=(~(get by queued-message-acks.state) current.state)
2019-05-29 05:56:05 +03:00
message-pump
2019-06-02 01:16:41 +03:00
:: .current is complete; pop, emit local ack, and try next message
2019-05-29 05:56:05 +03:00
::
2019-06-02 01:16:41 +03:00
=. queued-message-acks.state
(~(del by queued-message-acks.state) current.state)
2020-12-12 03:43:13 +03:00
:: clear all packets from this message from the packet pump
::
:: Note we did this when the original packet came in, a few lines
:: above. It's not clear why, but it doesn't always clear the
:: packets when it's not the current message. As a workaround,
:: we clear the packets again when we catch up to this packet.
::
:: This is slightly inefficient because we run this twice for
:: each packet and it may emit a few unnecessary packets, but
:: but it's not incorrect. pump-metrics are updated only once,
:: at the time when we actually delete the packet.
::
=. message-pump (run-packet-pump %done current.state lag=*@dr)
2019-12-02 23:20:57 +03:00
:: give %done to vane if we're ready
::
?- -.u.cur
%ok
=. message-pump (give %done current.state ~)
$(current.state +(current.state))
2019-05-29 05:56:05 +03:00
::
2019-12-02 23:20:57 +03:00
%nack
message-pump
2019-05-29 05:56:05 +03:00
::
2019-12-02 23:20:57 +03:00
%naxplanation
=. message-pump (give %done current.state `error.u.cur)
$(current.state +(current.state))
==
2019-06-02 01:16:41 +03:00
:: +is-message-num-in-range: %.y unless duplicate or future ack
::
++ is-message-num-in-range
|= =message-num
^- ?
::
?: (gte message-num next.state)
%.n
?: (lth message-num current.state)
%.n
!(~(has by queued-message-acks.state) message-num)
2019-06-01 06:32:13 +03:00
:: +feed-packets: give packets to |packet-pump until full
2019-05-29 05:56:05 +03:00
::
++ feed-packets
:: if nothing to send, no-op
::
2019-06-02 01:16:41 +03:00
?: &(=(~ unsent-messages) =(~ unsent-fragments)):state
2019-05-29 05:56:05 +03:00
message-pump
:: we have unsent fragments of the current message; feed them
::
2019-06-02 01:16:41 +03:00
?. =(~ unsent-fragments.state)
=/ res (feed:packet-pump unsent-fragments.state)
=+ [unsent packet-pump-gifts packet-pump-state]=res
2019-05-29 05:56:05 +03:00
::
2019-06-02 01:16:41 +03:00
=. unsent-fragments.state unsent
=. packet-pump-state.state packet-pump-state
2019-05-29 05:56:05 +03:00
::
=. message-pump (process-packet-pump-gifts packet-pump-gifts)
:: if it sent all of them, feed it more; otherwise, we're done
::
?~ unsent
feed-packets
message-pump
:: .unsent-messages is nonempty; pop a message off and feed it
::
2019-07-28 10:50:32 +03:00
=^ =message-blob unsent-messages.state ~(get to unsent-messages.state)
2019-06-01 06:32:13 +03:00
:: break .message into .chunks and set as .unsent-fragments
2019-05-29 05:56:05 +03:00
::
2019-07-28 10:50:32 +03:00
=. unsent-fragments.state (split-message next.state message-blob)
2019-06-01 06:32:13 +03:00
:: try to feed packets from the next message
2019-05-29 05:56:05 +03:00
::
2019-06-02 01:16:41 +03:00
=. next.state +(next.state)
2019-05-29 05:56:05 +03:00
feed-packets
2019-06-01 06:32:13 +03:00
:: +run-packet-pump: call +work:packet-pump and process results
2019-05-29 05:56:05 +03:00
::
++ run-packet-pump
|= =packet-pump-task
^+ message-pump
::
2019-06-02 01:16:41 +03:00
=^ packet-pump-gifts packet-pump-state.state
2019-05-29 05:56:05 +03:00
(work:packet-pump packet-pump-task)
::
(process-packet-pump-gifts packet-pump-gifts)
2019-06-01 06:32:13 +03:00
:: +process-packet-pump-gifts: pass |packet-pump effects up the chain
2019-05-29 05:56:05 +03:00
::
++ process-packet-pump-gifts
|= packet-pump-gifts=(list packet-pump-gift)
^+ message-pump
::
?~ packet-pump-gifts
message-pump
=. message-pump (give i.packet-pump-gifts)
::
$(packet-pump-gifts t.packet-pump-gifts)
2019-12-10 10:14:06 +03:00
:: +assert: sanity checks to isolate error cases
::
++ assert
^+ message-pump
=/ top-live
2021-04-29 00:12:46 +03:00
(pry:packet-queue:*make-packet-pump live.packet-pump-state.state)
2020-01-11 01:41:49 +03:00
?. |(?=(~ top-live) (lte current.state message-num.key.u.top-live))
2019-12-10 10:14:06 +03:00
~| [%strange-current current=current.state key.u.top-live]
!!
message-pump
2019-05-29 05:56:05 +03:00
--
2019-06-01 06:32:13 +03:00
:: +make-packet-pump: construct |packet-pump core
2019-05-29 05:56:05 +03:00
::
++ make-packet-pump
2019-06-01 05:03:09 +03:00
|= [state=packet-pump-state =channel]
2019-12-11 21:55:16 +03:00
=* veb veb.bug.channel
2019-05-29 05:56:05 +03:00
=| gifts=(list packet-pump-gift)
|%
++ packet-pump .
2019-06-01 03:50:22 +03:00
++ give |=(packet-pump-gift packet-pump(gifts [+< gifts]))
2019-12-11 21:55:16 +03:00
++ trace
|= [verb=? print=(trap tape)]
^+ same
(^trace verb her.channel ships.bug.channel print)
2019-06-01 06:32:13 +03:00
:: +packet-queue: type for all sent fragments, ordered by sequence number
2019-06-01 01:35:06 +03:00
::
++ packet-queue
%- (ordered-map live-packet-key live-packet-val)
2019-11-27 21:22:20 +03:00
lte-packets
2019-06-01 01:35:06 +03:00
:: +gauge: inflate a |pump-gauge to track congestion control
::
2019-12-11 21:55:16 +03:00
++ gauge (make-pump-gauge now.channel metrics.state [her bug]:channel)
2019-06-01 01:35:06 +03:00
:: +work: handle $packet-pump-task request
::
2019-05-29 05:56:05 +03:00
++ work
|= task=packet-pump-task
2019-06-01 05:03:09 +03:00
^+ [gifts state]
2019-05-29 05:56:05 +03:00
::
2019-06-01 05:03:09 +03:00
=- [(flop gifts) state]
2019-05-29 01:05:59 +03:00
::
?- -.task
2019-06-20 10:21:37 +03:00
%hear (on-hear [message-num fragment-num]:task)
%done (on-done message-num.task)
2019-12-10 10:14:06 +03:00
%wake (on-wake current.task)
2019-06-20 10:21:37 +03:00
%halt set-wake
2019-05-29 01:05:59 +03:00
==
2019-09-27 14:45:22 +03:00
:: +on-wake: handle packet timeout
2019-05-29 01:05:59 +03:00
::
2019-09-27 14:45:22 +03:00
++ on-wake
2019-12-10 10:14:06 +03:00
|= current=message-num
2019-06-01 01:35:06 +03:00
^+ packet-pump
2019-09-27 14:45:22 +03:00
:: assert temporal coherence
2019-06-01 03:50:22 +03:00
::
2019-09-27 14:45:22 +03:00
?< =(~ next-wake.state)
?> (gte now.channel (need next-wake.state))
=. next-wake.state ~
:: tell congestion control a packet timed out
2019-06-02 01:16:41 +03:00
::
2019-10-02 10:46:34 +03:00
=. metrics.state on-timeout:gauge
2019-09-27 14:45:22 +03:00
:: re-send first packet and update its state in-place
2019-06-02 01:16:41 +03:00
::
2019-11-15 03:10:48 +03:00
=- =* res -
=. live.state live.res
2019-12-10 10:14:06 +03:00
=? packet-pump ?=(^ static-fragment)
%- %+ trace snd.veb
=/ nums [message-num fragment-num]:u.static-fragment.res
|.("dead {<nums^show:gauge>}")
(give %send u.static-fragment.res)
2019-09-27 14:45:22 +03:00
packet-pump
2019-06-01 03:50:22 +03:00
::
2019-12-10 10:14:06 +03:00
=| acc=(unit static-fragment)
2019-09-27 14:45:22 +03:00
^+ [static-fragment=acc live=live.state]
2019-06-01 03:50:22 +03:00
::
2021-04-20 23:04:28 +03:00
%^ (dip:packet-queue _acc) live.state acc
2019-06-02 01:16:41 +03:00
|= $: acc=_acc
2019-06-01 03:50:22 +03:00
key=live-packet-key
val=live-packet-val
==
2019-06-02 01:16:41 +03:00
^- [new-val=(unit live-packet-val) stop=? _acc]
2019-12-10 10:14:06 +03:00
:: if already acked later message, don't resend
::
?: (lth message-num.key current)
%- %- slog :_ ~
leaf+"ames: strange wake queue, expected {<current>}, got {<key>}"
[~ stop=%.n ~]
2019-09-27 14:45:22 +03:00
:: packet has expired; update it in-place, stop, and produce it
2019-06-01 03:50:22 +03:00
::
2019-09-27 14:45:22 +03:00
=. last-sent.val now.channel
=. retries.val +(retries.val)
2019-06-01 03:50:22 +03:00
::
2019-12-10 10:14:06 +03:00
[`val stop=%.y `(to-static-fragment key val)]
2019-06-02 01:16:41 +03:00
:: +feed: try to send a list of packets, returning unsent and effects
2019-06-01 01:35:06 +03:00
::
2019-06-02 01:16:41 +03:00
++ feed
2019-05-29 05:56:05 +03:00
|= fragments=(list static-fragment)
2019-06-01 05:03:09 +03:00
^+ [fragments gifts state]
2019-06-02 01:16:41 +03:00
:: return unsent back to caller and reverse effects to finalize
::
=- [unsent (flop gifts) state]
::
^+ [unsent=fragments packet-pump]
2019-06-01 06:05:21 +03:00
:: bite off as many fragments as we can send
::
=/ num-slots num-slots:gauge
=/ sent (scag num-slots fragments)
=/ unsent (slag num-slots fragments)
::
2019-06-02 01:16:41 +03:00
:- unsent
^+ packet-pump
:: if nothing to send, we're done
::
?~ sent packet-pump
:: convert $static-fragment's into +ordered-set [key val] pairs
::
=/ send-list
2019-06-01 06:05:21 +03:00
%+ turn sent
|= static-fragment
2019-06-02 01:16:41 +03:00
^- [key=live-packet-key val=live-packet-val]
2019-06-01 06:05:21 +03:00
::
:- [message-num fragment-num]
2019-10-02 09:21:05 +03:00
:- [sent-date=now.channel retries=0 skips=0]
2019-06-01 06:05:21 +03:00
[num-fragments fragment]
2019-06-02 01:16:41 +03:00
:: update .live and .metrics
2019-05-29 01:05:59 +03:00
::
2019-06-02 01:16:41 +03:00
=. live.state (gas:packet-queue live.state send-list)
=. metrics.state (on-sent:gauge (lent send-list))
:: TMI
2019-06-01 06:05:21 +03:00
::
2019-06-02 01:16:41 +03:00
=> .(sent `(list static-fragment)`sent)
:: emit a $packet-pump-gift for each packet to send
::
2019-10-05 06:21:29 +03:00
%+ roll sent
|= [packet=static-fragment core=_packet-pump]
(give:core %send packet)
2019-11-27 21:22:20 +03:00
:: +fast-resend-after-ack: resend timed out packets
::
:: After we finally receive an ack, we want to resend all the live
:: packets that have been building up.
::
++ fast-resend-after-ack
|= [=message-num =fragment-num]
^+ packet-pump
=; res=[resends=(list static-fragment) live=_live.state]
=. live.state live.res
%+ reel resends.res
|= [packet=static-fragment core=_packet-pump]
(give:core %send packet)
::
=/ acc
resends=*(list static-fragment)
::
2021-04-20 23:04:28 +03:00
%^ (dip:packet-queue _acc) live.state acc
2019-11-27 21:22:20 +03:00
|= $: acc=_acc
key=live-packet-key
val=live-packet-val
==
^- [new-val=(unit live-packet-val) stop=? _acc]
?: (lte-packets key [message-num fragment-num])
[new-val=`val stop=%.n acc]
::
?: (gth (next-expiry:gauge key val) now.channel)
[new-val=`val stop=%.y acc]
::
=. last-sent.val now.channel
=. resends.acc [(to-static-fragment key val) resends.acc]
[new-val=`val stop=%.n acc]
2019-06-20 10:21:37 +03:00
:: +on-hear: handle ack on a live packet
2019-05-29 01:05:59 +03:00
::
2019-09-27 14:45:22 +03:00
:: If the packet was in our queue, delete it and update our
2019-12-21 09:56:51 +03:00
:: metrics, possibly re-sending skipped packets. Otherwise, no-op.
2019-06-02 01:16:41 +03:00
::
2019-06-20 10:21:37 +03:00
++ on-hear
2019-06-01 01:35:06 +03:00
|= [=message-num =fragment-num]
^+ packet-pump
::
2019-06-02 01:16:41 +03:00
=- :: if no sent packet matches the ack, don't apply mutations or effects
::
?. found.-
2019-11-15 03:10:48 +03:00
%- (trace snd.veb |.("miss {<show:gauge>}"))
2019-06-02 01:16:41 +03:00
packet-pump
::
=. metrics.state metrics.-
2019-06-01 05:03:09 +03:00
=. live.state live.-
2019-12-03 02:46:40 +03:00
%- ?. ?| =(0 fragment-num)
=(0 (mod counter.metrics.state 20))
==
same
2020-12-12 03:45:13 +03:00
(trace snd.veb |.("send: {<[fragment=fragment-num show:gauge]>}"))
2019-10-05 06:21:29 +03:00
:: .resends is backward, so fold backward and emit
2019-06-02 01:16:41 +03:00
::
2019-11-27 21:22:20 +03:00
=. packet-pump
%+ reel resends.-
|= [packet=static-fragment core=_packet-pump]
(give:core %send packet)
(fast-resend-after-ack message-num fragment-num)
2019-10-05 06:21:29 +03:00
::
=/ acc
:* found=`?`%.n
resends=*(list static-fragment)
metrics=metrics.state
==
2019-06-01 01:35:06 +03:00
::
2019-10-05 06:21:29 +03:00
^+ [acc live=live.state]
2019-06-02 01:16:41 +03:00
::
2021-04-20 23:04:28 +03:00
%^ (dip:packet-queue _acc) live.state acc
2019-06-02 01:16:41 +03:00
|= $: acc=_acc
2019-06-01 01:35:06 +03:00
key=live-packet-key
val=live-packet-val
==
2019-06-02 01:16:41 +03:00
^- [new-val=(unit live-packet-val) stop=? _acc]
2019-06-01 01:35:06 +03:00
::
2019-12-11 21:55:16 +03:00
=/ gauge (make-pump-gauge now.channel metrics.acc [her bug]:channel)
2019-06-01 01:35:06 +03:00
:: is this the acked packet?
::
?: =(key [message-num fragment-num])
:: delete acked packet, update metrics, and stop traversal
::
2019-10-05 06:21:29 +03:00
=. found.acc %.y
=. metrics.acc (on-ack:gauge -.val)
[new-val=~ stop=%.y acc]
2019-12-02 11:25:30 +03:00
:: is this a duplicate ack?
::
?. (lte-packets key [message-num fragment-num])
:: stop, nothing more to do
::
[new-val=`val stop=%.y acc]
2019-10-05 06:21:29 +03:00
:: ack was on later packet; mark skipped, tell gauge, and continue
::
=. skips.val +(skips.val)
=^ resend metrics.acc (on-skipped-packet:gauge -.val)
?. resend
[new-val=`val stop=%.n acc]
2019-06-01 01:35:06 +03:00
::
2019-10-05 06:21:29 +03:00
=. last-sent.val now.channel
=. retries.val +(retries.val)
=. resends.acc [(to-static-fragment key val) resends.acc]
[new-val=`val stop=%.n acc]
2019-06-20 10:21:37 +03:00
:: +on-done: apply ack to all packets from .message-num
2019-05-29 01:05:59 +03:00
::
2019-06-20 10:21:37 +03:00
++ on-done
2019-05-29 05:56:05 +03:00
|= =message-num
^+ packet-pump
::
2019-06-02 01:16:41 +03:00
=- =. metrics.state metrics.-
=. live.state live.-
::
2020-12-12 03:45:13 +03:00
%- (trace snd.veb |.("done {<message-num=message-num^show:gauge>}"))
2019-11-27 21:22:20 +03:00
(fast-resend-after-ack message-num `fragment-num`0)
2019-05-29 01:05:59 +03:00
::
2019-10-05 06:21:29 +03:00
^+ [metrics=metrics.state live=live.state]
2019-06-02 01:16:41 +03:00
::
2021-04-20 23:04:28 +03:00
%^ (dip:packet-queue pump-metrics) live.state acc=metrics.state
2019-06-02 01:16:41 +03:00
|= $: metrics=pump-metrics
key=live-packet-key
val=live-packet-val
==
^- [new-val=(unit live-packet-val) stop=? pump-metrics]
::
2019-12-11 21:55:16 +03:00
=/ gauge (make-pump-gauge now.channel metrics [her bug]:channel)
2019-12-02 11:25:30 +03:00
:: if we get an out-of-order ack for a message, skip until it
2019-06-02 01:16:41 +03:00
::
?: (lth message-num.key message-num)
2019-12-02 11:25:30 +03:00
[new-val=`val stop=%.n metrics]
2019-06-02 01:16:41 +03:00
:: if packet was from acked message, delete it and continue
::
?: =(message-num.key message-num)
[new-val=~ stop=%.n metrics=(on-ack:gauge -.val)]
:: we've gone past the acked message; we're done
::
[new-val=`val stop=%.y metrics]
:: +set-wake: set, unset, or reset timer, emitting moves
2019-05-29 01:05:59 +03:00
::
2019-06-02 01:16:41 +03:00
++ set-wake
2019-05-29 05:56:05 +03:00
^+ packet-pump
2021-04-29 00:12:46 +03:00
:: if nonempty .live, pry at head to get next wake time
2019-05-29 01:05:59 +03:00
::
2019-06-02 01:16:41 +03:00
=/ new-wake=(unit @da)
2021-04-29 00:12:46 +03:00
?~ head=(pry:packet-queue live.state)
2019-06-02 01:16:41 +03:00
~
2019-11-27 21:22:20 +03:00
`(next-expiry:gauge u.head)
2019-06-02 01:16:41 +03:00
:: no-op if no change
::
?: =(new-wake next-wake.state) packet-pump
:: unset old timer if non-null
::
=? packet-pump !=(~ next-wake.state)
=/ old (need next-wake.state)
=. next-wake.state ~
(give %rest old)
:: set new timer if non-null
::
=? packet-pump ?=(^ new-wake)
=. next-wake.state new-wake
(give %wait u.new-wake)
::
packet-pump
2019-06-01 01:35:06 +03:00
--
2019-10-05 06:21:29 +03:00
:: +to-static-fragment: convenience function for |packet-pump
2019-06-01 01:35:06 +03:00
::
2019-10-05 06:21:29 +03:00
++ to-static-fragment
|= [live-packet-key live-packet-val]
^- static-fragment
[message-num num-fragments fragment-num fragment]
2019-06-01 03:50:22 +03:00
:: +make-pump-gauge: construct |pump-gauge congestion control core
2019-06-01 06:05:21 +03:00
::
2019-06-01 01:35:06 +03:00
++ make-pump-gauge
2019-12-11 21:55:16 +03:00
|= [now=@da pump-metrics =ship =bug]
=* veb veb.bug
2019-12-03 02:46:40 +03:00
=* metrics +<+<
2019-06-01 01:35:06 +03:00
|%
2019-12-11 21:55:16 +03:00
++ trace
|= [verb=? print=(trap tape)]
^+ same
(^trace verb ship ships.bug print)
2019-06-01 06:05:21 +03:00
:: +next-expiry: when should a newly sent fresh packet time out?
2019-06-01 03:50:22 +03:00
::
2019-09-27 14:45:22 +03:00
:: Use rtt + 4*sigma, where sigma is the mean deviation of rtt.
:: This should make it unlikely that a packet would time out from a
:: delay, as opposed to an actual packet loss.
2019-06-01 06:05:21 +03:00
::
2019-09-27 14:45:22 +03:00
++ next-expiry
2019-11-27 21:22:20 +03:00
|= [live-packet-key live-packet-val]
2019-06-01 06:05:21 +03:00
^- @da
2019-11-27 21:22:20 +03:00
(add last-sent rto)
2019-06-01 06:05:21 +03:00
:: +num-slots: how many packets can we send right now?
::
++ num-slots
^- @ud
2019-09-27 14:45:22 +03:00
(sub-safe cwnd num-live)
:: +on-sent: adjust metrics based on sending .num-sent fresh packets
2019-06-01 03:50:22 +03:00
::
2019-09-27 14:45:22 +03:00
++ on-sent
|= num-sent=@ud
2019-08-28 06:53:19 +03:00
^- pump-metrics
::
2019-09-27 14:45:22 +03:00
=. num-live (add num-live num-sent)
2019-06-01 05:03:09 +03:00
metrics
2019-06-01 03:50:22 +03:00
:: +on-ack: adjust metrics based on a packet getting acknowledged
::
2019-06-01 01:35:06 +03:00
++ on-ack
2019-09-27 14:45:22 +03:00
|= =packet-state
2019-06-01 05:03:09 +03:00
^- pump-metrics
2019-06-01 01:35:06 +03:00
::
2019-10-02 09:21:05 +03:00
=. counter +(counter)
2019-09-27 14:45:22 +03:00
=. num-live (dec num-live)
:: if below congestion threshold, add 1; else, add avg. 1 / cwnd
2019-08-29 03:28:31 +03:00
::
2019-09-27 14:45:22 +03:00
=. cwnd
?: in-slow-start
+(cwnd)
(add cwnd !=(0 (mod (mug now) cwnd)))
:: if this was a re-send, don't adjust rtt or downstream state
::
?. =(0 retries.packet-state)
metrics
:: rtt-datum: new rtt measurement based on this packet roundtrip
::
=/ rtt-datum=@dr (sub-safe now last-sent.packet-state)
:: rtt-error: difference between this rtt measurement and expected
::
=/ rtt-error=@dr
?: (gte rtt-datum rtt)
(sub rtt-datum rtt)
(sub rtt rtt-datum)
:: exponential weighting ratio for .rtt and .rttvar
::
2019-11-28 03:43:09 +03:00
%- %+ trace ges.veb
|.("ack update {<show rtt-datum=rtt-datum rtt-error=rtt-error>}")
2019-09-27 14:45:22 +03:00
=. rtt (div (add rtt-datum (mul rtt 7)) 8)
=. rttvar (div (add rtt-error (mul rttvar 7)) 8)
=. rto (clamp-rto (add rtt (mul 4 rttvar)))
::
metrics
2019-10-05 06:21:29 +03:00
:: +on-skipped-packet: handle misordered ack
2019-06-01 03:50:22 +03:00
::
2019-09-27 14:45:22 +03:00
++ on-skipped-packet
|= packet-state
2019-10-05 06:21:29 +03:00
^- [resend=? pump-metrics]
2019-06-01 06:05:21 +03:00
::
2019-10-05 06:21:29 +03:00
=/ resend=? &(=(0 retries) |(in-recovery (gte skips 3)))
:- resend
::
=? cwnd !in-recovery (max 2 (div cwnd 2))
2019-11-15 03:10:48 +03:00
%- %+ trace snd.veb
|.("skip {<[resend=resend in-recovery=in-recovery show]>}")
2019-09-27 14:45:22 +03:00
metrics
:: +on-timeout: (re)enter slow-start mode on packet loss
2019-06-01 06:05:21 +03:00
::
2019-09-27 14:45:22 +03:00
++ on-timeout
2019-06-01 05:03:09 +03:00
^- pump-metrics
2019-08-28 06:53:19 +03:00
::
2019-12-03 02:46:40 +03:00
%- (trace ges.veb |.("timeout update {<show>}"))
2019-10-02 09:21:05 +03:00
=: ssthresh (max 1 (div cwnd 2))
2019-09-27 14:45:22 +03:00
cwnd 1
rto (clamp-rto (mul rto 2))
==
2019-06-04 15:38:08 +03:00
metrics
2019-09-27 14:45:22 +03:00
:: +clamp-rto: apply min and max to an .rto value
::
++ clamp-rto
|= rto=@dr
^+ rto
2019-12-06 23:11:06 +03:00
(min ~m2 (max ^~((div ~s1 5)) rto))
2019-10-05 06:21:29 +03:00
:: +in-slow-start: %.y iff we're in "slow-start" mode
2019-09-27 14:45:22 +03:00
::
++ in-slow-start
^- ?
(lth cwnd ssthresh)
2019-10-05 06:21:29 +03:00
:: +in-recovery: %.y iff we're recovering from a skipped packet
::
:: We finish recovering when .num-live finally dips back down to
:: .cwnd.
::
++ in-recovery
^- ?
(gth num-live cwnd)
2019-09-27 14:45:22 +03:00
:: +sub-safe: subtract with underflow protection
::
++ sub-safe
|= [a=@ b=@]
^- @
?:((lte a b) 0 (sub a b))
2019-10-05 06:21:29 +03:00
:: +show: produce a printable version of .metrics
2019-10-02 09:21:05 +03:00
::
++ show
=/ ms (div ~s1 1.000)
::
:* rto=(div rto ms)
rtt=(div rtt ms)
rttvar=(div rttvar ms)
ssthresh=ssthresh
cwnd=cwnd
num-live=num-live
counter=counter
==
2019-05-29 01:05:59 +03:00
--
2019-10-30 23:12:57 +03:00
:: +make-message-sink: construct |message-sink message receiver core
2019-05-29 01:05:59 +03:00
::
2019-10-30 23:12:57 +03:00
++ make-message-sink
|= [state=message-sink-state =channel]
2019-12-11 21:55:16 +03:00
=* veb veb.bug.channel
2019-10-30 23:12:57 +03:00
=| gifts=(list message-sink-gift)
2019-05-29 01:05:59 +03:00
|%
2019-10-30 23:12:57 +03:00
++ message-sink .
++ give |=(message-sink-gift message-sink(gifts [+< gifts]))
2019-12-11 21:55:16 +03:00
++ trace
|= [verb=? print=(trap tape)]
^+ same
(^trace verb her.channel ships.bug.channel print)
:: +work: handle a $message-sink-task
::
2019-05-29 01:05:59 +03:00
++ work
2019-10-30 23:12:57 +03:00
|= task=message-sink-task
2019-06-09 20:32:15 +03:00
^+ [gifts state]
2019-05-29 01:05:59 +03:00
::
2019-06-09 20:32:15 +03:00
=- [(flop gifts) state]
2019-05-29 01:05:59 +03:00
::
?- -.task
2019-06-20 10:21:37 +03:00
%done (on-done ok.task)
%drop (on-drop message-num.task)
2019-08-06 02:05:40 +03:00
%hear (on-hear [lane shut-packet ok]:task)
2019-05-29 01:05:59 +03:00
==
2019-06-11 23:22:24 +03:00
:: +on-hear: receive message fragment, possibly completing message
2019-05-29 01:05:59 +03:00
::
++ on-hear
2019-08-06 02:05:40 +03:00
|= [=lane =shut-packet ok=?]
2019-10-30 23:12:57 +03:00
^+ message-sink
2019-06-09 20:32:15 +03:00
:: we know this is a fragment, not an ack; expose into namespace
2019-05-29 01:05:59 +03:00
::
2019-06-09 20:32:15 +03:00
?> ?=(%& -.meat.shut-packet)
=+ [num-fragments fragment-num fragment]=+.meat.shut-packet
:: seq: message sequence number, for convenience
::
=/ seq message-num.shut-packet
:: ignore messages from far future; limit to 10 in progress
::
?: (gte seq (add 10 last-acked.state))
2020-12-12 03:45:13 +03:00
%- %+ trace odd.veb
|.("future %hear {<seq=seq^last-acked=last-acked.state>}")
2019-10-30 23:12:57 +03:00
message-sink
2019-06-09 20:32:15 +03:00
::
=/ is-last-fragment=? =(+(fragment-num) num-fragments)
:: always ack a dupe!
::
?: (lte seq last-acked.state)
?. is-last-fragment
:: single packet ack
::
2020-12-12 03:45:13 +03:00
%- %+ trace rcv.veb
|.("send dupe ack {<seq=seq^fragment-num=fragment-num>}")
2019-06-20 10:21:37 +03:00
(give %send seq %& fragment-num)
2019-06-19 03:38:25 +03:00
:: whole message (n)ack
2019-06-09 20:32:15 +03:00
::
2019-08-21 00:44:44 +03:00
=/ ok=? !(~(has in nax.state) seq)
2020-12-12 03:45:13 +03:00
%- (trace rcv.veb |.("send dupe message ack {<seq=seq>} ok={<ok>}"))
2019-06-20 10:21:37 +03:00
(give %send seq %| ok lag=`@dr`0)
2019-06-09 20:32:15 +03:00
:: last-acked<seq<=last-heard; heard message, unprocessed
::
2019-11-27 21:22:20 +03:00
:: Only true if we've heard some packets we haven't acked, which
:: doesn't happen for boons.
::
2019-06-09 20:32:15 +03:00
?: (lte seq last-heard.state)
?: is-last-fragment
:: drop last packet since we don't know whether to ack or nack
::
2019-11-28 03:58:26 +03:00
%- %+ trace rcv.veb
|. ^- tape
=/ data
2020-12-12 03:45:13 +03:00
:* her.channel seq=seq
fragment-num=fragment-num num-fragments=num-fragments
2019-11-28 03:58:26 +03:00
la=last-acked.state lh=last-heard.state
==
"hear last in-progress {<data>}"
2019-10-30 23:12:57 +03:00
message-sink
2019-06-09 20:32:15 +03:00
:: ack all other packets
::
2020-12-12 03:45:13 +03:00
%- %+ trace rcv.veb |.
=/ data
[seq=seq fragment-num=fragment-num num-fragments=num-fragments]
"send ack-1 {<data>}"
2019-06-20 10:21:37 +03:00
(give %send seq %& fragment-num)
2019-06-09 20:32:15 +03:00
:: last-heard<seq<10+last-heard; this is a packet in a live message
::
=/ =partial-rcv-message
:: create default if first fragment
::
?~ existing=(~(get by live-messages.state) seq)
[num-fragments num-received=0 fragments=~]
:: we have an existing partial message; check parameters match
::
?> (gth num-fragments.u.existing fragment-num)
?> =(num-fragments.u.existing num-fragments)
::
u.existing
::
2019-08-01 06:14:28 +03:00
=/ already-heard-fragment=?
2019-07-29 12:08:26 +03:00
(~(has by fragments.partial-rcv-message) fragment-num)
2019-06-09 20:32:15 +03:00
:: ack dupes except for the last fragment, in which case drop
::
2019-08-01 06:14:28 +03:00
?: already-heard-fragment
2019-06-09 20:32:15 +03:00
?: is-last-fragment
2019-12-18 02:40:51 +03:00
%- %+ trace rcv.veb |.
2020-12-12 03:45:13 +03:00
=/ data
[her.channel seq=seq lh=last-heard.state la=last-acked.state]
2019-12-18 02:40:51 +03:00
"hear last dupe {<data>}"
2019-10-30 23:12:57 +03:00
message-sink
2020-12-12 03:45:13 +03:00
%- %+ trace rcv.veb
|.("send dupe ack {<her.channel^seq=seq^fragment-num=fragment-num>}")
2019-06-20 10:21:37 +03:00
(give %send seq %& fragment-num)
2019-06-09 20:32:15 +03:00
:: new fragment; store in state and check if message is done
::
=. num-received.partial-rcv-message
+(num-received.partial-rcv-message)
::
=. fragments.partial-rcv-message
(~(put by fragments.partial-rcv-message) fragment-num fragment)
::
=. live-messages.state
(~(put by live-messages.state) seq partial-rcv-message)
:: ack any packet other than the last one, and continue either way
::
2019-10-30 23:12:57 +03:00
=? message-sink !is-last-fragment
2020-12-12 03:45:13 +03:00
%- %+ trace rcv.veb |.
=/ data
[seq=seq fragment-num=fragment-num num-fragments=num-fragments]
"send ack-2 {<data>}"
2019-06-20 10:21:37 +03:00
(give %send seq %& fragment-num)
2019-06-09 20:32:15 +03:00
:: enqueue all completed messages starting at +(last-heard.state)
::
2019-10-30 23:12:57 +03:00
|- ^+ message-sink
2019-06-09 20:32:15 +03:00
:: if this is not the next message to ack, we're done
::
?. =(seq +(last-heard.state))
2019-10-30 23:12:57 +03:00
message-sink
2019-06-09 20:32:15 +03:00
:: if we haven't heard anything from this message, we're done
::
?~ live=(~(get by live-messages.state) seq)
2019-10-30 23:12:57 +03:00
message-sink
2019-06-09 20:32:15 +03:00
:: if the message isn't done yet, we're done
::
?. =(num-received num-fragments):u.live
2019-10-30 23:12:57 +03:00
message-sink
2019-06-09 20:32:15 +03:00
:: we have whole message; update state, assemble, and send to vane
::
=. last-heard.state +(last-heard.state)
=. live-messages.state (~(del by live-messages.state) seq)
::
2019-12-03 02:46:40 +03:00
%- %+ trace msg.veb
2020-12-12 03:45:13 +03:00
|.("hear {<her.channel>} {<seq=seq>} {<num-fragments.u.live>}kb")
2019-07-28 10:50:32 +03:00
=/ message=* (assemble-fragments [num-fragments fragments]:u.live)
2019-10-30 23:12:57 +03:00
=. message-sink (enqueue-to-vane seq message)
2019-06-09 20:32:15 +03:00
::
$(seq +(seq))
2019-06-19 03:38:25 +03:00
:: +enqueue-to-vane: enqueue message to be sent to local vane
2019-06-09 20:32:15 +03:00
::
++ enqueue-to-vane
2019-07-28 10:50:32 +03:00
|= [seq=message-num message=*]
2019-10-30 23:12:57 +03:00
^+ message-sink
2019-06-09 20:32:15 +03:00
::
=/ empty=? =(~ pending-vane-ack.state)
=. pending-vane-ack.state (~(put to pending-vane-ack.state) seq message)
?. empty
2019-10-30 23:12:57 +03:00
message-sink
2019-06-20 10:21:37 +03:00
(give %memo seq message)
2019-06-11 03:31:50 +03:00
:: +on-done: handle confirmation of message processing from vane
2019-05-29 01:05:59 +03:00
::
++ on-done
2019-06-18 21:21:12 +03:00
|= ok=?
2019-10-30 23:12:57 +03:00
^+ message-sink
2019-05-29 01:05:59 +03:00
::
2019-06-11 03:31:50 +03:00
=^ pending pending-vane-ack.state ~(get to pending-vane-ack.state)
2019-06-19 03:38:25 +03:00
=/ =message-num message-num.p.pending
::
=. last-acked.state +(last-acked.state)
=? nax.state !ok (~(put in nax.state) message-num)
2019-06-11 03:31:50 +03:00
::
2019-11-27 21:22:20 +03:00
=. message-sink (give %send message-num %| ok lag=`@dr`0)
=/ next ~(top to pending-vane-ack.state)
?~ next
message-sink
(give %memo u.next)
2019-06-20 10:21:37 +03:00
:: +on-drop: drop .message-num from our .nax state
2019-06-19 03:38:25 +03:00
::
2019-06-20 10:21:37 +03:00
++ on-drop
2019-06-19 03:38:25 +03:00
|= =message-num
2019-10-30 23:12:57 +03:00
^+ message-sink
2019-06-19 03:38:25 +03:00
::
=. nax.state (~(del in nax.state) message-num)
::
2019-10-30 23:12:57 +03:00
message-sink
2019-05-29 01:05:59 +03:00
--
2022-01-27 16:32:49 +03:00
::
++ fine
|= [now=@da rof=roof =duct =ames-state]
=* state fine-state.ames-state
=< |%
++ on-keen
|= =path
^- (quip move _ames-state)
=/ omen
~| [%fine %invalid-namespace-path path]
(need (de-omen path))
2022-01-29 01:09:50 +03:00
=* ship p.bem.omen
2022-01-27 16:32:49 +03:00
=. want.state (~(put ju want.state) path duct)
?: (~(has by part.state) path)
:: request is already ongoing
::
[~ ames-state]
=. part.state (~(put by part.state) path *partial-fine)
2022-01-29 01:09:50 +03:00
:: if we don't know the target yet, store the request for later
::
=/ peer (~(get by peers.ames-state) ship)
?. ?=([~ %known *] peer)
::TODO full enqueue-alien-todo
=. peers.ames-state
%+ ~(put by peers.ames-state) ship
?~ peer [%alien %*(. *alien-agenda keens [path ~ ~])]
?> ?=(%alien -.u.peer)
u.peer(keens (~(put in keens.u.peer) path))
[~ ames-state]
(send-request p.bem.omen path 1)
2022-01-27 16:32:49 +03:00
::
++ on-yawn
|= =path
^- (quip move _ames-state)
=. want.state (~(del ju want.state) path duct)
[~ ames-state]
::
++ on-bide
|= =path
^- (quip move _ames-state)
=. hear.state (~(put ju hear.state) path duct)
[~ ames-state]
::
++ on-hear-response
|= [=lane =packet dud=(unit goof)]
^- (quip move _ames-state)
?^ dud
::TODO handle
~& [%fine %done-goofed u.dud]
[~ ames-state]
=/ [=peep =purr] (decode-request-info `@ux`content.packet)
=/ =rawr (decode-response-packet purr)
::TODO validate response signature
(handle-response [sndr.packet lane] peep rawr)
--
|%
+$ twit :: signed request
$: signature=@
peep
==
::
+$ peep :: request data
$: =path
num=@ud
==
::
+$ rawr :: response packet ::TODO meow
$: sig=@
siz=@ud
byts
==
::
+$ roar :: response message
$: sig=@
dat=(cask)
==
::
++ spit
|= =path
^- [pat=@t wid=@ud]
=+ pat=(spat path)
=+ wid=(met 3 pat)
?> (lte wid 384) ::TODO check when we handle %keen, in addition to here
[pat wid]
::
++ request-body
|= [=path num=@ud]
2022-01-29 01:10:50 +03:00
::NOTE path is expected to be a namespace path without the ship
2022-01-27 16:32:49 +03:00
^- byts
?> (lth num (bex 32))
=+ (spit path)
:- :(add 32 16 wid)
%+ can 3
:~ 4^num :: fragment number
2^wid :: path size
wid^`@`pat :: namespace path
==
::
++ encode-request
2022-01-29 01:10:50 +03:00
|= [=ship =path num=@ud]
::NOTE path is expected to be a namespace path without the ship
2022-01-27 16:32:49 +03:00
^- hoot ^- @
=+ bod=(request-body path num)
=+ syn=(can 3 64^(sign:keys dat.bod) bod ~)
%+ con 0b100 ::NOTE request bit
2022-01-29 01:10:50 +03:00
%+ encode-packet |
[[our ship] (mod life:keys 16) (mod (lyfe:keys ship) 16) ~ syn]
2022-01-27 16:32:49 +03:00
::
++ encode-response ::TODO unit tests
|= [=path data=(unit (cask))]
^- song
:: prepend request descriptions to each response packet
::
=; pacs=(list @ux)
%- head
%^ spin pacs 1
|= [pac=@ux num=@ud]
^- [purr _num]
:_ +(num)
^- @ux
::NOTE we stub out the receiver & origin details,
:: runtime should replace them as appropriate.
::TODO should have scry endpoint that produces gate that does
:: that packet transformation
(encode-packet | [our ~zod] (mod life:keys 16) 0b0 ~ pac)
:: prepend a signature and split the data into 1024-byte fragments
::
=/ frag=(list @)
::TODO should also sign the request path
=/ sig=@ (full:keys path (fall data ~))
?~ data [sig]~
%+ rip 13 ::NOTE 1024 bytes
(cat 3 sig (jam u.data)) ::TODO should include life
:: sign & packetize the fragments
::
%- head
%^ spin frag 1
|= [dat=@ num=@ud]
:_ +(num)
^- @ux
=/ req=byts (request-body path num)
=/ bod=byts
=/ wid=@ud (met 3 dat)
:- :(add 4 2 wid)
%+ can 3
:~ 4^(lent frag) :: number of fragments
2^wid :: response data fragment size in bytes
wid^dat :: response data fragment
==
=/ sig=byts
64^(sign:keys (can 3 req bod ~))
(can 3 req sig bod ~)
::
++ keys
|%
++ full
|= [=path mess=*]
(sign (shax (jam [our life path mess])))
::
2022-01-28 16:30:59 +03:00
++ life life.ames-state
++ sign sign:as:crypto-core.ames-state
2022-01-27 16:32:49 +03:00
::
2022-01-28 16:30:59 +03:00
::TODO for the unknown case, should use the alien-agenda
2022-01-27 16:32:49 +03:00
++ lyfe
|= who=ship
2022-01-28 16:30:59 +03:00
^- ^life
~| [%fine %unknown-peer who]
=/ ship-state (~(got by peers.ames-state) who)
?> ?=([%known *] ship-state)
life.ship-state
2022-01-27 16:32:49 +03:00
::
2022-01-28 16:30:59 +03:00
::TODO for the unknown case, should use the alien-agenda
2022-01-27 16:32:49 +03:00
++ pass
|= [who=ship lyf=^life]
2022-01-28 16:30:59 +03:00
~| [%fine %unknown-peer who lyf]
=/ ship-state (~(got by peers.ames-state) who)
?> ?=([%known *] ship-state)
~| [%fine %life-mismatch who lyf]
?> =(lyf life.ship-state)
public-key.ship-state
2022-01-27 16:32:49 +03:00
--
::
++ get-lane
|= =ship
^- lane:ames
=; lanes
::TODO should we send to all lanes?
?^ lanes i.lanes
~&(%fine-lane-stub &+~zod) ::TODO
!< (list lane:ames)
=< q %- need %- need
=/ =path /peers/(scot %p ship)/forward-lane
::TODO get from state
(rof `[our ~ ~] [%ames %x] [our %$ da+now] path)
::
++ decode-request
|= =hoot
^- twit
:- sig=(cut 3 [0 64] hoot)
-:(decode-request-info (rsh 3^64 hoot))
::
++ decode-request-info
|= =hoot
^- [=peep =purr]
=+ num=(cut 3 [0 4] hoot)
=+ len=(cut 3 [4 2] hoot)
=+ pat=(cut 3 [6 len] hoot)
:- [(stab pat) num]
:: if there is data remaining, it's the response
(rsh [3 (add 6 len)] hoot)
::
++ decode-response-packet
|= =purr
=; =rawr
~? !=(wid.rawr (met 3 dat.rawr)) [%fine %unexpected-dat-size]
rawr
:* sig=(cut 3 [0 64] purr)
siz=(cut 3 [64 4] purr)
wid=(cut 3 [68 2] purr)
dat=(rsh 3^70 purr)
==
::
++ verify-response-packet
|= rawr
!!
::
++ decode-response-msg
|= partial-fine ::TODO maybe take @ instead
^- roar
=/ mess=@
%+ can 3 ::TODO just (rep 13 -)
%+ turn (gulf 1 num-fragments)
~(got by fragments)
:- sig=(cut 3 [0 64] mess)
~| [%fine %response-not-cask]
;;((cask) (cue (rsh 3^64 mess)))
::
2022-01-29 01:09:50 +03:00
++ send-request
|= [=ship =path num=@ud]
^- (quip move _ames-state)
:_ ames-state
:: make sure we exclude the ship from the path proper,
:: since it already gets included in the request header
::
=. path (oust [1 1] path)
=/ =lane:ames (get-lane ship)
=/ =hoot (encode-request ship path 1)
[unix-duct.ames-state %give %send lane `@ux`hoot]~
::
2022-01-27 16:32:49 +03:00
++ process-response
|= [=path data=(unit (cask))]
^- (quip move _ames-state)
:- %+ turn ~(tap in (~(get ju want.state) path))
(late [%give %tune path data])
=. want.state (~(del by want.state) path)
=. part.state (~(del by part.state) path)
ames-state
::
++ handle-request
|= =twit
^- (list move)
=/ =song
%+ encode-response path.twit
(get-scry-result *gang path.twit)
::TODO different task, pick the right packet
[duct %give %howl path.twit song]~
::
++ handle-response
|= [[from=ship =lane:ames] =peep =rawr]
^- (quip move _ames-state)
?: =(0 siz.rawr)
?> =(~ dat.rawr)
(process-response path.peep ~)
?. (~(has by part.state) path.peep)
:: we did not initiate this request, or it's been cancelled
::
!!
=/ partial=partial-fine
(~(got by part.state) path.peep)
=. partial
?: (~(has by fragments.partial) num.peep)
partial
=, partial
:+ ~| [%fine %response-size-changed have=num-fragments new=siz.rawr]
?> |(=(0 num-fragments) =(num-fragments siz.rawr))
num-fragments
+(num-received)
(~(put by fragments) num.peep [wid dat]:rawr)
::
?: =(num-fragments num-received):partial
:: we have all the parts now, construct the full response
::
=/ =roar (decode-response-msg partial)
::TODO check signature
(process-response path.peep `dat.roar)
:: otherwise, store the part, and send out the next request
::
=. part.state (~(put by part.state) path.peep partial)
=/ next-num=@ud
=/ next=@ud +(num.peep)
:: we should receive responses in order, but in case we don't...
::
|-
?. (~(has by fragments.partial) next) next
$(next +((mod next num-fragments.partial)))
::
2022-01-29 01:10:50 +03:00
=/ =hoot (encode-request from path.peep next-num)
2022-01-27 16:32:49 +03:00
::TODO ask amsden, should we shotgun? we can tweak this
:: for now (mvp) though, stay 1-to-1
::TODO update lane in ames state
::TODO is reusing the lane fine?
:_ ames-state
[unix-duct.ames-state %give %send lane `@ux`hoot]~
::
++ get-scry-result
|= [=gang =path]
^- (unit (cask))
?~ nom=(de-omen path) ~
?> =(our p.bem.u.nom)
:: we only support scrying into clay,
:: and only if the data is fully public.
::
?. =(%c (end 3 (snag 0 path))) ~
=+ pem=(rof gang (need (de-omen %cp (slag 1 path))))
?> ?=(^ pem)
?> ?=(^ u.pem)
=+ per=!<([r=dict:clay w=dict:clay] q.u.u.pem)
?> =([%black ~ ~] rul.r.per)
=+ res=(rof gang u.nom)
?- res
~ !! ::TODO lets just not do the task case
[~ ~] ~
[~ ~ *] `[p q.q]:u.u.res
==
--
2019-05-25 05:03:33 +03:00
--