#lang scheme/base
(require "main.ss" srfi/78)
(provide run-tests)
(define (wait-idle)
(sync (system-idle-evt)))
(define (make-junk len)
(let ((buf (make-bytes len)))
(do ((i 0 (add1 i)))
((= i len) buf)
(bytes-set! buf i (random 255)))))
(define (bind-server sock where)
(with-handlers*
((exn:fail:socket?
(lambda (e)
(if (eq? (exn:fail:socket-errno e) EADDRINUSE)
#f
(raise e)))))
(socket-bind sock where)))
(define (socket-maker make-sock make-addr make-val)
(lambda (lo hi)
(let ((sock (make-sock)))
(socket-setsockopt sock SOL_SOCKET SO_REUSEADDR #t)
(let lp ((x lo))
(if (< x hi)
(if (bind-server sock (make-addr x))
(make-val sock)
(lp (add1 x)))
(error 'socket-maker "can't bind"))))))
(define tcp-server-socket
(socket-maker
socket
(lambda (port) (inet4-address INADDR_LOOPBACK port))
(lambda (sock) (socket-listen sock 1) sock)))
(define unix-server-socket
(socket-maker
(lambda () (socket PF_UNIX))
(lambda (x) (string->path (format "/tmp/test-~a~a" x (random))))
(lambda (sock) (socket-listen sock 1) sock)))
(define udp-server-socket
(socket-maker
(lambda () (socket PF_INET SOCK_DGRAM))
(lambda (port) (inet4-address INADDR_ANY port))
(lambda (sock) sock)))
(define (stream-server sock)
(define buf (make-bytes 4096))
(let-values (((cli cliaddr) (socket-accept sock)))
(let lp ()
(let ((ilen (socket-recv cli buf)))
(if (> ilen 0)
(begin
(socket-send-all cli buf 0 ilen)
(lp))
(begin
(socket-close cli)
(stream-server sock)))))))
(define (stream-client srv pf len)
(define-values (sbuf rbuf) (values (make-junk len) (make-bytes len)))
(define sock (socket pf SOCK_STREAM))
(socket-connect sock srv)
(check (socket-send-all sock sbuf) => (bytes-length sbuf))
(check (socket-recv-all sock rbuf) => (bytes-length rbuf))
(check (equal? rbuf sbuf) => #t)
(socket-close sock)
(check (socket-closed? sock) => #t))
(define (dgram-server sock)
(define buf (make-bytes 1500))
(let lp ()
(let-values (((ilen peer) (socket-recvfrom sock buf)))
(check (socket-sendto sock peer buf 0 ilen) => ilen)
(lp))))
(define (dgram-client srv len)
(define-values (sbuf rbuf) (values (make-junk len) (make-bytes len)))
(define sock (socket PF_INET SOCK_DGRAM))
(check (socket-sendto sock srv sbuf) => (bytes-length sbuf))
(let-values (((ilen peer) (socket-recvfrom sock rbuf)))
(check ilen => (bytes-length rbuf))
(check (inet-address=? peer srv) => #t)
(check peer => srv)
(check (equal? rbuf sbuf) => #t)))
(define (bcast-client bcast len)
(define-values (sbuf rbuf) (values (make-junk len) (make-bytes len)))
(define sock (socket PF_INET SOCK_DGRAM))
(socket-setsockopt sock SOL_SOCKET SO_BROADCAST #t)
(check (socket-sendto sock bcast sbuf) => (bytes-length sbuf))
(let-values (((ilen peer) (socket-recvfrom sock rbuf)))
(check ilen => (bytes-length rbuf))
(check (equal? rbuf sbuf) => #t)))
(define (msg-server sock)
(define data (make-bytes 1500))
(define name (make-bytes 32))
(let lp ()
(let-values (((ilen nlen clen flags) (socket-recvmsg sock name data #f)))
(check (socket-sendto sock (unpack-address name) data 0 ilen) => ilen)
(lp))))
(define (msg-client srv len)
(define-values (sbuf rbuf pbuf)
(values (make-junk len) (make-bytes len) (make-bytes 32)))
(define sock (socket AF_INET SOCK_DGRAM))
(check (socket-sendmsg sock (pack-address srv) sbuf #f)
=> (bytes-length sbuf))
(let-values (((ilen nlen clen flags) (socket-recvmsg sock pbuf rbuf #f)))
(check ilen => (bytes-length rbuf))
(check (equal? rbuf sbuf) => #t)
(check (inet-address=? (unpack-address pbuf) srv) => #t)
(check (unpack-address pbuf) => srv)))
(define (test-tcp)
(let* ((srvsock (tcp-server-socket 5000 5100))
(srvthr (thread (lambda () (stream-server srvsock))))
(srv (socket-getsockname srvsock)))
(stream-client srv PF_INET 128)
(stream-client srv PF_INET 16384)
(kill-thread srvthr)))
(define (test-udp)
(let* ((srvsock (udp-server-socket 5000 5100))
(srvthr (thread (lambda () (dgram-server srvsock))))
(srv (inet4-address
INADDR_LOOPBACK
(inet-address-port (socket-getsockname srvsock)))))
(wait-idle)
(dgram-client srv 1024)
(kill-thread srvthr)))
(define (test-bcast)
(let* ((srvsock (udp-server-socket 5000 5100))
(bcast (inet4-address
INADDR_BROADCAST
(inet-address-port (socket-getsockname srvsock)))))
(socket-setsockopt srvsock SOL_SOCKET SO_BROADCAST #t)
(let ((srvthr (thread (lambda () (dgram-server srvsock)))))
(wait-idle)
(bcast-client bcast 1024)
(kill-thread srvthr))))
(define (test-msg)
(let* ((srvsock (udp-server-socket 5000 5100))
(srvthr (thread (lambda () (msg-server srvsock))))
(srv (inet4-address
INADDR_LOOPBACK
(inet-address-port (socket-getsockname srvsock)))))
(wait-idle)
(msg-client srv 1024)
(kill-thread srvthr)))
(define (test-unix)
(let* ((srvsock (unix-server-socket 0 100))
(srvthr (thread (lambda () (stream-server srvsock))))
(srv (socket-getsockname srvsock)))
(stream-client srv PF_UNIX 4096)
(kill-thread srvthr)
(delete-file srv)))
(define (run-suite tests)
(for-each (lambda (test)
(printf "~n; test: ~a~n" (object-name test))
(test))
tests))
(define unix-suite
(list test-tcp test-udp test-bcast test-msg test-unix))
(define windows-suite
(list test-tcp test-udp test-bcast))
(define (run-tests)
(case (system-type)
((windows) (run-suite windows-suite))
(else (run-suite unix-suite)))
(check-report))