diff --git a/pkg/arvo/sys/vane/ames.hoon b/pkg/arvo/sys/vane/ames.hoon index 790ed55e87..5ffedece11 100644 --- a/pkg/arvo/sys/vane/ames.hoon +++ b/pkg/arvo/sys/vane/ames.hoon @@ -105,7 +105,9 @@ rot=`?`%.n :: routing attempts == => +~% %ames ..is ~ |% ++| %helpers :: +trace: print if .verb is set and we're tracking .ship :: ++ trace @@ -117,22 +119,373 @@ ~+ |(=(~ ships) (~(has in ships) ship)) same (slog leaf/"ames: {(scow %p ship)}: {(print)}" ~) --- -=> -~% %ames-generics ..is ~ -|% +:: +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]) + :: + %- cue + %+ can 13 + %+ turn (flop sorted) + |=(a=@ [1 a]) +:: +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 + :: + ?> =('b' (end 3 1 public-key)) + =. public-key (rsh 8 1 (rsh 3 1 public-key)) + :: + ?> =('B' (end 3 1 private-key)) + =. private-key (rsh 8 1 (rsh 3 1 private-key)) + :: + `@`(shar:ed:crypto public-key private-key) +:: +encode-packet: serialize a packet into a bytestream +:: +++ encode-packet + ~/ %encode-packet + |= packet + ^- blob + :: + =/ sndr-meta (encode-ship-metadata sndr) + =/ rcvr-meta (encode-ship-metadata rcvr) + :: + =/ body=@ + ;: mix + sndr-tick + (lsh 2 1 rcvr-tick) + (lsh 3 1 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=&] + [3 protocol-version] + [2 rank.sndr-meta] + [2 rank.rcvr-meta] + [20 checksum] + [1 relayed=.?(origin)] + == + (mix header (lsh 5 1 body)) +:: +decode-packet: deserialize packet from bytestream or crash +:: +++ decode-packet + ~/ %decode-packet + |= =blob + ^- packet + ~| %decode-packet-fail + :: first 32 (2^5) bits are header; the rest is body + :: + =/ header (end 5 1 blob) + =/ body (rsh 5 1 blob) + :: read header; first three bits are reserved + :: + =/ is-ames (cut 0 [3 1] header) + ?. =(& is-ames) + ~| %ames-not-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 + ~/ %is-valid-rank + |= [=ship size=@ubC] + ^- ? + .= size + ?- (clan:title ship) + %czar 2 + %king 2 + %duke 4 + %earl 8 + %pawn 16 + == +:: +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. + :: + =/ key (end 8 1 (rsh 3 1 public-key.open-packet)) + ?> (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)) + =/ content :(mix siv (lsh 7 1 len) (lsh 3 18 cyf)) + [[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 !! + =/ siv (end 7 1 content.packet) + =/ len (end 4 1 (rsh 7 1 content.packet)) + =/ cyf (rsh 3 18 content.packet) + ~| 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) +:: +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 + ~/ %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 + ~/ %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] +| %atomics :: +$ private-key @uwprivatekey +$ signature @uwsignature :: $rank: which kind of ship address, by length :: -:: 0: galaxy or star -- 2 bytes -:: 1: planet -- 4 bytes -:: 2: moon -- 8 bytes -:: 3: comet -- 16 bytes +:: 0b0: galaxy or star -- 2 bytes +:: 0b1: planet -- 4 bytes +:: 0b10: moon -- 8 bytes +:: 0b11: comet -- 16 bytes :: -+$ rank ?(%0 %1 %2 %3) ++$ rank ?(%0b0 %0b1 %0b10 %0b11) :: +| %kinetics :: $channel: combined sender and receiver identifying data @@ -165,7 +518,13 @@ :: address. Routes are opaque to Arvo and only have meaning in the :: interpreter. This enforces that Ames is transport-agnostic. :: -+$ packet [dyad encrypted=? origin=(unit lane) content=*] ++$ packet + $: dyad + sndr-tick=@ubC + rcvr-tick=@ubC + origin=(unit @uxaddress) + content=@uxcontent + == :: $open-packet: unencrypted packet payload, for comet self-attestation :: :: This data structure gets signed and jammed to form the .contents @@ -181,9 +540,7 @@ :: $shut-packet: encrypted packet payload :: +$ shut-packet - $: =sndr=life - =rcvr=life - =bone + $: =bone =message-num meat=(each fragment-meat ack-meat) == @@ -691,14 +1048,16 @@ ``noun+!>(!>(res)) == -- -:: helpers +:: |per-event: inner event-handling core :: -~% %ames-helpers +>+ ~ +~% %per-event ..decode-packet ~ |% ++ per-event =| moves=(list move) + ~% %event-gate ..per-event ~ |= [[our=ship now=@da eny=@ scry-gate=sley] =duct =ames-state] =* veb veb.bug.ames-state + ~% %event-core ..$ ~ |% ++ event-core . ++ abet [(flop moves) ames-state] @@ -848,20 +1207,14 @@ =/ =channel [[our ship] now channel-state -.peer-state] abet:on-jilt:(make-peer-core peer-state channel) :: +on-hear: handle raw packet receipt - :: - ++ on-hear - |= [=lane =blob] - ^+ event-core - (on-hear-packet lane (decode-packet blob) ok=%.y) :: +on-hole: handle packet crash notification :: - ++ on-hole - |= [=lane =blob] - ^+ event-core - (on-hear-packet lane (decode-packet blob) ok=%.n) + ++ on-hear |=([l=lane b=blob] (on-hear-packet l (decode-packet b) ok=&)) + ++ on-hole |=([l=lane b=blob] (on-hear-packet l (decode-packet b) ok=|)) :: +on-hear-packet: handle mildly processed packet receipt :: ++ on-hear-packet + ~/ %on-hear-packet |= [=lane =packet ok=?] ^+ event-core :: @@ -873,9 +1226,11 @@ ?. =(our rcvr.packet) on-hear-forward :: - ?: encrypted.packet - on-hear-shut - on-hear-open + ?: ?& ?=(%pawn (clan:title sndr.packet)) + !(~(has by peers.ames-state) sndr.packet) + == + on-hear-open + on-hear-shut :: +on-hear-forward: maybe forward a packet to someone else :: :: Note that this performs all forwarding requests without @@ -883,18 +1238,27 @@ :: provided by Vere. :: ++ on-hear-forward + ~/ %on-hear-forward |= [=lane =packet ok=?] ^+ event-core %- %^ trace for.veb sndr.packet |.("forward: {} -> {}") :: set .origin.packet if it doesn't already have one, re-encode, and send :: - =? origin.packet ?=(~ origin.packet) `lane + =? origin.packet + &(?=(~ origin.packet) !=(%czar (clan:title sndr.packet))) + ?: ?=(%& -.lane) + ~ + ?. (lte (met 3 p.lane) 6) + ~| ames-lane-size+p.lane !! + `p.lane + :: =/ =blob (encode-packet packet) (send-blob & rcvr.packet blob) :: +on-hear-open: handle receipt of plaintext comet self-attestation :: ++ on-hear-open + ~/ %on-hear-open |= [=lane =packet ok=?] ^+ event-core :: assert the comet can't pretend to be a moon or other address @@ -905,29 +1269,8 @@ =/ ship-state (~(get by peers.ames-state) sndr.packet) ?: ?=([~ %known *] ship-state) event-core - :: deserialize and type-check packet contents :: - ?> ?=(@ content.packet) - =+ ;; [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 life.ames-state - :: 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. - :: - =/ key (end 8 1 (rsh 3 1 public-key.open-packet)) - ?> (veri:ed:crypto signature signed key) + =/ =open-packet (decode-open-packet packet our life.ames-state) :: store comet as peer in our state :: =. peers.ames-state @@ -952,12 +1295,9 @@ :: +on-hear-shut: handle receipt of encrypted packet :: ++ on-hear-shut + ~/ %on-hear-shut |= [=lane =packet ok=?] ^+ event-core - :: encrypted packet content must be an encrypted atom - :: - ?> ?=(@ content.packet) - :: =/ sndr-state (~(get by peers.ames-state) sndr.packet) :: if we don't know them, maybe enqueue a jael %public-keys request :: @@ -977,19 +1317,11 @@ =/ =peer-state +.u.sndr-state =/ =channel [[our sndr.packet] now channel-state -.peer-state] ~| %ames-crash-on-packet-from^her.channel - =/ =shut-packet (decrypt symmetric-key.channel content.packet) - :: ward against replay attacks - :: - :: We only accept packets from a ship at their known life, and to - :: us at our current life. - :: - ~| our-life=[expected=our-life.channel got=rcvr-life.shut-packet] - ~| her-life=[expected=her-life.channel got=sndr-life.shut-packet] - ?> =(sndr-life.shut-packet her-life.channel) - ?> =(rcvr-life.shut-packet our-life.channel) + =/ =shut-packet + (decode-shut-packet packet [symmetric-key her-life our-life]:channel) :: non-galaxy: update route with heard lane or forwarded lane :: - =? route.peer-state !=(%czar (clan:title her.channel)) + =? route.peer-state !=(%czar (clan:title her.channel)) :: 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 @@ -1012,10 +1344,10 @@ ?: ?=(~ origin.packet) `[direct=%.y lane] ?: ?=([~ %& *] route.peer-state) - ?: =(lane.u.route.peer-state u.origin.packet) + ?: =(lane.u.route.peer-state |+u.origin.packet) route.peer-state - `[direct=%.n u.origin.packet] - `[direct=%.n u.origin.packet] + `[direct=%.n |+u.origin.packet] + `[direct=%.n |+u.origin.packet] :: perform peer-specific handling of packet :: =/ peer-core (make-peer-core peer-state channel) @@ -1397,6 +1729,7 @@ :: request the information from Jael if we haven't already. :: ++ send-blob + ~/ %send-blob |= [for=? =ship =blob] :: =/ final-ship ship @@ -1461,19 +1794,15 @@ ++ attestation-packet |= [her=ship =her=life] ^- blob - :: - =/ =open-packet - :* ^= public-key pub:ex:crypto-core.ames-state - ^= sndr our - ^= sndr-life life.ames-state - ^= rcvr her - ^= rcvr-life her-life - == - :: - =/ signed=@ (sign:as:crypto-core.ames-state (jam open-packet)) - =/ =packet [[our her] encrypted=%.n origin=~ signed] - :: - (encode-packet packet) + %- encode-packet + %- 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 + == :: +get-peer-state: lookup .her state or ~ :: ++ get-peer-state @@ -1732,13 +2061,15 @@ :: kind of flow this is (forward/backward), so flip the bit :: here. :: - =. bone.shut-packet (mix 1 bone.shut-packet) - :: - =/ content (encrypt symmetric-key.channel shut-packet) - =/ =packet [[our her.channel] encrypted=%.y origin=~ content] - =/ =blob (encode-packet packet) - :: - =. event-core (send-blob | her.channel blob) + =. event-core + %^ send-blob | her.channel + %- encode-packet + %: encode-shut-packet + shut-packet(bone (mix 1 bone.shut-packet)) + symmetric-key.channel + our her.channel + our-life.channel her-life.channel + == peer-core :: +got-duct: look up $duct by .bone, asserting already bound :: @@ -1796,17 +2127,7 @@ :: +on-pump-send: emit message fragment requested by |message-pump :: ++ on-pump-send - |= =static-fragment - ^+ peer-core - :: encrypt and encode .static-fragment to .blob bitstream - :: - %- send-shut-packet :* - our-life.channel - her-life.channel - bone - message-num.static-fragment - %& +.static-fragment - == + |=(f=static-fragment (send-shut-packet bone [message-num %& +]:f)) :: +on-pump-wait: relay |message-pump's set-timer request :: ++ on-pump-wait @@ -1853,16 +2174,7 @@ :: +on-sink-send: emit ack packet as requested by |message-sink :: ++ on-sink-send - |= [=message-num =ack-meat] - ^+ peer-core - :: - %- send-shut-packet :* - our-life.channel - her-life.channel - bone - message-num - %| ack-meat - == + |=([num=message-num ack=ack-meat] (send-shut-packet bone num %| ack)) :: +on-sink-memo: dispatch message received by |message-sink :: :: odd bone: %plea request message @@ -2783,259 +3095,4 @@ :: message-sink -- -:: +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 - |= [=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 - |= [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]) - :: - %- cue - %+ can 13 - %+ turn (flop sorted) - |=(a=@ [1 a]) -:: +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 - |= [=public-key =private-key] - ^- symmetric-key - :: - ?> =('b' (end 3 1 public-key)) - =. public-key (rsh 8 1 (rsh 3 1 public-key)) - :: - ?> =('B' (end 3 1 private-key)) - =. private-key (rsh 8 1 (rsh 3 1 private-key)) - :: - `@`(shar:ed:crypto public-key private-key) -:: +encrypt: encrypt $shut-packet into atomic packet content -:: -++ encrypt - |= [=symmetric-key plaintext=shut-packet] - ^- @ - :: - =? meat.plaintext - ?& ?=(%& -.meat.plaintext) - (gth (met 13 fragment.p.meat.plaintext) 1) - == - %_ meat.plaintext - fragment.p - (cut 13 [[fragment-num 1] fragment]:p.meat.plaintext) - == - (en:crub:crypto symmetric-key (jam plaintext)) -:: +decrypt: decrypt packet content to a $shut-packet or die -:: -++ decrypt - |= [=symmetric-key ciphertext=@] - ^- shut-packet - :: - ;; shut-packet - %- cue - %- need - (de:crub:crypto symmetric-key ciphertext) -:: +encode-packet: serialize a packet into a bytestream -:: -++ encode-packet - |= packet - ^- blob - :: - =/ sndr-meta (encode-ship-metadata sndr) - =/ rcvr-meta (encode-ship-metadata rcvr) - :: body: <> - :: - :: The .sndr and .rcvr ship addresses are encoded with fixed - :: lengths specified by the packet header. They live outside - :: the jammed-data section to simplify packet filtering in the - :: interpreter. - :: - =/ body=@ - ;: mix - sndr - (lsh 3 size.sndr-meta rcvr) - (lsh 3 (add size.sndr-meta size.rcvr-meta) (jam [origin content])) - == - :: header: 32-bit header assembled from bitstreams of fields - :: - :: <> - :: 4 bits at the end of the header are unused. - :: - =/ header=@ - %+ can 0 - :~ [3 protocol-version] - [20 (mug body)] - [2 rank.sndr-meta] - [2 rank.rcvr-meta] - [5 ?:(encrypted %0 %1)] - == - :: result is <
> - :: - (mix header (lsh 5 1 body)) -:: +decode-packet: deserialize packet from bytestream or crash -:: -++ decode-packet - |= =blob - ^- packet - :: first 32 (2^5) bits are header; the rest is body - :: - =/ header (end 5 1 blob) - =/ body (rsh 5 1 blob) - :: - =/ version (end 0 3 header) - =/ checksum (cut 0 [3 20] header) - =/ sndr-size (decode-ship-size (cut 0 [23 2] header)) - =/ rcvr-size (decode-ship-size (cut 0 [25 2] header)) - =/ encrypted ?+((cut 0 [27 5] header) !! %0 %.y, %1 %.n) - :: - =/ =dyad - :- sndr=(end 3 sndr-size body) - rcvr=(cut 3 [sndr-size rcvr-size] body) - :: - ?. =(protocol-version version) - ~| %ames-protocol^version^dyad !! - ?. =(checksum (end 0 20 (mug body))) - ~| %ames-checksum^dyad !! - :: - =+ ~| %ames-invalid-packet - ;; [origin=(unit lane) content=*] - ~| %ames-invalid-noun - %- cue - (rsh 3 (add rcvr-size sndr-size) body) - :: - [dyad encrypted origin content] -:: +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=@ - ^- @ - :: - ?+ rank !! - %0 2 - %1 4 - %2 8 - %3 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 %0] - ?: (lte size 4) [4 %1] - ?: (lte size 8) [8 %2] - [16 %3] -- diff --git a/pkg/arvo/tests/sys/vane/ames.hoon b/pkg/arvo/tests/sys/vane/ames.hoon index 26e162d0a4..2e3ac4fa7d 100644 --- a/pkg/arvo/tests/sys/vane/ames.hoon +++ b/pkg/arvo/tests/sys/vane/ames.hoon @@ -6,31 +6,43 @@ :: =/ nec vane =/ bud vane +=/ comet vane :: -=. our.nec ~nec -=. now.nec ~1111.1.1 -=. eny.nec 0xdead.beef -=. rof.nec |=(* ``[%noun !>(*(list turf))]) -:: -=. our.bud ~bud -=. now.bud ~1111.1.1 -=. eny.bud 0xbeef.dead -=. rof.bud |=(* ``[%noun !>(*(list turf))]) -:: +=. our.nec ~nec +=. now.nec ~1111.1.1 +=. eny.nec 0xdead.beef +=. life.ames-state.nec 2 +=. scry-gate.nec |=(* ``[%noun !>(*(list turf))]) =. crypto-core.ames-state.nec (pit:nu:crub:crypto 512 (shaz 'nec')) -=. crypto-core.ames-state.bud (pit:nu:crub:crypto 512 (shaz 'bud')) -:: =/ nec-pub pub:ex:crypto-core.ames-state.nec =/ nec-sec sec:ex:crypto-core.ames-state.nec +:: +=. our.bud ~bud +=. now.bud ~1111.1.1 +=. eny.bud 0xbeef.dead +=. life.ames-state.bud 3 +=. scry-gate.bud |=(* ``[%noun !>(*(list turf))]) +=. crypto-core.ames-state.bud (pit:nu:crub:crypto 512 (shaz 'bud')) =/ bud-pub pub:ex:crypto-core.ames-state.bud =/ bud-sec sec:ex:crypto-core.ames-state.bud :: +=. our.comet ~bosrym-podwyl-magnes-dacrys--pander-hablep-masrym-marbud +=. now.comet ~1111.1.1 +=. eny.comet 0xbeef.cafe +=. scry-gate.comet |=(* ``[%noun !>(*(list turf))]) +=. crypto-core.ames-state.comet + %- nol:nu:crub:crypto + 0w9N.5uIvA.Jg0cx.NCD2R.o~MtZ.uEQOB.9uTbp.6LHvg.0yYTP. + 3q3td.T4UF0.d5sDL.JGpZq.S3A92.QUuWg.IHdw7.izyny.j9W92 +=/ comet-pub pub:ex:crypto-core.ames-state.comet +=/ comet-sec sec:ex:crypto-core.ames-state.comet +:: =/ nec-sym (derive-symmetric-key:vane bud-pub nec-sec) =/ bud-sym (derive-symmetric-key:vane nec-pub bud-sec) -:: ?> =(nec-sym bud-sym) :: -=. life.ames-state.nec 2 +=/ comet-sym (derive-symmetric-key:vane bud-pub comet-sec) +:: =. peers.ames-state.nec %+ ~(put by peers.ames-state.nec) ~bud =| =peer-state:ames @@ -43,7 +55,6 @@ =. route.peer-state `[direct=%.y `lane:ames`[%& ~nec]] [%known peer-state] :: -=. life.ames-state.bud 3 =. peers.ames-state.bud %+ ~(put by peers.ames-state.bud) ~nec =| =peer-state:ames @@ -106,9 +117,10 @@ :: =/ =packet:ames :* [sndr=~nec rcvr=~bud] - encrypted=%.n + sndr-tick=0b10 + rcvr-tick=0b11 origin=~ - content=[12 13] + content=0xdead.beef == :: =/ encoded (encode-packet:vane packet) @@ -118,6 +130,50 @@ !> packet !> decoded :: +++ test-origin-encoding ^- tang + :: + =/ =packet:ames + :* [sndr=~nec rcvr=~bud] + sndr-tick=0b10 + rcvr-tick=0b11 + origin=`0xbeef.cafe.beef + content=0xdead.beef + == + :: + =/ encoded (encode-packet:vane packet) + =/ decoded (decode-packet:vane encoded) + :: + %+ expect-eq + !> packet + !> decoded +:: +++ test-shut-packet-encoding ^- tang + :: + =/ =shut-packet:ames + :+ bone=17 message-num=18 + [%& num-fragments=1 fragment-num=1 fragment=`@`0xdead.beef] + :: + =/ =packet:ames + (encode-shut-packet:ames shut-packet nec-sym ~marnec ~marbud-marbud 3 17) + :: + =/ decoded (decode-shut-packet:ames packet nec-sym 3 17) + :: + %+ expect-eq + !> shut-packet + !> decoded +:: +++ test-shut-packet-associated-data ^- tang + :: + =/ =shut-packet:ames + :+ bone=17 message-num=18 + [%& num-fragments=1 fragment-num=1 fragment=`@`0xdead.beef] + :: + =/ =packet:ames + (encode-shut-packet:ames shut-packet nec-sym ~marnec ~marbud-marbud 3 1) + :: + %- expect-fail + |.((decode-shut-packet:ames packet nec-sym 3 17)) +:: ++ test-alien-encounter ^- tang :: =/ lane-foo=lane:ames [%| `@ux``@`%lane-foo] @@ -125,18 +181,19 @@ =/ =plea:ames [%g /talk [%first %post]] :: =/ =shut-packet:ames - :* sndr-life=4 - rcvr-life=3 - bone=1 + :* bone=1 message-num=1 [%& num-fragments=1 fragment-num=0 (jam plea)] == :: =/ =packet:ames - :* [sndr=~bus rcvr=~bud] - encrypted=%.y - origin=~ - content=(encrypt:vane nec-sym shut-packet) + %: encode-shut-packet:vane + shut-packet + nec-sym + ~bus + ~bud + sndr-life=4 + rcvr-life=3 == :: =/ =blob:ames (encode-packet:vane packet) @@ -170,6 +227,56 @@ !> (sy ,.moves3) == :: +++ test-comet-encounter ^- tang + :: + =/ lane-foo=lane:ames [%| `@ux``@`%lane-foo] + :: + =/ =open-packet:ames + :* public-key=`@`comet-pub + sndr=our.comet + sndr-life=1 + rcvr=~bud + rcvr-life=3 + == + =/ packet + (encode-open-packet:vane open-packet crypto-core.ames-state.comet) + =/ blob (encode-packet:vane packet) + :: + =^ moves0 bud (call bud ~[//unix] %hear lane-foo blob) + :: + =/ =plea:ames [%g /talk [%first %post]] + =/ =shut-packet:ames + :* bone=1 + message-num=1 + [%& num-fragments=1 fragment-num=0 (jam plea)] + == + =/ =packet:ames + %: encode-shut-packet:vane + shut-packet + comet-sym + our.comet + ~bud + sndr-life=1 + rcvr-life=3 + == + =/ blob (encode-packet:vane packet) + =^ moves1 bud (call bud ~[//unix] %hear lane-foo blob) + :: + ;: weld + %+ expect-eq + !> ~ + !> moves0 + :: + %+ expect-eq + !> :~ :* ~[//unix] %pass /qos %d %flog %text + "; {} is your neighbor" + == + :* ~[//unix] %pass /bone/(scot %p our.comet)/1 + %g %plea our.comet plea + == == + !> moves1 + == +:: ++ test-message-flow ^- tang :: ~nec -> %plea -> ~bud :: diff --git a/pkg/urbit/vere/io/ames.c b/pkg/urbit/vere/io/ames.c index ae0656c3f1..9a3ad2a731 100644 --- a/pkg/urbit/vere/io/ames.c +++ b/pkg/urbit/vere/io/ames.c @@ -66,11 +66,12 @@ /* u3_head: ames packet header */ typedef struct _u3_head { + c3_o sim_o; // is ames protocol? c3_y ver_y; // protocol version - c3_l mug_l; // truncated mug hash of u3_body c3_y sac_y; // sender class c3_y rac_y; // receiver class - c3_o enc_o; // encrypted? + c3_l mug_l; // truncated mug hash of u3_body + c3_o rel_o; // relayed? } u3_head; /* u3_body: ames packet body @@ -78,8 +79,12 @@ typedef struct _u3_body { c3_d sen_d[2]; // sender c3_d rec_d[2]; // receiver - c3_w con_w; // jam size - c3_y* con_y; // (jam [origin content]) + c3_y sic_y; // sender life tick + c3_y ric_y; // receiver life tick + c3_s con_s; // content size + c3_y* con_y; // content + c3_d rog_d; // origin lane (optional) + c3_l mug_l; // checksum } u3_body; /* u3_panc: deconstructed incoming packet @@ -140,14 +145,6 @@ _ames_panc_free(u3_panc* pac_u) c3_free(pac_u); } -/* _ames_mug_body(): truncated (20 least-significant bits) mug hash of bytes -*/ -static c3_l -_ames_mug_body(c3_w len_w, c3_y* byt_y) -{ - return u3r_mug_bytes(byt_y, len_w) & 0xfffff; -} - /* _ames_sift_head(): parse packet header. */ static c3_o @@ -158,36 +155,20 @@ _ames_sift_head(u3_head* hed_u, c3_y buf_y[4]) | (buf_y[2] << 16) | (buf_y[3] << 24); - // XX only version 0 currently recognized + // first three bits are reserved // - hed_u->ver_y = hed_w & 0x7; - hed_u->mug_l = (hed_w >> 3) & 0xfffff; // 20 bits - hed_u->sac_y = (hed_w >> 23) & 0x3; - hed_u->rac_y = (hed_w >> 25) & 0x3; - hed_u->enc_o = (hed_w >> 27) & 0x1; - return c3y; + hed_u->sim_o = (hed_w >> 3) & 0x1; + hed_u->ver_y = (hed_w >> 4) & 0x7; + hed_u->sac_y = (hed_w >> 7) & 0x3; + hed_u->rac_y = (hed_w >> 9) & 0x3; + hed_u->mug_l = (hed_w >> 11) & 0xfffff; // 20 bits + hed_u->rel_o = (hed_w >> 31) & 0x1; + + // reject packets that don't even claim to be ames packets + // + return hed_u->sim_o; } -/* _ames_etch_head(): serialize packet header. -*/ -static void -_ames_etch_head(u3_head* hed_u, c3_y buf_y[4]) -{ - c3_w hed_w = hed_u->ver_y - | (hed_u->mug_l << 3) - | (hed_u->sac_y << 23) - | (hed_u->rac_y << 25) - | (hed_u->enc_o << 27); - - // only version 0 currently recognized - // - c3_assert( 0 == hed_u->ver_y ); - - buf_y[0] = hed_w & 0xff; - buf_y[1] = (hed_w >> 8) & 0xff; - buf_y[2] = (hed_w >> 16) & 0xff; - buf_y[3] = (hed_w >> 24) & 0xff; -} /* _ames_chub_bytes(): c3_y[8] to c3_d ** XX factor out, deduplicate with other conversions @@ -254,57 +235,106 @@ _ames_sift_body(u3_head* hed_u, c3_w len_w, c3_y* bod_y) { - c3_y sen_y = 2 << hed_u->sac_y; - c3_y rec_y = 2 << hed_u->rac_y; + c3_y rog_y, sen_y, rec_y; - if ( (sen_y + rec_y) >= len_w ) { + rog_y = ( c3y == hed_u->rel_o )? 6 : 0; + + sen_y = 2 << hed_u->sac_y; + rec_y = 2 << hed_u->rac_y; + + if ( (1 + sen_y + rec_y + rog_y) >= len_w ) { return c3n; } else { - _ames_ship_to_chubs(bod_u->sen_d, sen_y, bod_y); - _ames_ship_to_chubs(bod_u->rec_d, rec_y, bod_y + sen_y); + c3_y* gob_y; + c3_s gob_s; + + if ( rog_y) { + c3_y rag_y[8] = {0}; + memcpy(rag_y, bod_y, rog_y); + bod_u->rog_d = _ames_chub_bytes(rag_y); + } + else { + bod_u->rog_d = 0; + } + + gob_y = bod_y + rog_y; + gob_s = len_w - rog_y; + + bod_u->mug_l = u3r_mug_bytes(gob_y, gob_s) & 0xfffff; + + bod_u->sic_y = gob_y[0] & 0xf; + bod_u->ric_y = (gob_y[0] >> 4) & 0xf; + + _ames_ship_to_chubs(bod_u->sen_d, sen_y, gob_y + 1); + _ames_ship_to_chubs(bod_u->rec_d, rec_y, gob_y + 1 + sen_y); + + bod_u->con_s = gob_s - 1 - sen_y - rec_y; + bod_u->con_y = gob_y + 1 + sen_y + rec_y; - bod_u->con_w = len_w - sen_y - rec_y; - bod_u->con_y = bod_y + sen_y + rec_y; return c3y; } } +/* _ames_etch_head(): serialize packet header. +*/ +static void +_ames_etch_head(u3_head* hed_u, c3_y buf_y[4]) +{ + c3_w hed_w = ((hed_u->sim_o & 0x1) << 3) + ^ ((hed_u->ver_y & 0x7) << 4) + ^ ((hed_u->sac_y & 0x3) << 7) + ^ ((hed_u->rac_y & 0x3) << 9) + ^ ((hed_u->mug_l & 0xfffff) << 11) + ^ ((hed_u->rel_o & 0x1) << 31); + + // only version 0 currently recognized + // + c3_assert( 0 == hed_u->ver_y ); // XX remove after testing + + buf_y[0] = hed_w & 0xff; + buf_y[1] = (hed_w >> 8) & 0xff; + buf_y[2] = (hed_w >> 16) & 0xff; + buf_y[3] = (hed_w >> 24) & 0xff; +} + /* _ames_etch_pack(): serialize packet header and body. */ static c3_w _ames_etch_pack(u3_head* hed_u, u3_body* bod_u, - c3_o mug_o, c3_y** out_y) { - // start with the body - // - c3_y sen_y = 2 << hed_u->sac_y; // sender len - c3_y rec_y = 2 << hed_u->rac_y; // receiver len - c3_w bod_w = sen_y + rec_y + bod_u->con_w; // body len - c3_w len_w = 4 + bod_w; // packet len - c3_y* pac_y = c3_malloc(len_w); - c3_y* bod_y = pac_y + 4; + c3_y sen_y = 2 << hed_u->sac_y; // sender len + c3_y rec_y = 2 << hed_u->rac_y; // receiver len + c3_y rog_y = ( c3y == hed_u->rel_o )? 6 : 0; // origin len + c3_w bod_w = rog_y + 1 + sen_y + rec_y + bod_u->con_s; // body len + c3_w len_w = 4 + bod_w; // packet len + c3_y* pac_y = c3_malloc(len_w); // output buf + c3_y* bod_y = pac_y + 4; // body cursor + c3_y* gob_y = bod_y + rog_y; // after origin - _ames_ship_of_chubs(bod_u->sen_d, sen_y, bod_y); - _ames_ship_of_chubs(bod_u->rec_d, rec_y, bod_y + sen_y); - - { - c3_y* con_y = bod_y + sen_y + rec_y; - memcpy(con_y, bod_u->con_y, bod_u->con_w); - } - - // if we updated the origin lane, we need to update the mug too - // - if ( c3y == mug_o ) { - hed_u->mug_l = _ames_mug_body(bod_w, bod_y); - } - - // now we can serialize the head + // serialize the head // _ames_etch_head(hed_u, pac_y); + // serialize the origin, if present + // + if ( rog_y ) { + c3_y rag_y[8] = {0}; + _ames_bytes_chub(rag_y, bod_u->rog_d); + memcpy(bod_y, rag_y, rog_y); + } + + // serialize the body + // + gob_y[0] = (bod_u->sic_y & 0xf) ^ ((bod_u->ric_y & 0xf) << 4); + + _ames_ship_of_chubs(bod_u->sen_d, sen_y, gob_y + 1); + _ames_ship_of_chubs(bod_u->rec_d, rec_y, gob_y + 1 + sen_y); + + memcpy(gob_y + 1 + sen_y + rec_y, bod_u->con_y, bod_u->con_s); + *out_y = pac_y; return len_w; } @@ -371,28 +401,29 @@ _ames_send(u3_pact* pac_u) */ u3_lane u3_ames_decode_lane(u3_atom lan) { - u3_noun cud, tag, pip, por; - - cud = u3ke_cue(lan); - u3x_trel(cud, &tag, &pip, &por); - c3_assert( c3__ipv4 == tag ); - u3_lane lan_u; - lan_u.pip_w = u3r_word(0, pip); + c3_d lan_d; - c3_assert( _(u3a_is_cat(por)) ); - c3_assert( por < 65536 ); - lan_u.por_s = por; + c3_assert( c3y == u3r_safe_chub(lan, &lan_d) ); + u3z(lan); - u3z(cud); + lan_u.pip_w = (c3_w)lan_d; + lan_u.por_s = (c3_s)(lan_d >> 32); return lan_u; } -/* u3_ames_encode_lane(): serialize lane to jammed noun +/* u3_ames_lane_to_chub(): serialize lane to double-word +*/ +c3_d +u3_ames_lane_to_chub(u3_lane lan) { + return ((c3_d)lan.por_s << 32) ^ (c3_d)lan.pip_w; +} + +/* u3_ames_encode_lane(): serialize lane to noun */ u3_atom u3_ames_encode_lane(u3_lane lan) { - return u3ke_jam(u3nt(c3__ipv4, u3i_words(1, &lan.pip_w), lan.por_s)); + return u3i_chub(u3_ames_lane_to_chub(lan)); } /* _ames_lane_into_cache(): put las for who into cache, including timestamp @@ -438,57 +469,18 @@ _ames_lane_from_cache(u3p(u3h_root) lax_p, u3_noun who) { static u3_noun _ames_serialize_packet(u3_panc* pac_u, c3_o dop_o) { - c3_o nal_o = c3n; - - // update the body's lane, if desired + // update the body's lane, if: + // - we're supposed to (dop_o) + // - it hasn't already been updated (rel_o) + // - sender is not a galaxy // - if ( c3y == dop_o ) { - // unpack (jam [(unit lane) body]) - // - u3_noun lon, bod; - { - //NOTE we checked for cue safety in _ames_recv_cb - // - u3_weak old = u3s_cue_xeno_with(pac_u->sam_u->sil_u, - pac_u->bod_u.con_w, - pac_u->bod_u.con_y); - u3x_cell(u3x_good(old), &lon, &bod); - u3k(lon); u3k(bod); - u3z(old); - } - - // only replace the lane if it was ~ - // - //NOTE this sets an opaque lane even in the "sender is galaxy" case, - // but that doesn't matter: ames.hoon ignores origin in that case, - // always using the appropriate galaxy lane instead. - // - if ( u3_nul == lon ) { - c3_w con_w; - c3_y* con_y; - - u3z(lon); - lon = u3nt(u3_nul, c3n, u3_ames_encode_lane(pac_u->ore_u)); - nal_o = c3y; - - // XX off-loom jam? - // - { - u3_noun jam = u3ke_jam(u3nc(lon, bod)); - con_w = u3r_met(3, jam); - con_y = c3_malloc(con_w); - u3r_bytes(0, con_w, con_y, jam); - u3z(jam); - } - - c3_free(pac_u->ptr_v); - pac_u->ptr_v = con_y; - pac_u->bod_u.con_y = con_y; - pac_u->bod_u.con_w = con_w; - } - else { - u3z(lon); u3z(bod); - } + if ( c3y == dop_o + && c3n == pac_u->hed_u.rel_o + && !( ( 256 > pac_u->bod_u.sen_d[0] ) + && ( 0 == pac_u->bod_u.sen_d[1] ) ) ) + { + pac_u->hed_u.rel_o = c3y; + pac_u->bod_u.rog_d = u3_ames_lane_to_chub(pac_u->ore_u); } // serialize the packet @@ -500,7 +492,7 @@ _ames_serialize_packet(u3_panc* pac_u, c3_o dop_o) c3_y* pac_y; c3_w len_w = _ames_etch_pack(&pac_u->hed_u, &pac_u->bod_u, - nal_o, &pac_y); + &pac_y); pac = u3i_bytes(len_w, pac_y); c3_free(pac_y); @@ -989,7 +981,8 @@ _ames_try_forward(u3_ames* sam_u, if ( (u3_none == lac) && (1000 < sam_u->sat_u.foq_d) ) { sam_u->sat_u.fod_d++; if ( 0 == (sam_u->sat_u.fod_d % 10000) ) { - u3l_log("ames: dropped %" PRIu64 " forwards total\n", sam_u->sat_u.fod_d); + u3l_log("ames: dropped %" PRIu64 " forwards total\n", + sam_u->sat_u.fod_d); } c3_free(hun_y); @@ -1042,7 +1035,7 @@ _ames_try_forward(u3_ames* sam_u, } } -/* _ames_hear(): parse a (potential packet), dispatch appropriately. +/* _ames_hear(): parse a (potential) packet, dispatch appropriately. */ static void _ames_hear(u3_ames* sam_u, @@ -1073,7 +1066,8 @@ _ames_hear(u3_ames* sam_u, { sam_u->sat_u.hed_d++; if ( 0 == (sam_u->sat_u.hed_d % 100) ) { - u3l_log("ames: %" PRIu64 " dropped, failed to read header\n", sam_u->sat_u.hed_d); + u3l_log("ames: %" PRIu64 " dropped, failed to read header\n", + sam_u->sat_u.hed_d); } c3_free(hun_y); @@ -1089,7 +1083,8 @@ _ames_hear(u3_ames* sam_u, { sam_u->sat_u.vet_d++; if ( 0 == (sam_u->sat_u.vet_d % 100) ) { - u3l_log("ames: %" PRIu64 " dropped for version mismatch\n", sam_u->sat_u.vet_d); + u3l_log("ames: %" PRIu64 " dropped for version mismatch\n", + sam_u->sat_u.vet_d); } c3_free(hun_y); @@ -1100,26 +1095,26 @@ _ames_hear(u3_ames* sam_u, c3_w bod_w = len_w - 4; c3_y* bod_y = hun_y + 4; - // ensure the mug is valid + // unpack and validate the body // - if ( _ames_mug_body(bod_w, bod_y) != hed_u.mug_l ) { - sam_u->sat_u.mut_d++; - if ( 0 == (sam_u->sat_u.mut_d % 100) ) { - u3l_log("ames: %" PRIu64 " dropped for invalid mug\n", sam_u->sat_u.mut_d); + if ( (c3n == _ames_sift_body(&hed_u, &bod_u, bod_w, bod_y)) ) { + sam_u->sat_u.bod_d++; + if ( 0 == (sam_u->sat_u.bod_d % 100) ) { + u3l_log("ames: %" PRIu64 " dropped, failed to read body\n", + sam_u->sat_u.bod_d); } c3_free(hun_y); return; } - // unpack and validate the body + // ensure the mug is valid // - if ( (c3n == _ames_sift_body(&hed_u, &bod_u, bod_w, bod_y)) - || !ur_cue_test_with(sam_u->tes_u, bod_u.con_w, bod_u.con_y) ) - { - sam_u->sat_u.bod_d++; - if ( 0 == (sam_u->sat_u.bod_d % 100) ) { - u3l_log("ames: %" PRIu64 " dropped, failed to read body\n", sam_u->sat_u.bod_d); + if ( bod_u.mug_l != hed_u.mug_l ) { + sam_u->sat_u.mut_d++; + if ( 0 == (sam_u->sat_u.mut_d % 100) ) { + u3l_log("ames: %" PRIu64 " dropped for invalid mug\n", + sam_u->sat_u.mut_d); } c3_free(hun_y);