diff --git a/os-udp-test.rkt b/os-udp-test.rkt new file mode 100644 index 0000000..fb7a052 --- /dev/null +++ b/os-udp-test.rkt @@ -0,0 +1,19 @@ +#lang racket/base + +(require racket/match) +(require "os-userland-stdlib.rkt") +(require "os-udp.rkt") + +(ground-vm/userland/stdlib + (lambda () + (spawn display-driver) + (spawn read-line-driver) + (spawn udp-driver) + (poll) + (define s (rpc `(udp new 5555 65536))) + (let loop () + (wait (message-handlers + [(udp-packet source (and sink (? (lambda (x) (eq? x s)))) body) + (display "UDP!\n") + (send (udp-packet sink source body)) + (loop)]))))) \ No newline at end of file diff --git a/os-udp.rkt b/os-udp.rkt new file mode 100644 index 0000000..2c18bd1 --- /dev/null +++ b/os-udp.rkt @@ -0,0 +1,72 @@ +#lang racket/base + +;; UDP drivers for os.rkt + +(require racket/match) +(require racket/udp) +(require "dump-bytes.rkt") +(require "os-userland-stdlib.rkt") + +(provide (struct-out udp-address) + (struct-out udp-packet) + udp-driver) + +;; A UdpAddress is one of +;; -- a Symbol, representing a local socket +;; -- a (udp-address String Uint16), representing a remote socket +(struct udp-address (host port) #:prefab) + +;; A UdpPacket is a (udp-packet UdpAddress UdpAddress Bytes), and +;; represents a packet appearing on our local "subnet" of the full UDP +;; network, complete with source, destination and contents. +(struct udp-packet (source destination body) #:prefab) + +;; TODO: BUG?: Routing packets between two local sockets won't work +;; because the patterns aren't set up to recognise that situation. + +(define (udp-driver) + (rpc-service + [`(udp new ,port-number ,buffer-size) + (define s (udp-open-socket #f #f)) + (when port-number + (udp-bind! s #f port-number)) + (define sname (gensym 'udp-socket)) ;; !!! %%% TODO ? + (spawn (udp-sender sname s)) + (spawn (udp-receiver sname s buffer-size)) + (spawn (udp-closer sname s)) + sname])) + +(define ((for-me? sname) x) (eq? sname x)) + +(define ((udp-sender sname s)) + (let loop () + (wait (message-handlers + [`(close ,(? (for-me? sname))) + (void)] + [(udp-packet (? (for-me? sname)) (udp-address host port) body) + (meta-send (lambda () + (printf "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<~n~v~n" body) + (dump-bytes! body (bytes-length body)) + (flush-output) + (udp-send-to s host port body))) + (loop)])))) + +(define ((udp-receiver sname s buffer-size)) + (define buffer (make-bytes buffer-size)) + (let loop () + (wait (message-handlers + [`(close ,(? (for-me? sname))) + (void)]) + (meta-message-handlers + [((udp-receive!-evt s buffer) => (list packet-length host port)) + (define packet (subbytes buffer 0 packet-length)) + (printf ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>~n~v~n" packet) + (dump-bytes! buffer packet-length) + (flush-output) + (send (udp-packet (udp-address host port) sname packet)) + (loop)])))) + +(define ((udp-closer sname s)) + (wait (message-handlers + [`(close ,(? (for-me? sname))) + (udp-close s)])))