2011-12-14 19:21:19 +00:00
|
|
|
#lang racket/base
|
|
|
|
|
|
|
|
;; Simple imperative UDP server harness.
|
|
|
|
|
2011-12-15 17:22:59 +00:00
|
|
|
(require racket/match)
|
2011-12-14 19:21:19 +00:00
|
|
|
(require racket/udp)
|
2011-12-15 21:21:07 +00:00
|
|
|
(require (only-in srfi/1 append-reverse))
|
2012-02-15 15:41:15 +00:00
|
|
|
(require "../racket-matrix/dump-bytes.rkt")
|
2011-12-14 19:21:19 +00:00
|
|
|
|
|
|
|
(provide (struct-out udp-packet)
|
2011-12-16 16:42:06 +00:00
|
|
|
message-handlers
|
2011-12-14 19:21:19 +00:00
|
|
|
start-udp-service)
|
|
|
|
|
|
|
|
;; A UdpPacket is a (udp-packet Bytes String Uint16), and represents
|
|
|
|
;; either a received UDP packet and the source of the packet, or a UDP
|
|
|
|
;; packet ready to be sent along with the address to which it should
|
|
|
|
;; be sent.
|
2011-12-15 18:00:37 +00:00
|
|
|
(struct udp-packet (body host port) #:prefab)
|
2011-12-14 19:21:19 +00:00
|
|
|
|
2011-12-16 16:42:06 +00:00
|
|
|
;; TODO: Should packet->message be permitted to examine (or possibly
|
2011-12-15 17:18:14 +00:00
|
|
|
;; even transform!) the ServerState?
|
|
|
|
|
2011-12-16 16:35:17 +00:00
|
|
|
;; A Handler is a Message ServerState -> ListOf<Message> ServerState.
|
2011-12-15 18:02:10 +00:00
|
|
|
|
2011-12-16 16:42:06 +00:00
|
|
|
(define-syntax message-handlers
|
2011-12-15 18:02:10 +00:00
|
|
|
(syntax-rules ()
|
|
|
|
((_ old-state-var (pattern body ...) ...)
|
|
|
|
(list (cons (match-lambda (pattern #t) (_ #f))
|
|
|
|
(lambda (v old-state-var)
|
|
|
|
(match v
|
|
|
|
(pattern body ...))))
|
|
|
|
...))))
|
|
|
|
|
2011-12-14 19:21:19 +00:00
|
|
|
;; Starts a generic request/reply UDP server on the given port.
|
|
|
|
(define (start-udp-service
|
|
|
|
port-number ;; Uint16
|
2011-12-16 16:42:06 +00:00
|
|
|
packet->message ;; UdpPacket -> Message
|
|
|
|
;;--------------------------------------------------
|
|
|
|
outbound-message? ;; Message -> Boolean
|
|
|
|
message->packet ;; Message -> UdpPacket
|
|
|
|
;;--------------------------------------------------
|
|
|
|
message-handlers ;; ListOf<Pair<Message -> Boolean, Handler>>
|
2011-12-15 18:02:10 +00:00
|
|
|
default-handler ;; Handler
|
2011-12-14 19:21:19 +00:00
|
|
|
initial-state ;; ServerState
|
|
|
|
#:packet-size-limit
|
2011-12-16 16:42:06 +00:00
|
|
|
[packet-size-limit 65536])
|
2011-12-14 19:21:19 +00:00
|
|
|
(define s (udp-open-socket #f #f)) ;; the server socket
|
|
|
|
(udp-bind! s #f port-number) ;; bind it to the port we were given
|
|
|
|
|
2011-12-16 16:42:06 +00:00
|
|
|
(set! message-handlers ;; TEMPORARY while I figure out I/O
|
|
|
|
(cons (cons outbound-message?
|
|
|
|
(lambda (message state)
|
|
|
|
(define p (message->packet message))
|
2011-12-15 18:02:10 +00:00
|
|
|
(match-define (udp-packet body host port) p)
|
|
|
|
(printf "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<~n~v~n" body)
|
|
|
|
(dump-bytes! body (bytes-length body))
|
|
|
|
(flush-output)
|
|
|
|
(udp-send-to s host port body)
|
|
|
|
(values '() state)))
|
2011-12-16 16:42:06 +00:00
|
|
|
message-handlers))
|
2011-12-15 18:02:10 +00:00
|
|
|
|
2011-12-16 16:42:06 +00:00
|
|
|
(define (dispatch-messages messages next-messages-rev old-state)
|
|
|
|
(if (null? messages)
|
|
|
|
(check-for-io (reverse next-messages-rev) old-state)
|
|
|
|
(let ((message (car messages)))
|
|
|
|
(define-values (new-messages new-state)
|
|
|
|
(let search ((handlers message-handlers))
|
2011-12-15 18:02:10 +00:00
|
|
|
(cond
|
2011-12-16 16:42:06 +00:00
|
|
|
[(null? handlers) (default-handler message old-state)]
|
|
|
|
[((caar handlers) message) ((cdar handlers) message old-state)]
|
2011-12-15 18:02:10 +00:00
|
|
|
[else (search (cdr handlers))])))
|
2011-12-16 16:42:06 +00:00
|
|
|
(dispatch-messages (cdr messages)
|
|
|
|
(append-reverse new-messages next-messages-rev)
|
|
|
|
new-state))))
|
2011-12-15 18:02:10 +00:00
|
|
|
|
2011-12-16 16:42:06 +00:00
|
|
|
(define (check-for-io pending-messages old-state)
|
2011-12-14 19:21:19 +00:00
|
|
|
(define buffer (make-bytes packet-size-limit))
|
2011-12-16 16:42:06 +00:00
|
|
|
(define new-messages
|
2011-12-15 21:21:07 +00:00
|
|
|
(sync (handle-evt (udp-receive!-evt s buffer)
|
|
|
|
(match-lambda
|
|
|
|
[(list packet-length source-hostname source-port)
|
|
|
|
(define packet (subbytes buffer 0 packet-length))
|
|
|
|
(printf ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>~n~v~n" packet)
|
|
|
|
(dump-bytes! buffer packet-length)
|
|
|
|
(flush-output)
|
2011-12-14 19:21:19 +00:00
|
|
|
|
2011-12-15 21:21:07 +00:00
|
|
|
(define packet-and-source
|
|
|
|
(udp-packet packet source-hostname source-port))
|
2011-12-16 16:42:06 +00:00
|
|
|
(define message (packet->message packet-and-source))
|
|
|
|
(list message)]))
|
|
|
|
(if (null? pending-messages)
|
2011-12-15 21:21:07 +00:00
|
|
|
never-evt ;; Nothing waiting to be done, don't wake up until sth external arrives
|
|
|
|
(handle-evt (system-idle-evt)
|
|
|
|
(lambda (dummy) '())))))
|
2011-12-16 16:42:06 +00:00
|
|
|
(dispatch-messages (append new-messages pending-messages) '() old-state))
|
2011-12-14 19:21:19 +00:00
|
|
|
|
2011-12-15 21:21:07 +00:00
|
|
|
(check-for-io '() initial-state))
|