#!/usr/bin/env racket #lang racket ; vim:syntax=racket (require json "iputil.rkt" "unix-socket.rkt" "msg.rkt") ;; info : Peer ;; sock-in : Input-Port ;; sock-out : Output-Port (struct peer-conn [info sock-in sock-out] #:transparent) ;; alist : [Listof [Cons IP Route]] (struct router [(alist #:mutable)] #:transparent) ;; -> Router (define (make-router) (router '())) ;; Router Route IP -> Void (define (router-add! rs r src) (set-router-alist! rs (cons (cons src r) (router-alist rs)))) ;; Router IP -> (U IP #f) (define (router-find-best rs src) #f) ;; Str [Listof Peer-Conn] -> Void ;; -- ;; Runs router logic, given a list of peer connections. (define (run-router/conns ans peer-conns) (define mail (make-channel)) (define peer-threads (for/list ([pc (in-list peer-conns)]) (match-define (peer-conn peer sock-in sock-out) pc) (thread (λ () (define buf (make-bytes 65536)) (let loop () (define len (read-bytes-avail! buf sock-in)) (printf "got ~a bytes from ~a...\n" len peer) (define msg (bytes->msg (subbytes buf 0 len))) (channel-put mail (list peer msg)) (loop)))))) (define (ip->peer-conn ip) (findf (λ (p) (equal? ip (peer-ip (peer-conn-info p)))) peer-conns)) (define router (make-router)) (define (loop) (match-define (list src-peer msg) (channel-get mail)) (printf "====\nfrom ~a:\n~s\n" src-peer msg) (match msg [(msg:update src dst r) (router-add! router r src)] [(msg:data src dst data) (define-values [dst-peer resp-msg] (match (router-find-best router dst) [#f (values peer (msg:no-route src dst))] [dst-peer-ip (values (ip->peer-conn dst-peer-ip) msg)])) (printf "----\nwant to send back ~a to ~a\n" dst-peer resp-msg)] [_ (printf "----\nignored\n")]) (loop)) (printf "waiting for messages...\n") (loop)) ;; Str [Listof Peer] -> ;; Router main (define (run-router asn peers) (displayln asn) (map displayln peers) (displayln "------------") (with-handlers ([exn:break? (λ (e) (printf "time to die.\n"))]) (run-router/conns asn (for/list ([peer (in-list peers)]) (define-values [sock-in sock-out] (unix-socket-connect (ip->string (peer-ip peer)) 'SOCK-SEQPACKET)) (peer-conn peer sock-in sock-out))))) (module+ main (command-line #:program "router" #:args (asn . peers) (with-output-to-file "log.txt" #:exists 'replace (λ () ;; Run the router (run-router asn (map string->peer peers)))))) (module+ test (define-values [in1 out1] (make-pipe)) (define-values [in2 out2] (make-pipe)) (define p1 (peer-conn (string->peer "1.2.3.4-cust") in1 out1)) (define p2 (peer-conn (string->peer "1.2.3.5-peer") in2 out2)) ; (define abort-router (run-router/conns "123" (list p1 p2)) (void (write-string "{\"a\": 1, \"b\": [1,2,3]}" out1)))