Merge pull request #4051 from urbit/ted/ames-flat-revised

Ames flat packet format
This commit is contained in:
Joe Bryan 2020-12-03 14:12:56 -08:00 committed by GitHub
commit ce053facd5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 721 additions and 547 deletions

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:85a4e1625d528b5fdc88faeff4fd288a23d6fbf1c11a846fc8f8d5b3cd38370f
size 2118873
oid sha256:5af78cbe22c8311af47b070be953ca0ec50f383bc20140f38e3364aa56a4e2a2
size 2314689

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b3e9d1637efea5862a114ce320f6e14afeb1f9f418428e0490d9c079a9becc56
size 6712875
oid sha256:8e5d6fb3716e9e4dd3267a08aa70e8f782e722930eab3045a90c48b3e51a1668
size 6853071

View File

@ -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: {<sndr.packet>} -> {<rcvr.packet>}")
:: 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: <<sndr rcvr (jam [origin content])>>
::
:: 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
::
:: <<version checksum sndr-rank rcvr-rank encryption-type unused>>
:: 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 <<header body>>
::
(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]
--

View File

@ -29,23 +29,32 @@
[%event rcvr //newt/0v1n.2m9vh %hear hear-lane pac]~
:: +lane-to-ship: decode a ship from an aqua lane
::
:: Special-case one comet, since its address doesn't fit into a lane.
::
++ lane-to-ship
|= =lane:ames
^- ship
::
?- -.lane
%& p.lane
%| `ship``@`p.lane
%| =/ s `ship``@`p.lane
?. =(s 0xdead.beef.cafe)
s
~bosrym-podwyl-magnes-dacrys--pander-hablep-masrym-marbud
==
:: +ship-to-lane: encode a lane to look like it came from .ship
::
:: Never shows up as a galaxy, because Vere wouldn't know that either.
:: Special-case one comet, since its address doesn't fit into a lane.
::
++ ship-to-lane
|= =ship
^- lane:ames
::
[%| `address:ames``@`ship]
:- %|
^- address:ames ^- @
?. =(ship ~bosrym-podwyl-magnes-dacrys--pander-hablep-masrym-marbud)
ship
0xdead.beef.cafe
--
::
%+ aqua-vane-thread ~[%restore %send]

View File

@ -8,13 +8,19 @@
;< az=tid:spider
bind:m start-azimuth
;< ~ bind:m (spawn az ~bud)
;< ~ bind:m (spawn az ~marbud)
;< ~ bind:m (spawn az ~linnup-torsyx)
;< ~ bind:m (real-ship az ~bud)
::
;< ~ bind:m (spawn az ~marbud)
;< ~ bind:m (real-ship az ~marbud)
;< ~ bind:m (real-ship az ~linnup-torsyx)
::
;< ~ bind:m (real-ship az comet)
;< ~ bind:m (send-hi comet ~bud)
::
;< ~ bind:m (spawn az ~linnup-torsyx)
;< ~ bind:m (real-ship az ~linnup-torsyx)
::
;< ~ bind:m (send-hi comet ~linnup-torsyx)
;< ~ bind:m (send-hi ~linnup-torsyx comet)
::
;< ~ bind:m end-azimuth
(pure:m *vase)

View File

@ -6,31 +6,43 @@
::
=/ nec vane
=/ bud vane
=/ comet vane
::
=. our.nec ~nec
=. now.nec ~1111.1.1
=. eny.nec 0xdead.beef
=. our.nec ~nec
=. now.nec ~1111.1.1
=. eny.nec 0xdead.beef
=. life.ames-state.nec 2
=. rof.nec |=(* ``[%noun !>(*(list turf))])
::
=. our.bud ~bud
=. now.bud ~1111.1.1
=. eny.bud 0xbeef.dead
=. rof.bud |=(* ``[%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
=. rof.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
=. rof.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
"; {<our.comet>} is your neighbor"
==
:* ~[//unix] %pass /bone/(scot %p our.comet)/1
%g %plea our.comet plea
== ==
!> moves1
==
::
++ test-message-flow ^- tang
:: ~nec -> %plea -> ~bud
::

View File

@ -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);