1 ;;;; 00-socket.test --- test socket functions -*- scheme -*-
3 ;;;; Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010,
4 ;;;; 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
6 ;;;; This library is free software; you can redistribute it and/or
7 ;;;; modify it under the terms of the GNU Lesser General Public
8 ;;;; License as published by the Free Software Foundation; either
9 ;;;; version 3 of the License, or (at your option) any later version.
11 ;;;; This library is distributed in the hope that it will be useful,
12 ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 ;;;; Lesser General Public License for more details.
16 ;;;; You should have received a copy of the GNU Lesser General Public
17 ;;;; License along with this library; if not, write to the Free Software
18 ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 ;; This test runs early, so that we can fork before any threads are
21 ;; created in other tests.
23 (define-module (test-suite test-socket)
24 #:use-module (rnrs bytevectors)
25 #:use-module (srfi srfi-26)
26 #:use-module (test-suite lib))
34 (if (defined? 'inet-ntop)
35 (with-test-prefix "inet-ntop"
37 (with-test-prefix "ipv6"
39 (string? (inet-ntop AF_INET6 0)))
42 (string? (inet-ntop AF_INET6 (1- (ash 1 128)))))
44 (pass-if-exception "-1" exception:out-of-range
45 (inet-ntop AF_INET6 -1))
47 (pass-if-exception "2^128" exception:out-of-range
48 (inet-ntop AF_INET6 (ash 1 128)))
50 (pass-if-exception "2^1024" exception:out-of-range
51 (inet-ntop AF_INET6 (ash 1 1024))))))
57 (if (defined? 'inet-pton)
58 (with-test-prefix "inet-pton"
60 (with-test-prefix "ipv6"
61 (pass-if "00:00:00:00:00:00:00:00"
62 (eqv? 0 (inet-pton AF_INET6 "00:00:00:00:00:00:00:00")))
64 (pass-if "0:0:0:0:0:0:0:1"
65 (eqv? 1 (inet-pton AF_INET6 "0:0:0:0:0:0:0:1")))
68 (eqv? 1 (inet-pton AF_INET6 "::1")))
70 (pass-if "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF"
71 (eqv? #xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
73 "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF")))
75 (pass-if "F000:0000:0000:0000:0000:0000:0000:0000"
76 (eqv? #xF0000000000000000000000000000000
78 "F000:0000:0000:0000:0000:0000:0000:0000")))
80 (pass-if "0F00:0000:0000:0000:0000:0000:0000:0000"
81 (eqv? #x0F000000000000000000000000000000
83 "0F00:0000:0000:0000:0000:0000:0000:0000")))
85 (pass-if "0000:0000:0000:0000:0000:0000:0000:00F0"
88 "0000:0000:0000:0000:0000:0000:0000:00F0"))))))
90 (if (defined? 'inet-ntop)
91 (with-test-prefix "inet-ntop"
93 (with-test-prefix "ipv4"
95 (equal? "127.0.0.1" (inet-ntop AF_INET INADDR_LOOPBACK))))
97 (if (defined? 'AF_INET6)
98 (with-test-prefix "ipv6"
99 (pass-if "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF"
100 (string-ci=? "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF"
101 (inet-ntop AF_INET6 (- (expt 2 128) 1))))
104 (equal? "::1" (inet-ntop AF_INET6 1)))))))
108 ;;; make-socket-address
111 (with-test-prefix "make-socket-address"
112 (if (defined? 'AF_INET)
114 (let ((sa (make-socket-address AF_INET 123456 80)))
115 (and (= (sockaddr:fam sa) AF_INET)
116 (= (sockaddr:addr sa) 123456)
117 (= (sockaddr:port sa) 80)))))
119 (if (defined? 'AF_INET6)
121 ;; Since the platform doesn't necessarily support `scopeid', we won't
123 (let ((sa* (make-socket-address AF_INET6 123456 80 1))
124 (sa+ (make-socket-address AF_INET6 123456 80)))
125 (and (= (sockaddr:fam sa*) (sockaddr:fam sa+) AF_INET6)
126 (= (sockaddr:addr sa*) (sockaddr:addr sa+) 123456)
127 (= (sockaddr:port sa*) (sockaddr:port sa+) 80)
128 (= (sockaddr:flowinfo sa*) 1)))))
130 (if (defined? 'AF_UNIX)
132 (let ((sa (make-socket-address AF_UNIX "/tmp/unix-socket")))
133 (and (= (sockaddr:fam sa) AF_UNIX)
134 (string=? (sockaddr:path sa) "/tmp/unix-socket"))))))
138 ;;; AF_UNIX sockets and `make-socket-address'
142 ;; Honor `$TMPDIR', which tmpnam(3) doesn't do.
143 (or (getenv "TMPDIR") "/tmp"))
146 ;; Remember the current working directory.
149 ;; Temporarily cd to %TMPDIR. The goal is to work around path name
150 ;; limitations, which can lead to exceptions like:
152 ;; (misc-error "scm_to_sockaddr"
153 ;; "unix address path too long: ~A"
154 ;; ("/tmp/nix-build-fb7bph4ifh0vr3ihigm702dzffdnapfj-guile-coverage-1.9.5.drv-0/guile-test-socket-1258553296-77619")
158 (define (temp-file-path)
159 ;; Return a temporary file name, assuming the current directory is %TMPDIR.
160 (string-append "guile-test-socket-"
161 (number->string (current-time)) "-"
162 (number->string (random 100000))))
165 (if (defined? 'AF_UNIX)
166 (with-test-prefix "AF_UNIX/SOCK_DGRAM"
168 ;; testing `bind' and `sendto' and datagram sockets
170 (let ((server-socket (socket AF_UNIX SOCK_DGRAM 0))
172 (path (temp-file-path)))
177 (bind server-socket AF_UNIX path)
178 (set! server-bound? #t)
181 (let ((errno (system-error-errno args)))
182 (cond ((= errno EADDRINUSE) (throw 'unresolved))
183 (else (apply throw args)))))))
185 (pass-if "bind/sockaddr"
186 (let* ((sock (socket AF_UNIX SOCK_STREAM 0))
187 (path (temp-file-path))
188 (sockaddr (make-socket-address AF_UNIX path)))
192 (false-if-exception (delete-file path))
195 (let ((errno (system-error-errno args)))
196 (cond ((= errno EADDRINUSE) (throw 'unresolved))
197 (else (apply throw args))))))))
200 (if (not server-bound?)
202 (let ((client (socket AF_UNIX SOCK_DGRAM 0))
203 (message (string->utf8 "hello")))
204 (> (sendto client message AF_UNIX path) 0))))
206 (pass-if "sendto/sockaddr"
207 (if (not server-bound?)
209 (let ((client (socket AF_UNIX SOCK_DGRAM 0))
210 (message (string->utf8 "hello"))
211 (sockaddr (make-socket-address AF_UNIX path)))
212 (> (sendto client message sockaddr) 0))))
214 (false-if-exception (delete-file path)))))
217 (if (defined? 'AF_UNIX)
218 (with-test-prefix "AF_UNIX/SOCK_STREAM"
220 ;; testing `bind', `listen' and `connect' on stream-oriented sockets
222 (let ((server-socket (socket AF_UNIX SOCK_STREAM 0))
224 (server-listening? #f)
226 (path (temp-file-path)))
231 (bind server-socket AF_UNIX path)
232 (set! server-bound? #t)
235 (let ((errno (system-error-errno args)))
236 (cond ((= errno EADDRINUSE) (throw 'unresolved))
237 (else (apply throw args)))))))
239 (pass-if "bind/sockaddr"
240 (let* ((sock (socket AF_UNIX SOCK_STREAM 0))
241 (path (temp-file-path))
242 (sockaddr (make-socket-address AF_UNIX path)))
246 (false-if-exception (delete-file path))
249 (let ((errno (system-error-errno args)))
250 (cond ((= errno EADDRINUSE) (throw 'unresolved))
251 (else (apply throw args))))))))
254 (if (not server-bound?)
257 (listen server-socket 123)
258 (set! server-listening? #t)
261 (force-output (current-output-port))
262 (force-output (current-error-port))
263 (if server-listening?
264 (let ((pid (primitive-fork)))
265 ;; Spawn a server process.
267 ((-1) (throw 'unresolved))
268 ((0) ;; the kid: serve two connections and exit
270 (false-if-exception (accept server-socket)))
275 (serve (false-if-exception (accept server-socket))
279 (set! server-pid pid)
285 (let ((s (socket AF_UNIX SOCK_STREAM 0)))
286 (connect s AF_UNIX path)
289 (pass-if "connect/sockaddr"
292 (let ((s (socket AF_UNIX SOCK_STREAM 0)))
293 (connect s (make-socket-address AF_UNIX path))
299 (let ((status (cdr (waitpid server-pid))))
300 (eqv? 0 (status:exit-val status)))))
302 (false-if-exception (delete-file path))
307 ;; Testing `send', `recv!' & co. on stream-oriented sockets (with
308 ;; a bit of duplication with the above.)
310 (let ((server-socket (socket AF_UNIX SOCK_STREAM 0))
312 (server-listening? #f)
314 (message "hello, world!")
315 (path (temp-file-path)))
317 (define (sub-bytevector bv len)
318 (let ((c (make-bytevector len)))
319 (bytevector-copy! bv 0 c 0 len)
322 (pass-if "bind (bis)"
325 (bind server-socket AF_UNIX path)
326 (set! server-bound? #t)
329 (let ((errno (system-error-errno args)))
330 (cond ((= errno EADDRINUSE) (throw 'unresolved))
331 (else (apply throw args)))))))
333 (pass-if "listen (bis)"
334 (if (not server-bound?)
337 (listen server-socket 123)
338 (set! server-listening? #t)
341 (force-output (current-output-port))
342 (force-output (current-error-port))
343 (if server-listening?
344 (let ((pid (primitive-fork)))
345 ;; Spawn a server process.
347 ((-1) (throw 'unresolved))
348 ((0) ;; the kid: send MESSAGE and exit
351 (let ((conn (car (accept server-socket)))
352 (bv (string->utf8 message)))
353 (= (bytevector-length bv)
356 (set! server-pid pid)
362 (let ((s (socket AF_UNIX SOCK_STREAM 0)))
363 (connect s AF_UNIX path)
364 (let* ((buf (make-bytevector 123))
365 (received (recv! s buf)))
366 (string=? (utf8->string (sub-bytevector buf received))
369 (pass-if "accept (bis)"
372 (let ((status (cdr (waitpid server-pid))))
373 (eqv? 0 (status:exit-val status)))))
375 (false-if-exception (delete-file path))
380 (if (defined? 'AF_INET6)
381 (with-test-prefix "AF_INET6/SOCK_STREAM"
383 ;; testing `bind', `listen' and `connect' on stream-oriented sockets
386 ;; Some platforms don't support this protocol/family combination.
387 (false-if-exception (socket AF_INET6 SOCK_STREAM 0)))
389 (server-listening? #f)
396 (if (not server-socket)
400 (bind server-socket AF_INET6 ipv6-addr server-port)
401 (set! server-bound? #t)
404 (let ((errno (system-error-errno args)))
405 (cond ((= errno EADDRINUSE) (throw 'unresolved))
407 ;; On Linux-based systems, when `ipv6' support is
408 ;; missing (for instance, `ipv6' is loaded and
409 ;; /proc/sys/net/ipv6/conf/all/disable_ipv6 is set
410 ;; to 1), the socket call above succeeds but
411 ;; bind(2) fails like this.
412 ((= errno EADDRNOTAVAIL) (throw 'unresolved))
414 (else (apply throw args)))))))
416 (pass-if "bind/sockaddr"
417 (let* ((sock (false-if-exception (socket AF_INET6 SOCK_STREAM 0)))
418 (sockaddr (make-socket-address AF_INET6 ipv6-addr client-port)))
426 (let ((errno (system-error-errno args)))
427 (cond ((= errno EADDRINUSE) (throw 'unresolved))
428 ((= errno EADDRNOTAVAIL) (throw 'unresolved))
429 (else (apply throw args))))))))
432 (if (not server-bound?)
435 (listen server-socket 123)
436 (set! server-listening? #t)
439 (force-output (current-output-port))
440 (force-output (current-error-port))
441 (if server-listening?
442 (let ((pid (primitive-fork)))
443 ;; Spawn a server process.
445 ((-1) (throw 'unresolved))
446 ((0) ;; the kid: serve two connections and exit
448 (false-if-exception (accept server-socket)))
453 (serve (false-if-exception (accept server-socket))
457 (set! server-pid pid)
463 (let ((s (socket AF_INET6 SOCK_STREAM 0)))
464 (connect s AF_INET6 ipv6-addr server-port)
467 (pass-if "connect/sockaddr"
470 (let ((s (socket AF_INET6 SOCK_STREAM 0)))
471 (connect s (make-socket-address AF_INET6 ipv6-addr server-port))
477 (let ((status (cdr (waitpid server-pid))))
478 (eqv? 0 (status:exit-val status)))))
482 ;; Switch back to the previous directory.
483 (false-if-exception (chdir %curdir))