2021-06-08 07:33:56 +00:00
|
|
|
#lang racket/base
|
|
|
|
;;; SPDX-License-Identifier: LGPL-3.0-or-later
|
2022-01-16 08:48:18 +00:00
|
|
|
;;; SPDX-FileCopyrightText: Copyright © 2021-2022 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
|
2021-06-08 07:33:56 +00:00
|
|
|
|
|
|
|
(provide make-tunnel-relay
|
|
|
|
accept-bytes
|
2021-06-10 08:53:30 +00:00
|
|
|
run-relay)
|
2021-06-08 07:33:56 +00:00
|
|
|
|
|
|
|
(require racket/match)
|
|
|
|
(require preserves)
|
|
|
|
|
|
|
|
(require "main.rkt")
|
2021-06-10 09:42:07 +00:00
|
|
|
(require (only-in "actor.rkt" current-turn))
|
2021-06-08 07:33:56 +00:00
|
|
|
(require "engine.rkt")
|
2021-06-09 13:06:58 +00:00
|
|
|
(require "rewrite.rkt")
|
2021-09-24 11:02:51 +00:00
|
|
|
(require "schemas/protocol.rkt")
|
2021-07-01 07:40:52 +00:00
|
|
|
(require (prefix-in sturdy: "schemas/sturdy.rkt"))
|
2021-06-08 07:33:56 +00:00
|
|
|
|
2021-06-10 14:46:28 +00:00
|
|
|
(define-logger syndicate/relay)
|
|
|
|
|
2021-06-08 07:33:56 +00:00
|
|
|
;;---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
(struct inbound (local-handle imported))
|
|
|
|
|
2021-06-08 16:01:27 +00:00
|
|
|
(struct wire-symbol (oid ref [count #:mutable])
|
|
|
|
#:methods gen:custom-write
|
|
|
|
[(define (write-proc ws port mode)
|
|
|
|
(fprintf port "#<wire-symbol:~a/~a ~v>"
|
|
|
|
(wire-symbol-oid ws)
|
|
|
|
(wire-symbol-count ws)
|
|
|
|
(wire-symbol-ref ws)))])
|
2021-06-08 07:33:56 +00:00
|
|
|
|
|
|
|
(struct membrane (oid-map ref-map))
|
|
|
|
|
|
|
|
;; There are other kinds of relay. This one has exactly two participants connected to each other.
|
|
|
|
(struct tunnel-relay (facet
|
|
|
|
name
|
|
|
|
[read-buffer #:mutable]
|
|
|
|
packet-writer
|
|
|
|
inbound-assertions
|
|
|
|
outbound-assertions
|
|
|
|
exported-references
|
|
|
|
imported-references
|
|
|
|
[next-local-oid #:mutable]
|
|
|
|
[pending-turn-rev #:mutable]
|
|
|
|
)
|
|
|
|
#:transparent)
|
|
|
|
|
|
|
|
(struct relay-entity (relay oid) #:transparent)
|
|
|
|
|
|
|
|
;;---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
(define *inert-ref*
|
|
|
|
(entity-ref *dead-facet*
|
|
|
|
(entity #:name '*inert-ref*)
|
|
|
|
'()))
|
|
|
|
|
|
|
|
;;---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
(define (make-membrane)
|
|
|
|
(membrane (make-hash) (make-hasheq)))
|
|
|
|
|
|
|
|
(define (grab m getter key transient? f)
|
|
|
|
(let ((ws (hash-ref (getter m)
|
|
|
|
key
|
|
|
|
(lambda ()
|
|
|
|
(define ws (f))
|
|
|
|
(hash-set! (membrane-oid-map m) (wire-symbol-oid ws) ws)
|
|
|
|
(hash-set! (membrane-ref-map m) (wire-symbol-ref ws) ws)
|
|
|
|
ws))))
|
|
|
|
(when (not transient?) (set-wire-symbol-count! ws (+ (wire-symbol-count ws) 1)))
|
|
|
|
ws))
|
|
|
|
|
|
|
|
(define (drop m ws)
|
|
|
|
(set-wire-symbol-count! ws (- (wire-symbol-count ws) 1))
|
|
|
|
(when (zero? (wire-symbol-count ws))
|
|
|
|
(hash-remove! (membrane-oid-map m) (wire-symbol-oid ws))
|
|
|
|
(hash-remove! (membrane-ref-map m) (wire-symbol-ref ws))))
|
|
|
|
|
|
|
|
;;---------------------------------------------------------------------------
|
|
|
|
|
2021-06-10 09:42:07 +00:00
|
|
|
(define (make-tunnel-relay name packet-writer)
|
|
|
|
(tunnel-relay (turn-active-facet (current-turn))
|
2021-06-10 08:53:30 +00:00
|
|
|
name
|
|
|
|
#""
|
|
|
|
packet-writer
|
|
|
|
(make-hash)
|
|
|
|
(make-hash)
|
|
|
|
(make-membrane)
|
|
|
|
(make-membrane)
|
|
|
|
0
|
|
|
|
'()))
|
2021-06-08 07:33:56 +00:00
|
|
|
|
|
|
|
(define accept-bytes
|
|
|
|
(lambda (tr bs)
|
|
|
|
(turn! (tunnel-relay-facet tr)
|
2021-06-10 09:42:07 +00:00
|
|
|
(lambda ()
|
2021-06-08 07:33:56 +00:00
|
|
|
(define buffer (if (positive? (bytes-length (tunnel-relay-read-buffer tr)))
|
|
|
|
(bytes-append (tunnel-relay-read-buffer tr) bs)
|
|
|
|
bs))
|
|
|
|
(set-tunnel-relay-read-buffer! tr buffer)
|
|
|
|
(define p (open-input-bytes buffer))
|
|
|
|
(let read-more ()
|
|
|
|
(define start-pos (file-position p))
|
|
|
|
(match (read-preserve/binary p
|
|
|
|
#:read-syntax? #f
|
2021-09-24 11:02:51 +00:00
|
|
|
#:decode-embedded sturdy:parse-WireRef!
|
2021-06-08 07:33:56 +00:00
|
|
|
#:on-short (lambda () eof))
|
|
|
|
[(? eof-object?)
|
|
|
|
(when (positive? start-pos)
|
|
|
|
(set-tunnel-relay-read-buffer! tr (subbytes buffer start-pos)))]
|
|
|
|
[packet
|
2021-06-10 09:42:07 +00:00
|
|
|
(handle-packet tr packet)
|
2021-06-08 07:33:56 +00:00
|
|
|
(read-more)]))))))
|
|
|
|
|
|
|
|
(define (lookup-local tr local-oid)
|
|
|
|
(define ws (hash-ref (membrane-oid-map (tunnel-relay-exported-references tr)) local-oid #f))
|
|
|
|
(if ws (wire-symbol-ref ws) *inert-ref*))
|
|
|
|
|
2021-06-10 09:42:07 +00:00
|
|
|
(define (rewrite-in tr assertion)
|
|
|
|
(define imported '())
|
|
|
|
(define (save! ws) (set! imported (cons ws imported)))
|
|
|
|
(define rewritten ((map-embeddeds (lambda (r) (embedded (rewrite-ref-in tr r save!)))) assertion))
|
|
|
|
(values rewritten imported))
|
2021-06-08 07:33:56 +00:00
|
|
|
|
|
|
|
(define ref-attenuation-refinements (make-weak-hasheq))
|
|
|
|
|
2021-06-10 09:42:07 +00:00
|
|
|
(define (rewrite-ref-in tr wire-ref save!)
|
|
|
|
(match wire-ref
|
|
|
|
[(sturdy:WireRef-mine (sturdy:Oid oid))
|
|
|
|
(define ws (grab (tunnel-relay-imported-references tr)
|
|
|
|
membrane-oid-map
|
|
|
|
oid
|
|
|
|
#f
|
|
|
|
(lambda ()
|
|
|
|
(wire-symbol oid (turn-ref this-turn (make-relay-entity tr oid)) 0))))
|
|
|
|
(save! ws)
|
|
|
|
(wire-symbol-ref ws)]
|
|
|
|
[(sturdy:WireRef-yours (sturdy:Oid oid) attenuation)
|
|
|
|
(define r (lookup-local tr oid))
|
|
|
|
(if (or (null? attenuation) (eq? *inert-ref* r))
|
|
|
|
r
|
|
|
|
(hash-ref! (hash-ref! ref-attenuation-refinements r make-hash)
|
|
|
|
attenuation
|
|
|
|
(lambda () (apply attenuate-entity-ref r attenuation))))]))
|
|
|
|
|
|
|
|
(define (handle-packet tr packet)
|
|
|
|
(match (parse-Turn packet)
|
|
|
|
[(? eof-object?) (error 'handle-packet "Invalid IO.Turn")]
|
|
|
|
[(Turn wire-turn)
|
2021-06-10 14:46:28 +00:00
|
|
|
(log-syndicate/relay-debug "--> ~a" (preserve->string packet))
|
2021-06-10 09:42:07 +00:00
|
|
|
(for [(ev (in-list wire-turn))]
|
|
|
|
(match-define (TurnEvent (Oid oid) event) ev)
|
2021-06-08 07:33:56 +00:00
|
|
|
(define r (lookup-local tr oid))
|
2021-06-10 09:42:07 +00:00
|
|
|
(match event
|
|
|
|
[(Event-Assert (Assert (Assertion assertion) (Handle remote-handle)))
|
|
|
|
(define-values (a imported) (rewrite-in tr assertion))
|
|
|
|
(hash-set! (tunnel-relay-inbound-assertions tr)
|
|
|
|
remote-handle
|
|
|
|
(inbound (turn-assert! this-turn r a)
|
|
|
|
imported))]
|
|
|
|
[(Event-Retract (Retract (Handle remote-handle)))
|
|
|
|
(define i (hash-ref (tunnel-relay-inbound-assertions tr) remote-handle #f))
|
|
|
|
(when (not i) (error 'handle-packet "Peer retracted invalid handle ~a" remote-handle))
|
|
|
|
(hash-remove! (tunnel-relay-inbound-assertions tr) remote-handle)
|
|
|
|
(for [(ws (in-list (inbound-imported i)))]
|
|
|
|
(drop (tunnel-relay-imported-references tr) ws))
|
|
|
|
(turn-retract! this-turn (inbound-local-handle i))]
|
|
|
|
[(Event-Message (Message (Assertion body)))
|
|
|
|
(define-values (a imported) (rewrite-in tr body))
|
|
|
|
(when (not (null? imported))
|
|
|
|
(error 'handle-packet "Cannot receive transient reference"))
|
|
|
|
(turn-message! this-turn r a)]
|
|
|
|
[(Event-Sync (Sync peer))
|
|
|
|
(define imported '())
|
|
|
|
(define (save! ws) (set! imported (cons ws imported)))
|
|
|
|
(define k (rewrite-ref-in tr peer save!))
|
|
|
|
(turn-sync! this-turn
|
|
|
|
r
|
|
|
|
(lambda (_true)
|
|
|
|
(turn-message! this-turn k #t)
|
|
|
|
(for [(ws (in-list imported))]
|
|
|
|
(drop (tunnel-relay-imported-references tr) ws))))]))]))
|
2021-06-08 07:33:56 +00:00
|
|
|
|
2021-06-08 16:01:27 +00:00
|
|
|
(define (send-event tr oid event)
|
2021-06-08 07:33:56 +00:00
|
|
|
(when (null? (tunnel-relay-pending-turn-rev tr))
|
|
|
|
(queue-task! (actor-engine (facet-actor (tunnel-relay-facet tr)))
|
|
|
|
(lambda ()
|
2021-06-09 12:53:41 +00:00
|
|
|
(turn! (tunnel-relay-facet tr)
|
2021-06-10 09:42:07 +00:00
|
|
|
(lambda ()
|
2021-06-09 12:53:41 +00:00
|
|
|
(define pending (Turn (reverse (tunnel-relay-pending-turn-rev tr))))
|
|
|
|
(set-tunnel-relay-pending-turn-rev! tr '())
|
2021-06-10 14:46:28 +00:00
|
|
|
(log-syndicate/relay-debug "<-- ~a"
|
|
|
|
(preserve->string (->preserve pending)))
|
2021-06-09 12:53:41 +00:00
|
|
|
(parse-Turn! (->preserve pending))
|
|
|
|
((tunnel-relay-packet-writer tr)
|
|
|
|
(preserve->bytes (->preserve pending)
|
|
|
|
#:canonicalizing? #t
|
|
|
|
#:write-annotations? #f
|
2021-09-24 11:02:51 +00:00
|
|
|
#:encode-embedded ->preserve)))))))
|
2021-06-08 16:01:27 +00:00
|
|
|
(set-tunnel-relay-pending-turn-rev! tr (cons (TurnEvent (Oid oid) event)
|
|
|
|
(tunnel-relay-pending-turn-rev tr))))
|
2021-06-08 07:33:56 +00:00
|
|
|
|
|
|
|
(define (rewrite-out tr assertion transient?)
|
|
|
|
(define exported '())
|
|
|
|
(define (save! ws) (set! exported (cons ws exported)))
|
|
|
|
(define rewritten
|
|
|
|
((map-embeddeds (lambda (r) (embedded (rewrite-ref-out tr r transient? save!)))) assertion))
|
|
|
|
(values rewritten exported))
|
|
|
|
|
|
|
|
(define (rewrite-ref-out* tr local-ref transient? save!)
|
|
|
|
(define ws (grab (tunnel-relay-exported-references tr)
|
|
|
|
membrane-ref-map
|
|
|
|
local-ref
|
|
|
|
transient?
|
|
|
|
(lambda ()
|
2021-07-08 18:55:14 +00:00
|
|
|
(when transient?
|
|
|
|
(error 'rewrite-ref-out* "Cannot send transient reference"))
|
2021-06-08 07:33:56 +00:00
|
|
|
(define oid (tunnel-relay-next-local-oid tr))
|
|
|
|
(set-tunnel-relay-next-local-oid! tr (+ oid 1))
|
|
|
|
(wire-symbol oid local-ref 0))))
|
|
|
|
(save! ws)
|
2021-06-08 14:09:59 +00:00
|
|
|
(sturdy:WireRef-mine (sturdy:Oid (wire-symbol-oid ws))))
|
2021-06-08 07:33:56 +00:00
|
|
|
|
|
|
|
(define (rewrite-ref-out tr local-ref transient? save!)
|
|
|
|
(define re (entity-data (entity-ref-target local-ref)))
|
|
|
|
(cond [(or (not (relay-entity? re)) (not (eq? (relay-entity-relay re) tr)))
|
|
|
|
(rewrite-ref-out* tr local-ref transient? save!)]
|
|
|
|
[(null? (entity-ref-attenuation local-ref))
|
2021-06-08 14:09:59 +00:00
|
|
|
(sturdy:WireRef-yours (sturdy:Oid (relay-entity-oid re)) '())]
|
2021-06-08 07:33:56 +00:00
|
|
|
[else
|
|
|
|
;; we may trust the peer to enforce attenuation on our
|
|
|
|
;; behalf, in which case we can return (sturdy:WireRef-yours
|
|
|
|
;; (relay-entity-oid re) (entity-ref-attenuation local-ref))
|
|
|
|
;; here, but for now we don't.
|
|
|
|
(rewrite-ref-out* tr local-ref transient? save!)]))
|
|
|
|
|
|
|
|
(define (release-ref-out tr ws)
|
|
|
|
(drop (tunnel-relay-exported-references tr) ws))
|
|
|
|
|
|
|
|
(define (register tr assertion maybe-handle)
|
|
|
|
(define-values (rewritten exported) (rewrite-out tr assertion (eq? maybe-handle #f)))
|
|
|
|
(when maybe-handle (hash-set! (tunnel-relay-outbound-assertions tr) maybe-handle exported))
|
|
|
|
rewritten)
|
|
|
|
|
|
|
|
(define (deregister tr handle)
|
|
|
|
(for [(ws (in-list (hash-ref (tunnel-relay-outbound-assertions tr) handle '())))]
|
|
|
|
(release-ref-out tr ws))
|
|
|
|
(hash-remove! (tunnel-relay-outbound-assertions tr) handle))
|
|
|
|
|
|
|
|
(define (make-relay-entity tr oid)
|
2021-06-08 16:01:27 +00:00
|
|
|
(entity #:name
|
|
|
|
(list (tunnel-relay-name tr) oid)
|
|
|
|
#:assert
|
2021-06-10 09:42:07 +00:00
|
|
|
(lambda (assertion handle)
|
2021-06-08 16:01:27 +00:00
|
|
|
(send-event tr oid (Event-Assert
|
|
|
|
(Assert (Assertion (register tr assertion handle))
|
|
|
|
(Handle handle)))))
|
|
|
|
#:retract
|
2021-06-10 09:42:07 +00:00
|
|
|
(lambda (handle)
|
2021-06-08 16:01:27 +00:00
|
|
|
(deregister tr handle)
|
|
|
|
(send-event tr oid (Event-Retract (Retract (Handle handle)))))
|
|
|
|
#:message
|
2021-06-10 09:42:07 +00:00
|
|
|
(lambda (body)
|
2021-06-08 16:01:27 +00:00
|
|
|
(send-event tr oid (Event-Message (Message (Assertion (register tr body #f))))))
|
|
|
|
#:sync
|
2021-06-10 09:42:07 +00:00
|
|
|
(lambda (peer)
|
2021-06-08 16:01:27 +00:00
|
|
|
(define exported #f)
|
|
|
|
(define (save! ws) (set! exported ws))
|
|
|
|
(define spe (sync-peer-entity tr oid peer (lambda () exported)))
|
|
|
|
(send-event tr oid (Event-Sync
|
2021-06-08 14:09:59 +00:00
|
|
|
(Sync (rewrite-ref-out tr (turn-ref this-turn spe) #f save!)))))
|
2021-06-08 16:01:27 +00:00
|
|
|
#:data
|
|
|
|
(relay-entity tr oid)))
|
2021-06-08 07:33:56 +00:00
|
|
|
|
|
|
|
(define (sync-peer-entity tr oid peer get-export)
|
|
|
|
(define handle-map (make-hash))
|
2021-06-08 16:01:27 +00:00
|
|
|
(entity #:name
|
|
|
|
(list (tunnel-relay-name tr) oid 'sync)
|
|
|
|
#:assert
|
2021-06-10 09:42:07 +00:00
|
|
|
(lambda (assertion handle)
|
2021-06-08 16:01:27 +00:00
|
|
|
(hash-set! handle-map handle (turn-assert! this-turn peer assertion)))
|
|
|
|
#:retract
|
2021-06-10 09:42:07 +00:00
|
|
|
(lambda (handle)
|
2021-06-08 16:01:27 +00:00
|
|
|
(turn-retract! this-turn (hash-ref handle-map handle))
|
|
|
|
(hash-remove! handle-map handle))
|
|
|
|
#:message
|
2021-06-10 09:42:07 +00:00
|
|
|
(lambda (body)
|
2021-06-08 16:01:27 +00:00
|
|
|
(release-ref-out tr (get-export))
|
|
|
|
(turn-message! this-turn peer body))
|
|
|
|
#:sync
|
2021-06-10 09:42:07 +00:00
|
|
|
(lambda (peer-k)
|
2021-06-08 16:01:27 +00:00
|
|
|
(turn-sync! this-turn peer peer-k))))
|
2021-06-08 07:33:56 +00:00
|
|
|
|
2021-06-10 08:53:30 +00:00
|
|
|
(define (run-relay #:packet-writer packet-writer
|
|
|
|
#:setup-inputs setup-inputs
|
|
|
|
#:then [then #f]
|
|
|
|
#:name [name (gensym 'relay)]
|
|
|
|
#:initial-oid [initial-oid #f]
|
|
|
|
#:initial-ref [initial-ref #f])
|
2021-06-10 09:42:07 +00:00
|
|
|
(define tr (make-tunnel-relay name packet-writer))
|
|
|
|
(setup-inputs tr)
|
|
|
|
(when initial-ref (rewrite-ref-out tr
|
|
|
|
(if (procedure? initial-ref)
|
|
|
|
(initial-ref)
|
|
|
|
initial-ref)
|
|
|
|
#f
|
|
|
|
(lambda (_ws) (void))))
|
|
|
|
(when then
|
|
|
|
(turn-assert! this-turn
|
|
|
|
then
|
|
|
|
(and initial-oid
|
|
|
|
(embedded
|
|
|
|
(rewrite-ref-in tr
|
|
|
|
(sturdy:WireRef-mine
|
|
|
|
(sturdy:Oid initial-oid))
|
|
|
|
(lambda (_ws) (void))))))))
|