123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573 |
- ;;;; 00-socket.test --- test socket functions -*- scheme -*-
- ;;;;
- ;;;; Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- ;;;; 2011, 2012, 2013, 2014, 2017, 2021 Free Software Foundation, Inc.
- ;;;;
- ;;;; This library is free software; you can redistribute it and/or
- ;;;; modify it under the terms of the GNU Lesser General Public
- ;;;; License as published by the Free Software Foundation; either
- ;;;; version 3 of the License, or (at your option) any later version.
- ;;;;
- ;;;; This library is distributed in the hope that it will be useful,
- ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
- ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- ;;;; Lesser General Public License for more details.
- ;;;;
- ;;;; You should have received a copy of the GNU Lesser General Public
- ;;;; License along with this library; if not, write to the Free Software
- ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- ;; This test runs early, so that we can fork before any threads are
- ;; created in other tests.
- (define-module (test-suite test-socket)
- #:use-module (rnrs bytevectors)
- #:use-module (srfi srfi-26)
- #:use-module (test-suite lib))
- ;;;
- ;;; inet-ntop
- ;;;
- (if (defined? 'inet-ntop)
- (with-test-prefix "inet-ntop"
- (with-test-prefix "ipv6"
- (pass-if "0"
- (string? (inet-ntop AF_INET6 0)))
- (pass-if "2^128-1"
- (string? (inet-ntop AF_INET6 (1- (ash 1 128)))))
- (pass-if-exception "-1" exception:out-of-range
- (inet-ntop AF_INET6 -1))
- (pass-if-exception "2^128" exception:out-of-range
- (inet-ntop AF_INET6 (ash 1 128)))
- (pass-if-exception "2^1024" exception:out-of-range
- (inet-ntop AF_INET6 (ash 1 1024))))))
- ;;;
- ;;; inet-pton
- ;;;
- (if (defined? 'inet-pton)
- (with-test-prefix "inet-pton"
- (with-test-prefix "ipv6"
- (pass-if "00:00:00:00:00:00:00:00"
- (eqv? 0 (inet-pton AF_INET6 "00:00:00:00:00:00:00:00")))
- (pass-if "0:0:0:0:0:0:0:1"
- (eqv? 1 (inet-pton AF_INET6 "0:0:0:0:0:0:0:1")))
- (pass-if "::1"
- (eqv? 1 (inet-pton AF_INET6 "::1")))
- (pass-if "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF"
- (eqv? #xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
- (inet-pton AF_INET6
- "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF")))
- (pass-if "F000:0000:0000:0000:0000:0000:0000:0000"
- (eqv? #xF0000000000000000000000000000000
- (inet-pton AF_INET6
- "F000:0000:0000:0000:0000:0000:0000:0000")))
- (pass-if "0F00:0000:0000:0000:0000:0000:0000:0000"
- (eqv? #x0F000000000000000000000000000000
- (inet-pton AF_INET6
- "0F00:0000:0000:0000:0000:0000:0000:0000")))
- (pass-if "0000:0000:0000:0000:0000:0000:0000:00F0"
- (eqv? #xF0
- (inet-pton AF_INET6
- "0000:0000:0000:0000:0000:0000:0000:00F0"))))))
- (if (defined? 'inet-ntop)
- (with-test-prefix "inet-ntop"
- (with-test-prefix "ipv4"
- (pass-if "127.0.0.1"
- (equal? "127.0.0.1" (inet-ntop AF_INET INADDR_LOOPBACK))))
- (if (defined? 'AF_INET6)
- (with-test-prefix "ipv6"
- (pass-if "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF"
- (string-ci=? "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF"
- (inet-ntop AF_INET6 (- (expt 2 128) 1))))
- (pass-if "::1"
- (equal? "::1" (inet-ntop AF_INET6 1)))))))
- ;;;
- ;;; make-socket-address
- ;;;
- (with-test-prefix "make-socket-address"
- (if (defined? 'AF_INET)
- (pass-if "AF_INET"
- (let ((sa (make-socket-address AF_INET 123456 80)))
- (and (= (sockaddr:fam sa) AF_INET)
- (= (sockaddr:addr sa) 123456)
- (= (sockaddr:port sa) 80)))))
- (if (defined? 'AF_INET6)
- (pass-if "AF_INET6"
- ;; Since the platform doesn't necessarily support `scopeid', we won't
- ;; test it.
- (let ((sa* (make-socket-address AF_INET6 123456 80 1))
- (sa+ (make-socket-address AF_INET6 123456 80)))
- (and (= (sockaddr:fam sa*) (sockaddr:fam sa+) AF_INET6)
- (= (sockaddr:addr sa*) (sockaddr:addr sa+) 123456)
- (= (sockaddr:port sa*) (sockaddr:port sa+) 80)
- (= (sockaddr:flowinfo sa*) 1)))))
- (if (defined? 'AF_UNIX)
- (begin
- (pass-if "AF_UNIX"
- (let ((sa (make-socket-address AF_UNIX "/tmp/unix-socket")))
- (and (= (sockaddr:fam sa) AF_UNIX)
- (string=? (sockaddr:path sa) "/tmp/unix-socket"))))
- (pass-if "AF_UNIX abstract"
- (let ((sa (make-socket-address AF_UNIX "\x00/tmp/abstract-socket")))
- (and (= (sockaddr:fam sa) AF_UNIX)
- (string=? (sockaddr:path sa) "\x00/tmp/abstract-socket")))))))
- ;;;
- ;;; setsockopt
- ;;;
- (with-test-prefix "setsockopt AF_INET"
- (if (and (defined? 'AF_INET) (defined? 'TCP_NODELAY))
- (pass-if "IPPROTO_TCP TCP_NODELAY"
- (let ((sock (socket AF_INET SOCK_STREAM 0)))
- (setsockopt sock IPPROTO_TCP TCP_NODELAY 1)
- (eqv? 1 (getsockopt sock IPPROTO_TCP TCP_NODELAY))))))
- ;;;
- ;;; AF_UNIX sockets and `make-socket-address'
- ;;;
- (define %tmpdir
- ;; Honor `$TMPDIR', which tmpnam(3) doesn't do.
- (or (getenv "TMPDIR") "/tmp"))
- (define %curdir
- ;; Remember the current working directory.
- (getcwd))
- ;; Temporarily cd to %TMPDIR. The goal is to work around path name
- ;; limitations, which can lead to exceptions like:
- ;;
- ;; (misc-error "scm_to_sockaddr"
- ;; "unix address path too long: ~A"
- ;; ("/tmp/nix-build-fb7bph4ifh0vr3ihigm702dzffdnapfj-guile-coverage-1.9.5.drv-0/guile-test-socket-1258553296-77619")
- ;; #f)
- (false-if-exception (chdir %tmpdir))
- (define (temp-file-path)
- ;; Return a temporary file name, assuming the current directory is %TMPDIR.
- (string-append "guile-test-socket-"
- (number->string (current-time)) "-"
- (number->string (random 100000))))
- (define (primitive-fork-if-available)
- (if (not (provided? 'fork))
- -1
- (primitive-fork)))
- (if (defined? 'AF_UNIX)
- (with-test-prefix "AF_UNIX/SOCK_DGRAM"
- ;; testing `bind' and `sendto' and datagram sockets
- (let ((server-socket (socket AF_UNIX SOCK_DGRAM 0))
- (server-bound? #f)
- (path (temp-file-path)))
- (pass-if "bind"
- (catch 'system-error
- (lambda ()
- (bind server-socket AF_UNIX path)
- (set! server-bound? #t)
- #t)
- (lambda args
- (let ((errno (system-error-errno args)))
- (cond ((= errno EADDRINUSE) (throw 'unresolved))
- (else (apply throw args)))))))
- (pass-if "bind/sockaddr"
- (let* ((sock (socket AF_UNIX SOCK_STREAM 0))
- (path (temp-file-path))
- (sockaddr (make-socket-address AF_UNIX path)))
- (catch 'system-error
- (lambda ()
- (bind sock sockaddr)
- (false-if-exception (delete-file path))
- #t)
- (lambda args
- (let ((errno (system-error-errno args)))
- (cond ((= errno EADDRINUSE) (throw 'unresolved))
- (else (apply throw args))))))))
- (pass-if "sendto"
- (if (not server-bound?)
- (throw 'unresolved)
- (let ((client (socket AF_UNIX SOCK_DGRAM 0))
- (message (string->utf8 "hello")))
- (> (sendto client message AF_UNIX path) 0))))
- (pass-if "sendto/sockaddr"
- (if (not server-bound?)
- (throw 'unresolved)
- (let ((client (socket AF_UNIX SOCK_DGRAM 0))
- (message (string->utf8 "hello"))
- (sockaddr (make-socket-address AF_UNIX path)))
- (> (sendto client message sockaddr) 0))))
- (false-if-exception (delete-file path)))))
- (if (defined? 'AF_UNIX)
- (with-test-prefix "AF_UNIX/SOCK_STREAM"
- ;; testing `bind', `listen' and `connect' on stream-oriented sockets
- (let ((server-socket (socket AF_UNIX SOCK_STREAM 0))
- (server-bound? #f)
- (server-listening? #f)
- (server-pid #f)
- (path (temp-file-path)))
- (pass-if "bind"
- (catch 'system-error
- (lambda ()
- (bind server-socket AF_UNIX path)
- (set! server-bound? #t)
- #t)
- (lambda args
- (let ((errno (system-error-errno args)))
- (cond ((= errno EADDRINUSE) (throw 'unresolved))
- (else (apply throw args)))))))
- (pass-if "bind/sockaddr"
- (let* ((sock (socket AF_UNIX SOCK_STREAM 0))
- (path (temp-file-path))
- (sockaddr (make-socket-address AF_UNIX path)))
- (catch 'system-error
- (lambda ()
- (bind sock sockaddr)
- (false-if-exception (delete-file path))
- #t)
- (lambda args
- (let ((errno (system-error-errno args)))
- (cond ((= errno EADDRINUSE) (throw 'unresolved))
- (else (apply throw args))))))))
- (pass-if "listen"
- (if (not server-bound?)
- (throw 'unresolved)
- (begin
- (listen server-socket 123)
- (set! server-listening? #t)
- #t)))
- (force-output (current-output-port))
- (force-output (current-error-port))
- (when server-listening?
- (let ((pid (primitive-fork-if-available)))
- ;; Spawn a server process.
- (case pid
- ((-1) ;; fork not available
- #f)
- ((0) ;; the kid: serve two connections and exit
- (let serve ((conn
- (false-if-exception (accept server-socket)))
- (count 1))
- (if (not conn)
- (exit 1)
- (if (> count 0)
- (serve (false-if-exception (accept server-socket))
- (- count 1)))))
- (exit 0))
- (else ;; the parent
- (set! server-pid pid)
- #t))))
- (pass-if "connect"
- (if (not server-pid)
- (throw 'unresolved)
- (let ((s (socket AF_UNIX SOCK_STREAM 0)))
- (connect s AF_UNIX path)
- #t)))
- (pass-if "connect/sockaddr"
- (if (not server-pid)
- (throw 'unresolved)
- (let ((s (socket AF_UNIX SOCK_STREAM 0)))
- (connect s (make-socket-address AF_UNIX path))
- #t)))
- (pass-if "accept"
- (if (not server-pid)
- (throw 'unresolved)
- (let ((status (cdr (waitpid server-pid))))
- (eqv? 0 (status:exit-val status)))))
- (false-if-exception (delete-file path))
- #t)
- ;; testing `bind', `listen' and `connect' on abstract stream-oriented sockets
- (let ((server-socket (socket AF_UNIX SOCK_STREAM 0))
- (server-bound? #f)
- (server-listening? #f)
- (server-pid #f)
- (path (temp-file-path)))
- (false-if-exception (delete-file path))
- (set! path (string-append "\x00" path))
- (pass-if "bind abstract"
- (catch 'system-error
- (lambda ()
- (bind server-socket AF_UNIX path)
- (set! server-bound? #t)
- #t)
- (lambda args
- (let ((errno (system-error-errno args)))
- (if (= errno EADDRINUSE)
- (throw 'unresolved)
- (apply throw args))))))
- (pass-if "listen abstract"
- (if (not server-bound?)
- (throw 'unresolved)
- (begin
- (listen server-socket 123)
- (set! server-listening? #t)
- #t)))
- (force-output (current-output-port))
- (force-output (current-error-port))
- (when server-listening?
- (let ((pid (primitive-fork-if-available)))
- ;; Spawn a server process.
- (case pid
- ((-1) ;; fork not available
- #f)
- ((0) ;; the kid: serve one connection and exit
- (let serve ((conn
- (false-if-exception (accept server-socket)))
- (count 0))
- (if (not conn)
- (exit 1)
- (exit 0))))
- (else ;; the parent
- (set! server-pid pid)
- #t))))
- (pass-if "connect abstract"
- (if (not server-pid)
- (throw 'unresolved)
- (let ((s (socket AF_UNIX SOCK_STREAM 0)))
- (display "connect abstract\n")
- (connect s AF_UNIX path)
- #t)))
- (pass-if "accept abstract"
- (if (not server-pid)
- (throw 'unresolved)
- (begin
- (let ((status (cdr (waitpid server-pid))))
- (eqv? 0 (status:exit-val status))))))
- #t)
- ;; Testing `send', `recv!' & co. on stream-oriented sockets (with
- ;; a bit of duplication with the above.)
- (let ((server-socket (socket AF_UNIX SOCK_STREAM 0))
- (server-bound? #f)
- (server-listening? #f)
- (server-pid #f)
- (message "hello, world!")
- (path (temp-file-path)))
- (define (sub-bytevector bv len)
- (let ((c (make-bytevector len)))
- (bytevector-copy! bv 0 c 0 len)
- c))
- (pass-if "bind (bis)"
- (catch 'system-error
- (lambda ()
- (bind server-socket AF_UNIX path)
- (set! server-bound? #t)
- #t)
- (lambda args
- (let ((errno (system-error-errno args)))
- (cond ((= errno EADDRINUSE) (throw 'unresolved))
- (else (apply throw args)))))))
- (pass-if "listen (bis)"
- (if (not server-bound?)
- (throw 'unresolved)
- (begin
- (listen server-socket 123)
- (set! server-listening? #t)
- #t)))
- (force-output (current-output-port))
- (force-output (current-error-port))
- (if server-listening?
- (let ((pid (primitive-fork-if-available)))
- ;; Spawn a server process.
- (case pid
- ((-1)
- #f)
- ((0) ;; the kid: send MESSAGE and exit
- (exit
- (false-if-exception
- (let ((conn (car (accept server-socket)))
- (bv (string->utf8 message)))
- (= (bytevector-length bv)
- (send conn bv))))))
- (else ;; the parent
- (set! server-pid pid)
- #t))))
- (pass-if "recv!"
- (if (not server-pid)
- (throw 'unresolved)
- (let ((s (socket AF_UNIX SOCK_STREAM 0)))
- (connect s AF_UNIX path)
- (let* ((buf (make-bytevector 123))
- (received (recv! s buf)))
- (string=? (utf8->string (sub-bytevector buf received))
- message)))))
- (pass-if "accept (bis)"
- (if (not server-pid)
- (throw 'unresolved)
- (let ((status (cdr (waitpid server-pid))))
- (eqv? 0 (status:exit-val status)))))
- (false-if-exception (delete-file path))
- #t)))
- (if (defined? 'AF_INET6)
- (with-test-prefix "AF_INET6/SOCK_STREAM"
- ;; testing `bind', `listen' and `connect' on stream-oriented sockets
- (let ((server-socket
- ;; Some platforms don't support this protocol/family combination.
- (false-if-exception (socket AF_INET6 SOCK_STREAM 0)))
- (server-bound? #f)
- (server-listening? #f)
- (server-pid #f)
- (ipv6-addr 1) ; ::1
- (server-port 8889)
- (client-port 9998))
- (pass-if "bind"
- (if (not server-socket)
- (throw 'unresolved))
- (catch 'system-error
- (lambda ()
- (bind server-socket AF_INET6 ipv6-addr server-port)
- (set! server-bound? #t)
- #t)
- (lambda args
- (let ((errno (system-error-errno args)))
- (cond ((= errno EADDRINUSE) (throw 'unresolved))
- ;; On Linux-based systems, when `ipv6' support is
- ;; missing (for instance, `ipv6' is loaded and
- ;; /proc/sys/net/ipv6/conf/all/disable_ipv6 is set
- ;; to 1), the socket call above succeeds but
- ;; bind(2) fails like this.
- ((= errno EADDRNOTAVAIL) (throw 'unresolved))
- (else (apply throw args)))))))
- (pass-if "bind/sockaddr"
- (let* ((sock (false-if-exception (socket AF_INET6 SOCK_STREAM 0)))
- (sockaddr (make-socket-address AF_INET6 ipv6-addr client-port)))
- (if (not sock)
- (throw 'unresolved))
- (catch 'system-error
- (lambda ()
- (bind sock sockaddr)
- #t)
- (lambda args
- (let ((errno (system-error-errno args)))
- (cond ((= errno EADDRINUSE) (throw 'unresolved))
- ((= errno EADDRNOTAVAIL) (throw 'unresolved))
- (else (apply throw args))))))))
- (pass-if "listen"
- (if (not server-bound?)
- (throw 'unresolved)
- (begin
- (listen server-socket 123)
- (set! server-listening? #t)
- #t)))
- (force-output (current-output-port))
- (force-output (current-error-port))
- (if server-listening?
- (let ((pid (primitive-fork-if-available)))
- ;; Spawn a server process.
- (case pid
- ((-1)
- #f)
- ((0) ;; the kid: serve two connections and exit
- (let serve ((conn
- (false-if-exception (accept server-socket)))
- (count 1))
- (if (not conn)
- (exit 1)
- (if (> count 0)
- (serve (false-if-exception (accept server-socket))
- (- count 1)))))
- (exit 0))
- (else ;; the parent
- (set! server-pid pid)
- #t))))
- (pass-if "connect"
- (if (not server-pid)
- (throw 'unresolved)
- (let ((s (socket AF_INET6 SOCK_STREAM 0)))
- (connect s AF_INET6 ipv6-addr server-port)
- #t)))
- (pass-if "connect/sockaddr"
- (if (not server-pid)
- (throw 'unresolved)
- (let ((s (socket AF_INET6 SOCK_STREAM 0)))
- (connect s (make-socket-address AF_INET6 ipv6-addr server-port))
- #t)))
- (pass-if "accept"
- (if (not server-pid)
- (throw 'unresolved)
- (let ((status (cdr (waitpid server-pid))))
- (eqv? 0 (status:exit-val status)))))
- #t)))
- ;; Switch back to the previous directory.
- (false-if-exception (chdir %curdir))
|